From f040d7c245757b1ac40ec4968a5ca1fbb6440b4a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 3 Aug 2007 19:04:07 +0800 Subject: [PATCH] Add REST and SIZE --- server/src/do_cmd.c | 101 +++++++++++++++++++++++++++++++++++++++++-------- server/src/do_cmd.h | 2 + server/src/parse_cmd.c | 10 ++++- server/src/xylftp.h | 1 + 4 files changed, 98 insertions(+), 16 deletions(-) diff --git a/server/src/do_cmd.c b/server/src/do_cmd.c index c7dbaa0..7a3a05f 100644 --- a/server/src/do_cmd.c +++ b/server/src/do_cmd.c @@ -593,12 +593,23 @@ static int _stat_retr(const char *path) char buf[BUF_LEN]={""}; debug_printf("retr from %s\n",path); + fd = open(path, O_RDONLY); if(fd != -1) { + if((off_t)-1 == lseek(fd, user_env.restartat, SEEK_SET)){ + _stat_fail_501(); + r_close(fd); + #ifdef DEBUG + perror("lseek"); + #else + write_log("lseek error.", 0); + #endif + return -errno; + } _stat_success_150(); while((i = read(fd, buf, BUF_LEN)) != 0) { if (i == -1) { - close(user_env.data_fd); + r_close(user_env.data_fd); _stat_fail_501(); return -1; } else { @@ -608,11 +619,12 @@ static int _stat_retr(const char *path) } user_env.download_files++; r_close(fd); - close(user_env.data_fd); + r_close(user_env.data_fd); + user_env.restartat = 0; _stat_success_226(); return 0; } else { - close(user_env.data_fd); + r_close(user_env.data_fd); _stat_fail_501(); return -1; } @@ -1170,10 +1182,10 @@ int do_stor(char *arg) ssize_t rsize; char buff[BUF_LEN]; -#ifdef DEBUG - printf("****STOR; arg = %s\n", arg); - printf("user_env.current_path=%s\n", user_env.current_path); -#endif + + debug_printf("****STOR; arg = %s\n", arg); + debug_printf("user_env.current_path=%s\n", user_env.current_path); + if (!user_env.enable_upload) { write(user_env.connect_fd, "550 Permission denied.\r\n", strlen("550 Permission denied.\r\n")); close(user_env.data_fd); @@ -1198,9 +1210,9 @@ int do_stor(char *arg) strcat(pathname, "/"); strcat(pathname, arg); } -#ifdef DEBUG - printf("pathname=%s.\n", pathname); -#endif + + debug_printf("pathname=%s.\n", pathname); + fd = open(pathname, O_RDWR|O_CREAT); if (fd < 0) { write(user_env.connect_fd, "550 Permission denied.\r\n", 23); @@ -1212,10 +1224,19 @@ int do_stor(char *arg) #endif return -errno; } - _stat_success_150(); + if((off_t)-1 == lseek(fd, user_env.restartat, SEEK_SET)){ + r_close(fd); #ifdef DEBUG - printf("%s create OK! \n", pathname); + perror("lseek"); +#else + write_log("lseek error.", 0); #endif + return -errno; + } + _stat_success_150(); + + debug_printf("%s create OK! \n", pathname); + sd = user_env.data_fd; for(;;){ rsize = read(sd, buff, BUF_LEN); @@ -1235,14 +1256,64 @@ int do_stor(char *arg) } r_close(fd); r_close(sd); + user_env.restartat = 0; write(user_env.connect_fd, stor_ok, strlen(stor_ok)); user_env.upload_files++; -#ifdef DEBUG - printf("%d files, %d KB.\n", user_env.upload_files, user_env.upload_kbytes); -#endif + + debug_printf("%d files, %d KB.\n", user_env.upload_files, user_env.upload_kbytes); + return 0; } +int do_rest(const char *arg) +{ + char *endptr; + const char failed_msg[] = "501 REST needs a numeric parameter\r\n"; + const char succ_msg[] = "350 Restarting successfully." + " Send STORE or RETRIEVE to initiate transfer\r\n"; + const char restrict_msg[] = "501 REST: Resuming transfers not" + " allowed in ASCII mode\r\n"; + user_env.restartat = (off_t) strtoull(arg, &endptr, 10); + if (*endptr != 0 || user_env.restartat < (off_t) 0) { + user_env.restartat = 0; + write(user_env.connect_fd, failed_msg, strlen(failed_msg)); + return -1; + } else { + if (user_env.ascii_on && user_env.restartat != 0) { + write(user_env.connect_fd, restrict_msg, strlen(restrict_msg)); + return 0; + } else { + write(user_env.connect_fd, succ_msg, strlen(succ_msg)); + return 0; + } + } +} + +int do_size(const char *name) +{ + const char fail_msg[] = "550 Could not get file size.\r\n"; + const char fail_msg2[] = "550 I can only retrieve regular files.\r\n"; + char buf[MAX_MSG_LEN] = {0,}; + struct stat st; + + if (!*name) { + write(user_env.connect_fd, fail_msg, strlen(fail_msg)); + return -1; + } else if (stat(name, &st)) { + write(user_env.connect_fd, fail_msg, strlen(fail_msg)); + write_log("stat failed.", 0); + return -errno; + } else if (!S_ISREG(st.st_mode)) { + write(user_env.connect_fd, fail_msg2, strlen(fail_msg2)); + return -1; + } else { + snprintf(buf, MAX_MSG_LEN, "%d %llu\r\n", 213, + (unsigned long long)st.st_size); + write(user_env.connect_fd, buf, strlen(buf)); + return 0; + } +} + /*reply the wrong or unsupported command*/ int failed(const char *s) { diff --git a/server/src/do_cmd.h b/server/src/do_cmd.h index f703b9a..7731bd0 100644 --- a/server/src/do_cmd.h +++ b/server/src/do_cmd.h @@ -38,4 +38,6 @@ extern int failed(const char *); extern int do_retr(const char *); extern int do_mode(const char *); extern int do_stru(char *); +extern int do_rest(const char *); +extern int do_size(const char *); #endif /*end of _DO_CMD_H*/ diff --git a/server/src/parse_cmd.c b/server/src/parse_cmd.c index fec275a..182d9a1 100644 --- a/server/src/parse_cmd.c +++ b/server/src/parse_cmd.c @@ -33,7 +33,7 @@ struct parse_cmd{ const char *commands[] = {"USER","PASS","SYST","QUIT","RETR","STOR","RNFR","RNTO","ABOR","DELE", "RMD","MKD","PWD","CWD","CDUP","PORT","NOOP","PASV","TYPE","MODE", - "STAT","STRU","LIST"}; /*服务器支持的所有命令*/ + "STAT","STRU","LIST", "REST", "SIZE"}; /*服务器支持的所有命令*/ static int _line_cmd(char *line_buf, struct parse_cmd *user_cmd) { @@ -222,6 +222,14 @@ int parse_cmd(char *p_buf) debug_printf("call list()\n"); do_list(user_cmd.arg); break; + case 24: + debug_printf("call rest()\n"); + do_rest(user_cmd.arg); + break; + case 25: + debug_printf("call size()\n"); + do_size(user_cmd.arg); + break; default: debug_printf("call failed()\n"); failed(user_cmd.cmd); diff --git a/server/src/xylftp.h b/server/src/xylftp.h index c04ed22..ee96ee5 100644 --- a/server/src/xylftp.h +++ b/server/src/xylftp.h @@ -109,6 +109,7 @@ struct user_env{ bool ascii_on; /*是否为ascii码模式*/ int connect_fd; /*控制连接*/ int data_fd; /*数据连接*/ + off_t restartat; /*REST续传位置*/ unsigned int port_connections; /*对其它主机使用port命令的次数*/ unsigned int upload_files; unsigned int upload_kbytes; -- 2.11.4.GIT