static int cftp_receive_handle(struct cftp_descriptor *desc, struct cftp_file_request *req) { int ret; switch (req->st_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: println("Create Device: %s", req->filename); remove(req->filename); ret = mknod(req->filename, req->st_mode, req->st_rdev); break; case S_IFLNK: println("Create Symlink: %s", req->filename); remove(req->filename); ret = symlink(req->filename + text_len(req->filename) + 1, req->filename); if (ret < 0 && errno == EEXIST) { ret = 0; } break; case S_IFDIR: println("Create Directory: %s", req->filename); ret = mkdir(req->filename, req->st_mode); if (ret < 0 && errno == EEXIST) { ret = 0; } break; case S_IFREG: println("Receive Regular File: %s", req->filename); if (desc->receive_handle) { return desc->receive_handle(desc->data, req); } return cftp_server_receive_file(desc, req->filename, req->st_mode, req->offset, req->size); default: error_msg("unknown file type"); cftp_send_error_message(desc, (struct cftp_error_message *) req, "unknown file type"); return -EINVAL; } if (ret < 0) { cftp_send_error_message(desc, (struct cftp_error_message *) req, __FUNCTION__); } else { cftp_send_ack_message(desc, (struct cftp_ack_message *) req, 0, 0); } return ret; }
static int cftp_command_handle(struct cftp_descriptor *desc, struct cftp_command_request *req) { int ret; ret = system(req->command); if (ret < 0) { cftp_send_error_message(desc, (struct cftp_error_message *) req, "system"); } else { cftp_send_ack_message(desc, (struct cftp_ack_message *) req, 0, 0); } return ret; }
int cftp_server_receive_file(struct cftp_descriptor *desc, const char *filename, mode_t mode, u32 offset, size_t size) { int fd; int ret; union cftp_message *msg; ssize_t recvlen, sendlen; u16 blk_num; struct progress_bar bar; size_t max_xfer_length; max_xfer_length = desc->max_xfer_length; msg = malloc(max_xfer_length); if (msg == NULL) { pr_err_info("malloc"); return -ENOMEM; } fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd < 0) { pr_err_info("open file %s faild", filename); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "open file %s faild", filename); ret = fd; goto out_free_msg; } if (offset) { ret = lseek(fd, offset, SEEK_SET); if (ret < 0) { pr_err_info("lseek"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "seek file %s faild", filename); goto out_free_msg; } } println("offset = %s", size2text(offset)); println("size = %s", size2text(size)); blk_num = 0; progress_bar_init(&bar, size, 0, PROGRESS_BAR_TYPE_DATA); while (1) { sendlen = cftp_send_ack_message(desc, (struct cftp_ack_message *) msg, blk_num, desc->retry_count); if (sendlen < 0) { pr_err_info("cftp_send_ack_message"); ret = sendlen; goto out_close_file; } recvlen = cftp_receive_data(desc, msg, max_xfer_length); if (recvlen < 0) { pr_err_info("cftp_receive_data"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "receive file failed"); ret = recvlen; goto out_close_file; } switch (msg->type) { case CFTP_PACKAGE_ERROR: show_error_message((struct cftp_error_message *) msg); ret = -EFAULT; goto out_close_file; case CFTP_PACKAGE_DATA: if (msg->data_pkg.blk_num != blk_num) { pr_warn_info("blk_num %d != %d", msg->data_pkg.blk_num, blk_num); continue; } sendlen = write(fd, msg->data_pkg.data, recvlen - sizeof(msg->data_pkg)); if (sendlen < 0) { pr_err_info("write"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "write file failed"); ret = sendlen; goto out_close_file; } blk_num++; if ((size_t) recvlen < max_xfer_length) { cftp_send_ack_message(desc, (struct cftp_ack_message *) msg, blk_num, 0); progress_bar_finish(&bar); println("Receive data complete"); ret = 0; goto out_close_file; } else { progress_bar_add(&bar, sendlen); } break; default: pr_err_info("invalid package type"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "invalid package type"); ret = -EINVAL; goto out_close_file; } } out_close_file: close(fd); out_free_msg: free(msg); return ret; }
int cftp_client_receive_file(struct cftp_descriptor *desc, const char *file_in, u32 offset_in, const char *file_out, u32 offset_out, size_t size) { int fd; int ret; ssize_t recvlen, sendlen; u16 blk_num; union cftp_message *msg; size_t max_xfer_length; fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, 0777); if (fd < 0) { pr_err_info("open file %s failed", file_out); return fd; } if (offset_out) { ret = lseek(fd, offset_out, SEEK_SET); if (ret < 0) { pr_err_info("lseek"); goto out_close_file; } } max_xfer_length = desc->max_xfer_length; msg = malloc(max_xfer_length); if (msg == NULL) { pr_err_info("malloc"); ret = -ENOMEM; goto out_close_file; } sendlen = cftp_send_file_reuest(desc, (void *) msg, file_in, NULL, offset_in, size, 1); if (sendlen < 0) { pr_err_info("cftp_send_data_retry"); ret = sendlen; goto out_free_msg; } println("Remote@%s => Local@%s", file_in, file_out); println("seek = %s", size2text(offset_out)); println("skip = %s", size2text(offset_in)); println("size = %s", size2text(size)); blk_num = 0; while (1) { recvlen = cftp_receive_data(desc, msg, max_xfer_length); if (recvlen < 0) { pr_err_info("cftp_receive_data"); ret = recvlen; goto out_free_msg; } switch (msg->type) { case CFTP_PACKAGE_ERROR: show_error_message((struct cftp_error_message *) msg); ret = -EFAULT; goto out_free_msg; case CFTP_PACKAGE_DATA: if (msg->data_pkg.blk_num == blk_num) { sendlen = write(fd, msg->data_pkg.data, recvlen - sizeof(msg->data_pkg)); if (sendlen < 0) { pr_err_info("write"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "write file failed"); ret = sendlen; goto out_free_msg; } blk_num++; if ((blk_num & 0xFF) == 0) { print_char('.'); } if ((size_t) recvlen < max_xfer_length) { println(" Receive data complete"); cftp_send_ack_message(desc, (struct cftp_ack_message *) msg, blk_num, 0); ret = 0; goto out_free_msg; } } else { pr_warn_info("%d != %d", msg->data_pkg.blk_num, blk_num); } sendlen = cftp_send_ack_message(desc, (struct cftp_ack_message *) msg, blk_num, desc->retry_count); if (sendlen < 0) { pr_err_info("cftp_send_ack_message"); ret = sendlen; goto out_free_msg; } break; default: pr_err_info("invalid package type"); cftp_send_error_message(desc, (struct cftp_error_message *) msg, "invalid package type"); ret = -EINVAL; goto out_free_msg; } } out_free_msg: free(msg); out_close_file: close(fd); return ret; }