📄 cmdftp.c
字号:
start_transfer: transfer_interrupted = TRAN_INTR_NO; if (my_raw_write(s, len, cmdftp_control) < 0) { s[len - 2] = 0; if TRANSFER_INTERRUPTED_CHECK(s, 0); } else { s[len - 2] = 0; if (!(rv = recv_answer(0, 0, suppress_err))) { if TRANSFER_INTERRUPTED_CHECK(s, 1); } } free(s); return rv;}void reset_cmd_buffer(void) { cmd_ptr = cmd_buffer + CMD_BUF_SIZE;}char* recv_line(int sc) { char* new_ptr; ptrdiff_t n; size_t len; if (*cmd_ptr == 0) { ssize_t bytes = my_raw_read(cmd_buffer, CMD_BUF_SIZE, sc); if (bytes <= 0) return 0; cmd_buffer[bytes] = 0; cmd_ptr = cmd_buffer; if (*cmd_ptr == '\n' && cmd_buffer[CMD_BUF_SIZE - 1] == '\r') cmd_ptr++; } new_ptr = strchr(cmd_ptr, '\r'); if (!new_ptr) new_ptr = cmd_buffer + CMD_BUF_SIZE; n = new_ptr - cmd_ptr; strncpy(cmd_line, cmd_ptr, n); cmd_line[n] = 0; cmd_ptr = new_ptr; if (cmd_ptr == cmd_buffer + CMD_BUF_SIZE) { ssize_t bytes = my_raw_read(cmd_buffer, CMD_BUF_SIZE, sc); if (bytes <= 0) return 0; cmd_buffer[bytes] = 0; cmd_ptr = cmd_buffer; new_ptr = strchr(cmd_ptr, '\r'); if (!new_ptr) new_ptr = cmd_buffer + CMD_BUF_SIZE; n = new_ptr - cmd_ptr; len = strlen(cmd_line); strncat(cmd_line, cmd_ptr, n); cmd_line[len + n] = 0; cmd_ptr = new_ptr; } if (*cmd_ptr == '\r') { cmd_ptr++; if (*cmd_ptr == '\n') cmd_ptr++; } return cmd_line;}int recv_confirm(void) { int rv = 0; start_transfer: if (recv_answer(0, 0, 0) == 226) rv = 1; else if TRANSFER_INTERRUPTED_CHECK("recv_confirm", 1); return rv;}int recv_answer(int store, struct line_data* d, char suppress_err) { char* answer; int code; char str_code[] = { 0, 0, 0, ' ', 0 }; reset_cmd_buffer(); answer = recv_line(cmdftp_control); if (!answer || strlen(answer) < 3) return 0; strncpy(str_code, answer, 3); if (answer[3] == '-') { while ((answer = recv_line(cmdftp_control))) { if (strncmp(answer, str_code, 4) == 0) break; if (store) store_line(answer, d); else printf("%s\n", answer); } } sscanf(str_code, "%i", &code); if (code >= 400 && !suppress_err) { cmdftp_war(CMDFTP_WAR_RERR, answer); } return code;}int getport() { unsigned int b[6]; int i, answer; size_t len; char* port_str; if ((answer = send_command("PASV", 0)) != 227) return 0; port_str = cmd_buffer + 4; len = strlen(port_str += 4); for (i = 0; i < len; i++) if (!isdigit(port_str[i])) port_str[i] = ' '; if (sscanf(port_str, "%u %u %u %u %u %u", b, b + 1, b + 2, b + 3, b + 4, b + 5) != 6) return 0; return b[4] * 256 + b[5];}/*******************************//* MEMORY AND STRING FUNCTIONS *//*******************************/void* my_malloc(size_t s) { void* rv; if (!(rv = malloc(s))) cmdftp_err(CMDFTP_ERR_HEAP, ""); return rv;}void* my_realloc(void* ptr, size_t s) { void* rv; if (!(rv = realloc(ptr, s))) cmdftp_err(CMDFTP_ERR_HEAP, ""); return rv;}#if !HAVE_STRDUPchar* strdup(char* s) { char* rv = malloc(strlen(s) + 1); strcpy(rv, s); return rv;}#endifchar* my_strdup(char* s) { char* rv; if (!(rv = strdup(s))) cmdftp_err(CMDFTP_ERR_HEAP, ""); return rv;}/***************************//* OTHER UTILITY FUNCTIONS *//***************************/void cleanexit(void) { exit(fclose(stdout) == 0 ? 0 : -1);}void split_cmd(char* cmd, char** argv) { size_t len; int i; len = strlen(cmd); for (i = 0; i < 4; i++) { argv[i] = my_malloc(len + 1); while (isspace(*cmd)) cmd++; read_token(&cmd, argv[i]); }}void free_cmd(char** argv) { int i; for (i = 0; i < 4; i++) { if (argv[i]) { free(argv[i]); argv[i] = 0; } }} int str_binsearch(char* key) { int low, high, mid, chk; low = 0; high = N_COMMANDS - 1; while (low <= high) { mid = (low + high) / 2; if ((chk = strcmp(key, commands[mid])) > 0) low = mid + 1; else if (chk < 0) high = mid - 1; else return mid; } return -1;}char* readline(int enable_tab, int enable_echo) { char* ptr; int c; ptr = cmd_userinput; memset(cmd_userinput, 0, sizeof(cmd_userinput)); cmdftp_raw_mode(); while (1) { c = fgetc(stdin); if (c == '\n') { *ptr = 0; fputc('\n', stdout); break; } else if ((c == '\t') && (enable_tab) && (ptr - cmd_userinput) < (CMD_BUF_SIZE - 10)) { readline_tab(); ptr = cmd_userinput + strlen(cmd_userinput); } else if (c == cmdftp_termios.c_cc[VERASE] || c == 8) readline_bs(&ptr, enable_echo); else if ((c >= 32) && (c <= 127)) { if ((ptr - cmd_userinput) < (CMD_BUF_SIZE - 10)) { *ptr++ = c; if (enable_echo) fputc(c, stdout); } } else if (c == EOF) break; } cmdftp_canon_mode(); return (c != EOF) ? my_strdup(cmd_userinput) : 0;}void readline_bs(char** ptr, int enable_echo) { if (*ptr > cmd_userinput) { *(--(*ptr)) = 0; if (enable_echo) fprintf(stdout, "\b \b"); }}void readline_tab(void) { char* argv[4]; char* mask, *completion; struct list_data ld; int c, i, j, lc_mode; size_t len, len_buffer; split_cmd(cmd_userinput, argv); if (!*argv[1]) { free_cmd(argv); return; } mask = 0; c = i = j = len = len_buffer = 0; init_list(&ld); if (strcmp(argv[0], "d") == 0 || strcmp(argv[0], "dr") == 0) { lc_mode = *argv[2] ? CMDFTP_LOCAL : CMDFTP_REMOTE; } else if (strcmp(argv[0], "u") == 0) { lc_mode = *argv[2] ? CMDFTP_REMOTE : CMDFTP_LOCAL; } else lc_mode = mode; if (*(mask = argv[2]) != '\0') { char* tmp; tmp = escape_string(argv[1]); free(argv[1]); argv[1] = tmp; } else { mask = argv[1]; } strcat(mask, "*"); len_buffer = strlen(mask) - 1; if (!mf[lc_mode][MODE_FETCH_LIST](mask, &ld) || ld.count == 0) goto endtab; escape_list(&ld); len = strlen(ld.data[0].escaped_fullname); for (i = 0; i < len; i++) { c = ld.data[0].escaped_fullname[i]; for (j = 1; j < ld.count; j++) { if (ld.data[j].escaped_fullname[i] != c) goto endcommon; } } endcommon: endtab: if (ld.count) { completion = my_malloc(i + 2); strncpy(completion, ld.data[0].escaped_fullname, i); if (ld.count == 1 && mf[lc_mode][MODE_FILE](ld.data[0].fullname) == FILE_ISDIR) completion[i++] = '/'; completion[i] = 0; } else { completion = my_malloc(len_buffer + 1); strncpy(completion, mask, len_buffer); completion[len_buffer] = 0; } snprintf(cmd_userinput, CMD_BUF_SIZE, "%s%s%s%s%s", argv[0], *argv[1] ? " " : "", *argv[2] ? argv[1] : "", *argv[2] ? " " : "", completion); free(completion); if (ld.count > 1) { fputc('\n', stdout); for (j = 0; j < ld.count; j++) { printf("%s\n", ld.data[j].escaped_fullname); } } else { fputc('\r', stdout); } print_prompt(); printf("%s", cmd_userinput); free_list(&ld); free_cmd(argv);}void cmdftp_pwd_start(void) { cmdftp_termios.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &cmdftp_termios);}void cmdftp_pwd_end(void) { cmdftp_termios.c_lflag |= ECHO; tcsetattr(0, TCSANOW, &cmdftp_termios);}void cmdftp_raw_mode(void) { cmdftp_termios.c_lflag &= ~ICANON; cmdftp_termios.c_lflag &= ~ECHO; cmdftp_termios.c_cc[VMIN] = 1; cmdftp_termios.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, &cmdftp_termios);}void cmdftp_canon_mode(void) { cmdftp_termios.c_lflag |= ICANON; cmdftp_termios.c_lflag |= ECHO; tcsetattr(0, TCSANOW, &cmdftp_termios);}int cmdftp_execute(char* p1, char* p2, int read_fd, int write_fd) { char** argv = 0; char* argptr; pid_t pid; int status, rv, count; rv = count = 0; argptr = p1 = my_strdup(p1); do { argv = my_realloc(argv, sizeof(char*) * (count + 1)); argv[count++] = argptr; argptr = strchr(argptr + 1, ' '); if (argptr) *argptr++ = 0; } while (argptr); count += (p2 ? 2 : 1); argv = my_realloc(argv, sizeof(char*) * count); argv[count - 1] = 0; if (p2) argv[count - 2] = p2; if ((pid = fork()) < 0) goto end_proc; else if (pid > 0) { if (waitpid(pid, &status, 0) > 0) { if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) rv = 1; } } else { if (read_fd != -1) { close(0); dup(read_fd); close(read_fd); } if (write_fd != -1) { close(1); dup(write_fd); close(write_fd); } execvp(argv[0], argv); exit(-1); } end_proc: free(p1); free(argv); return rv;}/* temporary file handling */char* cmdftp_temp_fn;size_t cmdftp_temp_fn_len;int is_good_tmpdir(char* candidate) { struct stat buf; if (stat(candidate, &buf) != 0) return 0; return (S_ISDIR(buf.st_mode) && (buf.st_mode & S_IRWXU));}void init_temp(void) { if (env[CMDFTP_ENV_TMPDIR] && is_good_tmpdir(env[CMDFTP_ENV_TMPDIR])) { cmdftp_temp_fn = fullpath(env[CMDFTP_ENV_TMPDIR], "cmdftpXXXXXX");#ifdef P_tmpdir } else if (is_good_tmpdir(P_tmpdir)) { cmdftp_temp_fn = fullpath(P_tmpdir, "cmdftpXXXXXX");#endif } else if (is_good_tmpdir("/tmp")) { cmdftp_temp_fn = fullpath("/tmp", "cmdftpXXXXXX"); } else { cmdftp_err(CMDFTP_ERR_TMPD, ""); } cmdftp_temp_fn_len = strlen(cmdftp_temp_fn);}#if !HAVE_MKSTEMPint mkstemp(char* template) {#define MKSTEMP_ATTEMPTS 10 int rv, attempt; size_t len; char *ptr; off_t n; char ascii[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; len = strlen(template); /* must be >= 6 */ ptr = template + len - 6; /* point to XXXXXX part */ n = *((off_t*)o.hostname); /* a crazy thing */ if (n < 0) n = -n; for (attempt = 0; attempt < MKSTEMP_ATTEMPTS; attempt++) { int i; for (i = 0; i < 6; i++) { ptr[i] = ascii[n % (sizeof(ascii) - 1)]; n /= sizeof(ascii) - 1; } rv = open(template, O_RDWR | O_CREAT | O_EXCL, 0600); if (rv >= 0 || errno != EEXIST) return rv; } errno = EEXIST; return -1;#undef MKSTEMP_ATTEMPTS}#endifFILE* cmdftp_temp(char** fn) { int i; FILE* rv; *fn = 0; for (i = cmdftp_temp_fn_len - 6; i < cmdftp_temp_fn_len; i++) cmdftp_temp_fn[i] = 'X'; if ((i = mkstemp(cmdftp_temp_fn)) < 0) return 0; if (!(rv = fdopen(i, "r+"))) return 0; *fn = my_strdup(cmdftp_temp_fn); return rv;}void canonized_fn(char* des[3], char* arg) { char* tmpmask; tmpmask = my_strdup(arg); des[0] = my_strdup(dirname(tmpmask)); free(tmpmask); tmpmask = my_strdup(arg); des[1] = my_strdup(basename(tmpmask)); free(tmpmask); des[2] = fullpath(des[0], des[1]);}/*****************************************************************************/void free_fn(char* des[3]) { int i; for (i = 0; i < 3; i++) free(des[i]);}/*****************************************************************************/char* clean_fn(char* fn) { if (strncmp(fn, "./", 2) == 0) return fn + 2; else if(strncmp(fn, "//", 2) == 0) return fn + 1; else return fn;}/*****************************************************************************/char* fullpath(char* s, char* q) { char* rv = my_malloc(strlen(s) + strlen(q) + 2); sprintf(rv, "%s/%s", s, q); return rv;}/********************//* SIGNAL FUNCTIONS *//********************/void init_signals(void) { memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, 0); sa.sa_handler = &handler_INT; sigaction(SIGINT, &sa, 0);}void handler_INT(int i) { if (transfer_interrupted == TRAN_INTR_INT) { cmdftp_err(CMDFTP_ERR_INTR, ""); } else { transfer_interrupted = TRAN_INTR_INT; }}/******************************//* STRUCT LINE_DATA FUNCTIONS *//******************************/void init_lines(struct line_data* d) { d->count = 0; d->lines = 0;}void init_list(struct list_data* d) { d->count = 0; d->data = 0;}void escape_list(struct list_data* d) { int i; for (i = 0; i < d->count; i++) { d->data[i].escaped_fullname = escape_string(d->data[i].fullname); }}char* escape_string(char* filestring) { char* src, *dst, *fs_new; size_t len; len = strlen(src = filestring); dst = fs_new = my_malloc(len * 2 + 1); do { if (*src == '\\') { *dst++ = '\\'; } else if (*src == ' ') { *dst++ = '\\'; } } while ((*dst++ = *src++)); return fs_new;}void store_line(char* line, struct line_data* d) { int i = d->count; d->lines = my_realloc(d->lines, sizeof(char*) * (++d->count)); d->lines[i] = my_malloc(CMD_BUF_SIZE - 9); strncpy(d->lines[i], line, CMD_BUF_SIZE - 10); d->lines[i][CMD_BUF_SIZE - 10] = 0; }void store_list(char* fullname, struct list_data* d) { int i; char* base; base = basename(fullname); if ((o.d && (strcmp(base, ".") == 0 || strcmp(base, "..") == 0)) || (!o.d && *base == '.')) return; i = d->count; d->data = my_realloc(d->data, sizeof(struct list_entry) * (++d->count)); d->data[i].escaped_fullname = 0; d->data[i].fullname = my_strdup(fullname); d->data[i].basename = my_strdup(base); d->data[i].dirname = my_strdup(dirname(fullname));}void store_pretty_list(char* fullname, struct list_data* d) { int i = d->count; d->data = my_realloc(d->data, sizeof(struct list_entry) * (++d->count)); d->data[i].escaped_fullname = 0; d->data[i].fullname = my_strdup(fullname); d->data[i].basename = d->data[i].dirname = 0;}void free_lines(struct line_data* d) { int i; if (d->lines) { for (i = 0; i < d->count; i++) free(d->lines[i]); free(d->lines); d->lines = 0; } d->count = 0;}void free_list(struct list_data* d) { int i; if (d->data) { for (i = 0; i < d->count; i++) { if (d->data[i].escaped_fullname) free(d->data[i].escaped_fullname); if (d->data[i].fullname) free(d->data[i].fullname); if (d->data[i].basename) free(d->data[i].basename); if (d->data[i].dirname) free(d->data[i].dirname); } free(d->data); d->data = 0; } d->count = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -