file_operation常用成员原型

本文详细解析了文件操作结构file_operations,其中包括了文件读写、定位、控制等关键操作的实现方式。通过对该结构的深入理解,可以更好地掌握Linux内核中文件系统的运作原理。

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    int (*open) (struct inode *, struct file *);
    int (*release) (struct inode *, struct file *);
};

#include "scp.h" #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdio.h> #include <sys/stat.h> #include <netinet/in.h> #include <sys/file.h> #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> // 主要头文件(包含 open() 的函数原型和标志常量) /**************************************************************************************************/ /* GLOBAL_VARIABLES */ /**************************************************************************************************/ scp_context *scp_contextp = NULL; /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ #if 1 //Archer const char ISP_FILE_PATH[] = "/etc/3g4g.gz"; const char TM_FILTER_APPS_FILE_PATH[] = "/tmp/tm-shn/list_pc_filter_apps.db.gz"; const char TM_SEC_RULES_FILE_PATH[] = "/tmp/tm-shn/list_security_rules.db.gz"; const char TM_SEC_WRS_CATS_FILE_PATH[] = "/tmp/tm-shn/list_security_wrs_cats.db.gz"; const char TM_APPBLOCKLIST_FILE_PATH[] = "/tmp/appblock/avira_applist.gz"; const char GUEST_NETWORK_PORTAL_LOGO_PATH_READ[] = "/www/tmp/portal_logo.png"; const char GUEST_NETWORK_PORTAL_BACK_PATH_READ[] = "/www/tmp/portal_back.jpg"; const char GUEST_NETWORK_PORTAL_LOGO_PATH_WRITE[] = "/tmp/guest_portal/portal_logo.png"; const char GUEST_NETWORK_PORTAL_BACK_PATH_WRITE[] = "/tmp/guest_portal/portal_back.jpg"; const char TESTFILE1[] = "/tmp/testfile1"; const char TESTFILE2[] = "/tmp/testfile2"; #else //Aginet const char USBDISK_VOICEMAIL_RECORD_PATH[] = "/var/usbdisk/usbvm/voicemail/record/"; const char USBDISK_VOICEMAIL_NOTIFY_PATH[] = "/var/usbdisk/usbvm/voicemail/voiceNotify/"; const char LARGEDATA_VOICEMAIL_RECORD_PATH[] = "/large_data/usbvm/voicemail/record/"; const char REGION_JSON_GZ_FILE[] = "/web/js/region.json.gz"; const char REGION_JSON_GZ_MD5_FILE[] = "/web/js/region.json.gz.MD5"; const char ISPPROFILE_GZ_JSON_FILE[] = "/web/js/ispprofile.json.gz"; const char ISPPROFILE_GZ_JSON_MD5_FILE[] = "/web/js/ispprofile.json.gz.MD5"; const char ISPLOGO_PNG_GZ_FILE[] = "/web/img/isplogo.png.gz"; const char ISPLOGO_PNG_GZ_MD5_FILE[] = "/web/img/isplogo.png.gz.MD5"; const char AGC_DATABUFF_ISPLOGO_PNG_GZ_FILE[] = "/var/tmp/AginetConfig/databuff/isplogo.png.gz"; const char AGC_DATABUFF_ISPLOGO_PNG_GZ_MD5_FILE[] = "/var/tmp/AginetConfig/databuff/isplogo.png.gz.MD5"; //test const char TESTFILE1[] = "/tmp/testfile1"; const char TESTFILE2[] = "/tmp/testfile2"; #endif typedef struct { const char *file_path; int options; } SCP_FILE_PERMISSION; #define OPT_READ (0x01) #define OPT_WRITE (0x02) #define OPT_DATE (0x04) #define OPT_INCLUDE(x, opt) (opt == ((x) & opt)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #if 1 //Archer static SCP_FILE_PERMISSION file_permissions[] = { {ISP_FILE_PATH, OPT_READ | OPT_DATE}, {TM_FILTER_APPS_FILE_PATH, OPT_READ | OPT_DATE}, {TM_SEC_RULES_FILE_PATH, OPT_READ | OPT_DATE}, {TM_SEC_WRS_CATS_FILE_PATH, OPT_READ | OPT_DATE}, {TM_APPBLOCKLIST_FILE_PATH, OPT_READ | OPT_DATE}, {GUEST_NETWORK_PORTAL_LOGO_PATH_READ, OPT_READ | OPT_DATE}, {GUEST_NETWORK_PORTAL_BACK_PATH_READ, OPT_READ | OPT_DATE}, {GUEST_NETWORK_PORTAL_LOGO_PATH_WRITE, OPT_WRITE | OPT_DATE}, {GUEST_NETWORK_PORTAL_BACK_PATH_WRITE, OPT_WRITE | OPT_DATE}, {TESTFILE1, OPT_READ | OPT_WRITE | OPT_DATE}, {TESTFILE2, OPT_READ | OPT_WRITE | OPT_DATE}, }; #else //Aginet static SCP_FILE_PERMISSION file_permissions[] = { {USBDISK_VOICEMAIL_RECORD_PATH, OPT_READ | OPT_DATE}, {USBDISK_VOICEMAIL_NOTIFY_PATH, OPT_READ | OPT_DATE}, {LARGEDATA_VOICEMAIL_RECORD_PATH, OPT_READ | OPT_DATE}, {REGION_JSON_GZ_FILE, OPT_READ | OPT_DATE}, {REGION_JSON_GZ_MD5_FILE, OPT_READ | OPT_DATE}, {ISPPROFILE_GZ_JSON_FILE, OPT_READ | OPT_DATE}, {ISPPROFILE_GZ_JSON_MD5_FILE, OPT_READ | OPT_DATE}, {ISPLOGO_PNG_GZ_FILE, OPT_READ | OPT_DATE}, {ISPLOGO_PNG_GZ_MD5_FILE, OPT_READ | OPT_DATE}, {AGC_DATABUFF_ISPLOGO_PNG_GZ_FILE, OPT_READ | OPT_DATE}, {AGC_DATABUFF_ISPLOGO_PNG_GZ_MD5_FILE, OPT_READ | OPT_DATE}, {TESTFILE1, OPT_READ | OPT_WRITE | OPT_DATE}, {TESTFILE2, OPT_READ | OPT_WRITE | OPT_DATE}, }; #endif /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ static int check_file_permission(const char *fn, int type, int need_date) { int i = 0; if (fn == NULL) { return -1; } for (i = 0; i < ARRAY_SIZE(file_permissions); i++) { if (0 == strcmp(fn, file_permissions[i].file_path)) { if ((SESSION_TYPE_SOURCE == type) && (!OPT_INCLUDE(file_permissions[i].options, OPT_READ))) { return -1; } if ((SESSION_TYPE_TARGET == type) && (!OPT_INCLUDE(file_permissions[i].options, OPT_WRITE))) { return -1; } if (need_date && (!OPT_INCLUDE(file_permissions[i].options, OPT_DATE))) { return -1; } return 0; } } return -1; } static void set_file_time(int fd, int atime, int mtime) { if (fd < 0) return; struct timespec tv[2] = { {0, UTIME_NOW}, //0: access {0, UTIME_NOW} //1: modify }; if (atime >= 0) { tv[0].tv_sec = atime; tv[0].tv_nsec = 0; } if (mtime >= 0) { tv[1].tv_sec = mtime; tv[1].tv_nsec = 0; } futimens(fd, tv); } static void hex2bin(const char *hex, unsigned char *bin, int hex_len) { int i = 0; int val = 0; if (hex_len & 1) hex_len--; memset(bin, 0, hex_len >> 1); for (i = 0; i < hex_len; i++) { switch (hex[i]) { case '0'...'9': val = hex[i] - '0'; break; case 'a'...'z': val = hex[i] - 'a' + 10; break; case 'A'...'Z': val = hex[i] - 'A' + 10; break; } bin[i >> 1] = (bin[i >> 1] << 4) + val; } } static void bin2hex(const unsigned char *bin, char *hex, int bin_len) { int i = 0; int val = 0; for (i = 0; i < bin_len; i++) { val = (bin[i] >> 4) & 0x0f; hex[i << 1] = val + ((val >= 10) ? ('A' - 10) : '0'); val = (bin[i]) & 0x0f; hex[(i << 1) + 1] = val + ((val >= 10) ? ('A' - 10) : '0'); } } static int calc_checksum(int fd, unsigned char *output, int size) { if (fd < 0 || NULL == output || size <= 0) return -1; unsigned char buf[SCP_PACKET_MAX_SIZE]; int read_len = SCP_PACKET_MAX_SIZE; int len = 0; off_t offset = lseek(fd, 0, SEEK_CUR); lseek(fd, 0, SEEK_SET); SHA256_CTX ctx; SHA256_Init(&ctx); do { if (size < read_len) read_len = size; len = scp_fd_read_direct(fd, (char *)buf, read_len); if (len <= 0) return -1; SHA256_Update(&ctx, buf, len); size -= len; } while (size > 0); SHA256_Final(output, &ctx); lseek(fd, offset, SEEK_SET); return 0; } /**************************************************************************************************/ /* PUBLIC_FUNCTIONS */ /**************************************************************************************************/ int scp_fd_write_direct(int fd, const char* buf, size_t size) { int len; int ret = size; if (fd < 0) { return 0; } for (;;) { len = write(fd, buf, size); if (len < 0) { if (EINTR == errno) { continue; } ret = -1; break; } else if (len == 0) { ret = 0; break; } else if ((size_t)len >= size) { break; } else { buf += len; size -= len; } } return ret; } int scp_fd_read_direct(int fd, char* buf, size_t size) { if (fd < 0) { return 0; } int len; int ret = size; fd_set fds; struct timeval tv; int retval; for (;;) { FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = 1; tv.tv_usec = 0; retval = select(fd + 1, &fds, NULL, NULL, &tv); if (retval < 0) { if (EINTR == errno) { continue; } ret = -1; break; } else if (retval == 0) { ret = -1; break; } len = read(fd, buf, size); if (len < 0) { if (EINTR == errno) { continue; } ret = -1; break; } else if (len == 0) { ret = 0; break; } else if ((size_t)len >= size) { break; } else { buf += len; size -= len; } } return ret; } int scp_make_packet(unsigned char *buf, cJSON *control) { SCP_HEADER *scp_hdr = (SCP_HEADER *)buf; int ctrl_len = 0; char *control_str = NULL; control_str = cJSON_PrintUnformatted(control); SCPSDebug("scp_make_packet: %s", control_str); ctrl_len = strlen(control_str); scp_hdr->ctrl_len = htons(ctrl_len); memcpy(SCP_HEADER_GET_PAYLOAD(scp_hdr, 0), control_str, ctrl_len); free(control_str); SCPSDebug("make packet ctrl %d.", ctrl_len); for (; (ctrl_len & 0x03) != 0; ctrl_len++) *SCP_HEADER_GET_PAYLOAD(scp_hdr, ctrl_len) = '\0'; SCPSDebug("packet ctrl padding length %d.", ctrl_len); scp_hdr->data_len = 0; return ctrl_len + sizeof(SCP_HEADER); } #define CHECK_PARAM(param, obj_type) do { \ if (NULL == param) return SCP_ERROR_CODE_CONTROL_SECTION_NOT_FOUND; \ if (param->type != obj_type) { \ SCPSDebug("Get param %s %d, %d expected.", param->string, param->type, obj_type); \ return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; \ } \ } while(0) int scp_get_method(const unsigned char *buf, cJSON **control, int *id, int *type, int *val, cJSON **param_ret) { cJSON *root = NULL; cJSON *param = NULL; SCP_HEADER *scp_hdr = (SCP_HEADER *)buf; SCPSDebug("scp get json1: %s\n", SCP_HEADER_GET_PAYLOAD(scp_hdr, 0)); root = cJSON_Parse((const char *)SCP_HEADER_GET_PAYLOAD(scp_hdr, 0)); if (NULL == root) return SCP_ERROR_CODE_CONTROL_DECRYPT_FAILED; if (NULL != control) *control = root; //调用者自行删除root CHECK_PARAM(root, cJSON_Object); param = cJSON_GetObjectItem(root, "id"); CHECK_PARAM(param, cJSON_Number); if (0 >= param->valueint || SCP_MAX_ID < param->valueint) return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; *id = param->valueint; param = cJSON_GetObjectItem(root, "error_code"); if (param != NULL) { CHECK_PARAM(param, cJSON_Number); *val = param->valueint; *type = SCP_PACKET_TYPE_RESPONSE; if (NULL != param_ret) *param_ret = cJSON_GetObjectItem(root, "result"); return 0; } param = cJSON_GetObjectItem(root, "method"); if (param != NULL) { CHECK_PARAM(param, cJSON_String); if (0 == strncmp(param->valuestring, "read", SCP_METHOD_STR_LEN)) *val = SESSION_TYPE_SOURCE; else if (0 == strncmp(param->valuestring, "write", SCP_METHOD_STR_LEN)) *val = SESSION_TYPE_TARGET; else return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; *type = SCP_PACKET_TYPE_REQUEST; if (NULL != param_ret) *param_ret = cJSON_GetObjectItem(root, "params"); return 0; } param = cJSON_GetObjectItem(root, "data_offset"); if (param != NULL) { CHECK_PARAM(param, cJSON_Number); *val = param->valueint; *type = SCP_PACKET_TYPE_DATA; return 0; } return SCP_ERROR_CODE_CONTROL_SECTION_NOT_FOUND; } int send_file_data(scp_session *psession) { int ret = 0; int fd = -1; int file_size = 0; int state = 0; cJSON* control = NULL; cJSON* control_offset = NULL; //assert(psession != NULL); control = cJSON_CreateObject(); if (NULL == control) { ret = SCP_ERROR_CODE_SERVER_ERROR; goto send_data_session_end; } cJSON_AddNumberToObject(control, "id", psession->id); cJSON_AddNumberToObject(control, "data_offset", 0); control_offset = cJSON_GetObjectItem(control, "data_offset"); if (NULL == control) { ret = SCP_ERROR_CODE_SERVER_ERROR; goto send_data_session_end; } ctx_rdlock_session(SESSION_TYPE_SOURCE); fd = psession->fd; file_size = psession->file_size; ctx_unlock_session(SESSION_TYPE_SOURCE); //assert(fd >= 0); //assert(file_size >= 0); unsigned char buf[SCP_PACKET_MAX_SIZE]; SCP_HEADER *scp_hdr = (SCP_HEADER *)buf; unsigned char *buf_ctrl = SCP_HEADER_GET_PAYLOAD(scp_hdr, 0); int data_len = 0; int pkt_len = 0; int len = 0; int offset = 0; SCPSDebug("send_file_data start."); while (offset < file_size) { //设置数据报文控制信息 cJSON_SetIntValue(control_offset, offset); pkt_len = scp_make_packet(buf, control); //读取文件数据 data_len = (SCP_PACKET_MAX_SIZE - pkt_len); if (file_size - offset < data_len) data_len = file_size - offset; scp_hdr->data_len = htons(data_len); len = scp_fd_read_direct(fd, (char *)buf + pkt_len, data_len); if (len < data_len) { ret = SCP_ERROR_CODE_SERVER_ERROR; break; } SCPSDebug("fd = %d, make data pack %d %d.", fd, offset, data_len); //检查任务是否已被停止 ctx_lock_data_send(); while (scp_contextp->data_pack_num >= scp_contextp->data_speed_limit) { ctx_wait_data_send(); } scp_contextp->data_pack_num++; ctx_unlock_data_send(); //SCPSDebug("get condition."); ctx_rdlock_session(SESSION_TYPE_SOURCE); state = psession->state; ctx_unlock_session(SESSION_TYPE_SOURCE); if (SESSION_STATE_HALT == state) { SCPSDebug("get halt state."); break; } //SCPSDebug("send data."); if (ctx_send_request_func != NULL) { ctx_send_request_func(buf, pkt_len + data_len); } offset += data_len; } SCPSDebug("send data finish."); ctx_wrlock_session(SESSION_TYPE_SOURCE); clean_session(SESSION_TYPE_SOURCE, psession); ctx_unlock_session(SESSION_TYPE_SOURCE); send_data_session_end: if (NULL != control) { cJSON_Delete(control); } if (NULL != ctx_send_callback_func) { ctx_send_callback_func(); } return ret; } int recv_file_data(int id, const unsigned char *buf, int offset) { int ret = 0; int ses_index = -1; scp_session *psession = NULL; scp_target_session *pext = NULL; int data_len = 0; int len = 0; const unsigned char *buf_data; const SCP_HEADER *hdr = (SCP_HEADER *)buf; //assert(control != NULL) //assert(buf != NULL) SCPSDebug("recv_file_data start."); ctx_wrlock_session(SESSION_TYPE_TARGET); ses_index = match_session(SESSION_TYPE_TARGET, id); if (-1 == ses_index) goto error_recv_data; //匹配失败,不回复 psession = ctx_get_session(SESSION_TYPE_TARGET, ses_index); pext = ctx_get_target_extention(ses_index); if (offset != pext->offset) { ret = SCP_ERROR_CODE_FILE_CHECK_DATA_LOST; goto error_recv_data; } //SCPSDebug("offset check."); psession->expire = 0; data_len = ntohs(hdr->data_len); len = ntohs(hdr->ctrl_len); buf_data = SCP_HEADER_GET_PAYLOAD(hdr, SCP_PADDING_LENGTH(len)); if (data_len > 0) { //SCPSDebug("write data to file %d.", data_len); len = scp_fd_write_direct(psession->fd, (const char *)buf_data, data_len); if (len < data_len) { ret = SCP_ERROR_CODE_SERVER_ERROR; goto error_recv_data; } SHA256_Update(&(pext->ctx), buf_data, data_len); } pext->offset += data_len; if (pext->offset >= psession->file_size) { SCPSDebug("get all data."); ret = SCP_ERROR_CODE_FILE_CHECK_PASS; if (pext->offset > 0) { unsigned char dgest[SCP_SHA_CHECKSUM_LEN] = {0}; SHA256_Final(dgest, &(pext->ctx)); if (memcmp(pext->checksum, dgest, SCP_SHA_CHECKSUM_LEN)) { //SCPSDebug("wrong checksum."); ret = SCP_ERROR_CODE_FILE_CHECK_CHECKSUM_FAIL; } } set_file_time(psession->fd, pext->time[0], pext->time[1]); } error_recv_data: if (ret != 0 && ses_index != -1) { //接收数据完成或失败,关闭session //接收文件失败时是否需要删除文件? clean_session(SESSION_TYPE_TARGET, psession); } ctx_unlock_session(SESSION_TYPE_TARGET); return ret; } int stop_send_file_data(int id) { int ses_index = -1; scp_session *psession = NULL; SCPSDebug("stop_send_file_data start."); ctx_wrlock_session(SESSION_TYPE_SOURCE); do { ses_index = match_session(SESSION_TYPE_SOURCE, id); if (-1 == ses_index) { break; } SCPSDebug("stop session %d.", ses_index); psession = ctx_get_session(SESSION_TYPE_SOURCE, ses_index); psession->state = SESSION_STATE_HALT; } while (1); ctx_unlock_session(SESSION_TYPE_SOURCE); return SCP_ERROR_CODE_ACCEPT; } int send_file_request(int id, cJSON *control, int *new_session, cJSON **new_status) { int ret = 0; int ses_index = -1; scp_session *psession = NULL; int fd = -1; cJSON *param = NULL, *param_options = NULL; char *filename = NULL; int max_size = 0; int set_date = 0; struct stat stat_i; param = cJSON_GetObjectItem(control, "filename"); CHECK_PARAM(param, cJSON_String); filename = param->valuestring; if (strlen(filename) > SCP_MAX_FILEPATH_LEN) { return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; } param_options = cJSON_GetObjectItem(control, "option"); if (NULL != param_options) { CHECK_PARAM(param_options, cJSON_Object); param = cJSON_GetObjectItem(param_options, "max_size"); if (NULL != param) { CHECK_PARAM(param, cJSON_Number); max_size = param->valueint; } param = cJSON_GetObjectItem(param_options, "send_date"); if (NULL != param) { CHECK_PARAM(param, cJSON_Number); set_date = 1; } } if (0 != check_file_permission(filename, SESSION_TYPE_SOURCE, set_date)) { return SCP_ERROR_CODE_OPERATION_NO_PERMISSION; } if (0 != stat(filename, &stat_i)) { if (ENOENT == errno) return SCP_ERROR_CODE_OPERATION_FILE_NOT_FOUND; else return SCP_ERROR_CODE_SERVER_ERROR; } if (max_size > 0 && stat_i.st_size > max_size) { return SCP_ERROR_CODE_OPERATION_FILE_OVER_SIZE; } SCPSDebug("generate file status."); //生成文件基本信息 char mode[5]; sprintf(mode, "%04o", stat_i.st_mode & 0x0fff); cJSON* status = cJSON_CreateObject(); cJSON_AddNumberToObject(status, "size", stat_i.st_size); cJSON_AddStringToObject(status, "permissions", mode); if (set_date) { cJSON* date = cJSON_CreateObject(); cJSON_AddNumberToObject(date, "change_time", stat_i.st_mtime); cJSON_AddNumberToObject(date, "access_time", stat_i.st_atime); cJSON_AddItemToObject(status, "date", date); } SCPSDebug("send_file_request start."); if (stat_i.st_size <= 0) { SCPSDebug("filesize 0."); cJSON_AddStringToObject(status, "checksum", "0000000000000000000000000000000000000000000000000000000000000000"); ses_index = -1; goto skip_session; } ctx_wrlock_session(SESSION_TYPE_SOURCE); ret = scp_open_file_read(&fd, filename); if (ret < 0) { goto error_send_request; } ret = create_session(SESSION_TYPE_SOURCE, id, fd, &ses_index); if (ret) { goto error_send_request; } psession = ctx_get_session(SESSION_TYPE_SOURCE, ses_index); if (stat_i.st_size > 0) { unsigned char checksum[SCP_SHA_CHECKSUM_LEN]; char checksum_HEX[SCP_SHA_CHECKSUM_STR_LEN + 1]; SCPSDebug("calculate checksum."); if (calc_checksum(fd, checksum, stat_i.st_size) < 0) { ret = SCP_ERROR_CODE_SERVER_ERROR; goto error_send_request; } bin2hex(checksum, checksum_HEX, SCP_SHA_CHECKSUM_LEN); checksum_HEX[SCP_SHA_CHECKSUM_STR_LEN] = '\0'; cJSON_AddStringToObject(status, "checksum", checksum_HEX); } psession->file_size = stat_i.st_size; SCPSDebug("file %s, size = %d\n", param->valuestring, psession->file_size); skip_session: //数据发送任务需要等发送完response包后再创建 *new_session = ses_index; *new_status = status; ctx_unlock_session(SESSION_TYPE_SOURCE); return SCP_ERROR_CODE_ACCEPT; error_send_request: if (fd >= 0) { scp_close_file(&fd); } if (0 != ses_index) { clean_session(SESSION_TYPE_SOURCE, psession); } ctx_unlock_session(SESSION_TYPE_SOURCE); return ret; } int recv_file_request(int id, cJSON* control) { int ret = 0; int ses_index = -1; scp_session *psession = NULL; scp_target_session *pext = NULL; int fd = -1; cJSON *param = NULL, *param_status = NULL, *param2 = NULL; char *filename = NULL; mode_t mode = 0; int set_date = 0; int size = 0; char *checksum = NULL; int atime = -1; int mtime = -1; //assert(control != NULL) param = cJSON_GetObjectItem(control, "filename"); CHECK_PARAM(param, cJSON_String); filename = param->valuestring; if (strlen(filename) > SCP_MAX_FILEPATH_LEN) { return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; } param_status = cJSON_GetObjectItem(control, "file_status"); CHECK_PARAM(param_status, cJSON_Object); param = cJSON_GetObjectItem(param_status, "date"); if (NULL != param) { //SCPSDebug("find date param."); CHECK_PARAM(param, cJSON_Object); param2 = cJSON_GetObjectItem(param, "access_time"); if (NULL != param2) { CHECK_PARAM(param2, cJSON_Number); atime = param2->valueint; } param2 = cJSON_GetObjectItem(param, "change_time"); if (NULL != param2) { CHECK_PARAM(param2, cJSON_Number); mtime = param2->valueint; } set_date = 1; } param = cJSON_GetObjectItem(param_status, "permissions"); if (NULL != param) { CHECK_PARAM(param, cJSON_String); sscanf(param->valuestring, "%o", &mode); } param = cJSON_GetObjectItem(param_status, "size"); CHECK_PARAM(param, cJSON_Number); size = param->valueint; // 文件大小为0时checksum无意义 if (size > 0) { param = cJSON_GetObjectItem(param_status, "checksum"); CHECK_PARAM(param, cJSON_String); checksum = param->valuestring; if (strlen(checksum) != SCP_SHA_CHECKSUM_STR_LEN) { return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; } } if (0 != check_file_permission(filename, SESSION_TYPE_TARGET, set_date)) { return SCP_ERROR_CODE_OPERATION_NO_PERMISSION; } SCPSDebug("recv_file_request start."); ctx_wrlock_session(SESSION_TYPE_TARGET); ret = scp_open_file_write(&fd, filename); if (ret) { goto error_recv_request; } if (0 != mode) fchmod(fd, mode); if (size <= 0) { SCPSDebug("filesize 0."); set_file_time(fd, atime, mtime); scp_close_file(&fd); goto skip_session; } ret = create_session(SESSION_TYPE_TARGET, id, fd, &ses_index); if (ret) { goto error_recv_request; } init_session_target(ses_index); // 设置文件基本信息 psession = ctx_get_session(SESSION_TYPE_TARGET, ses_index); pext = ctx_get_target_extention(ses_index); SCPSDebug("set file stat."); pext->time[0] = atime; pext->time[1] = mtime; psession->file_size = size; if (size > 0) { SCPSDebug("cache checksum."); hex2bin(checksum, (unsigned char *)pext->checksum, SCP_SHA_CHECKSUM_STR_LEN); } skip_session: ctx_unlock_session(SESSION_TYPE_TARGET); return SCP_ERROR_CODE_ACCEPT; error_recv_request: if (fd >= 0) { scp_close_file(&fd); } if (0 != ses_index) { clean_session(SESSION_TYPE_TARGET, psession); } ctx_unlock_session(SESSION_TYPE_TARGET); return ret; } int scp_open_file_read(int *fd, char *filename) { //assert(*fd < 0); SCPSDebug("open file %s read", filename); int new_fd = open(filename, O_RDONLY); if (new_fd < 0) return SCP_ERROR_CODE_OPERATION_FILE_NOT_FOUND; if (flock(new_fd, LOCK_SH | LOCK_NB)) { SCPSDebug("lock file %s failed.", filename); close(new_fd); return SCP_ERROR_CODE_OPERATION_FILE_IN_USE; } *fd = new_fd; return 0; } int scp_open_file_write(int *fd, char *filename) { //assert(*fd < 0); SCPSDebug("open file %s write", filename); int new_fd = -1; if (access(filename, F_OK) != -1) new_fd = open(filename, O_WRONLY | O_TRUNC); else new_fd = open(filename, O_WRONLY | O_CREAT); if (new_fd < 0) return SCP_ERROR_CODE_SERVER_ERROR; if (flock(new_fd, LOCK_EX | LOCK_NB)) { SCPSDebug("lock file %s failed.", filename); close(new_fd); return SCP_ERROR_CODE_OPERATION_FILE_IN_USE; } *fd = new_fd; return 0; } int scp_close_file(int *fd) { if (*fd < 0) return 0; flock(*fd, LOCK_UN); close(*fd); *fd = -1; return 0; } int init_session_target(int ses_index) { scp_contextp->target_ext[ses_index].offset = 0; SHA256_Init(&(scp_contextp->target_ext[ses_index].ctx)); return 0; } int create_session(int type, int id, int fd, int *res) { SCPSDebug("create session %d %d.", type, id); int len; int i = 0; int tar = -1; scp_session *psession; ctx_session_foreach(type, i, psession) { if (psession->state == SESSION_STATE_STOP && -1 == tar) tar = i; if (SESSION_TYPE_TARGET == type && psession->id == id) { //只有接收模式的id对重复是敏感的 return SCP_ERROR_CODE_CONTROL_VALUE_ILLEGAL; } } if (-1 == tar && i >= scp_contextp->session_max[type]) { if (scp_contextp->session_max[type] < SCP_MAX_SESSION_NUM) { scp_contextp->session_max[type]++; } else { SCPSDebug("session %d full.", type); return SCP_ERROR_CODE_SERVER_ERROR; } tar = i; } scp_contextp->session[type][tar] = (scp_session) { .id = id, .fd = fd, .file_size = 0, .state = SESSION_STATE_RUNNING, .expire = 0 }; SCPSDebug("new session %d %d.", type, tar); *res = tar; return 0; } int match_session(int type, int id) { int i = 0; scp_session *psession; ctx_session_foreach(type, i, psession) { if (psession->state != SESSION_STATE_RUNNING) continue; if (psession->id == id) { SCPSDebug("match session %d %d %d.", type, id, i); return i; } } SCPSDebug("session %d %d not found.", type, id); return -1; } int clean_session(int type, scp_session* psession) { //SCPSDebug("clean session %d %d.", type, psession->id); psession->state = SESSION_STATE_STOP; scp_close_file(&(psession->fd)); //target扩展信息没有动态申请内存,无需处理 while ((scp_contextp->session_max[type] > 0) && (SESSION_STATE_STOP == scp_contextp->session[type][scp_contextp->session_max[type] - 1].state)) scp_contextp->session_max[type]--; SCPSDebug("session %d %d cleaned, session max %d.", type, psession->id, scp_contextp->session_max[type]); return 0; } void init_session() { int i = 0; for (i = 0; i < SCP_MAX_SESSION_NUM; i++) { scp_contextp->session[SESSION_TYPE_SOURCE][i].state = SESSION_STATE_STOP; scp_contextp->session[SESSION_TYPE_TARGET][i].state = SESSION_STATE_STOP; } scp_contextp->session_max[SESSION_TYPE_SOURCE] = 0; scp_contextp->session_max[SESSION_TYPE_TARGET] = 0; pthread_rwlock_init(&(scp_contextp->sessionlock[SESSION_TYPE_SOURCE]), NULL); pthread_rwlock_init(&(scp_contextp->sessionlock[SESSION_TYPE_TARGET]), NULL); } void close_all_session() { int i = 0; scp_session *psession; SCPSDebug("clean all sessions."); ctx_wrlock_session(SESSION_TYPE_TARGET); ctx_session_foreach(SESSION_TYPE_TARGET, i, psession) { if (psession->state == SESSION_STATE_RUNNING) clean_session(SESSION_TYPE_TARGET, psession); } ctx_unlock_session(SESSION_TYPE_TARGET); // 发送会话需等任务自行结束 ctx_wrlock_session(SESSION_TYPE_SOURCE); ctx_session_foreach(SESSION_TYPE_SOURCE, i, psession) { if (psession->state == SESSION_STATE_RUNNING) psession->state = SESSION_STATE_HALT; } ctx_unlock_session(SESSION_TYPE_SOURCE); // 防止有任务卡在发包限速的位置 ctx_lock_data_send(); scp_contextp->data_speed_limit = SCP_MAX_SESSION_NUM; scp_contextp->data_pack_num = 0; ctx_active_data_send(); ctx_unlock_data_send(); usleep(100000); pthread_rwlock_destroy(&(scp_contextp->sessionlock[SESSION_TYPE_SOURCE])); pthread_rwlock_destroy(&(scp_contextp->sessionlock[SESSION_TYPE_TARGET])); } void scp_data_flush() { // 清空发包计数 ctx_lock_data_send(); scp_contextp->data_pack_num = 0; ctx_active_data_send(); ctx_unlock_data_send(); // 检查收包超时 int i = 0; scp_session *psession; ctx_wrlock_session(SESSION_TYPE_TARGET); ctx_session_foreach(SESSION_TYPE_TARGET, i, psession) { if (psession->state == SESSION_STATE_RUNNING) { psession->expire++; if (psession->expire >= SCP_DEFAULT_TIMEOUT) { SCPSDebug("target session %d timeout, id: %d.", psession->id); clean_session(SESSION_TYPE_TARGET, psession); } } } ctx_unlock_session(SESSION_TYPE_TARGET); } void scp_set_data_speed(int speed_limit) { ctx_lock_data_send(); scp_contextp->data_speed_limit = speed_limit; ctx_unlock_data_send(); } void scp_init( scp_context *context, p_scp_send_request sdp, p_scp_send_data_end_callback sdep) { if (NULL == context) { return; } scp_contextp = context; // 设置数据发送任务的回调函数,尤其是发包接口一定要统一 scp_contextp->send_func = sdp; scp_contextp->finish_func = sdep; // 数据发送限速模块 pthread_mutex_init(&(scp_contextp->speedlock), NULL); pthread_cond_init(&(scp_contextp->speedcond), NULL); scp_contextp->data_pack_num = 0; scp_contextp->data_speed_limit = SCP_DEFAULT_SPEED_LIMIT; } void scp_close() { close_all_session(); pthread_mutex_destroy(&(scp_contextp->speedlock)); pthread_cond_destroy(&(scp_contextp->speedcond)); }解析这个文件,怎么实现scp
最新发布
12-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值