📄 cmdftp.c
字号:
/* cast between function pointer types is always ok, as soon as we remember to cast back to the right type before using one. */ char* (*fun_getcwd)(void) = (char* (*)(void))mf[mode][MODE_GETCWD]; if (cwd[mode]) free(cwd[mode]); if ((cwd[mode] = fun_getcwd())) cwd[mode] = my_strdup(cwd[mode]); else if ((cwd[mode] = fun_getcwd())) cwd[mode] = my_strdup(cwd[mode]); else cmdftp_err(CMDFTP_ERR_PWD, "");}/**************************************//* DISPATCHED COMMANDS *//**************************************/int cmd_quit(char** argv) { cmdftp_war(CMDFTP_WAR_BYE, ""); cleanexit(); return 0; /* never reached */}int cmd_h(char** argv) { char* arg; int i; arg = argv[0]; if (*arg != 0) cmdftp_war(CMDFTP_WAR_IARG, arg); for (i = 0; i < (sizeof(msg_help) / sizeof(char*)); i += 2) printf("%-14s %s\n", msg_help[i], msg_help[i + 1]); return 1;} int cmd_l(char** argv) { char* arg; arg = argv[0]; if (*arg != 0) cmdftp_war(CMDFTP_WAR_IARG, arg); mode = CMDFTP_LOCAL; return 1;}int cmd_r(char** argv) { char* arg; arg = argv[0]; if (*arg != 0) cmdftp_war(CMDFTP_WAR_IARG, arg); mode = CMDFTP_REMOTE; return 1;}int cmd_pwd(char** argv) { char* arg; arg = argv[0]; if (*arg != 0) cmdftp_war(CMDFTP_WAR_IARG, arg); printf("%s\n", cwd[mode]); return 1;}int cmd_cd(char** argv) { char* arg; int rv; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } if ((rv = mf[mode][MODE_CHDIR](arg)) == -2) return 0; do_setcwd(mode); return (rv == 0);}int cmd_ren(char** argv) { int rv; if (*argv[0] == 0 || *argv[1] == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } rv = do_ren(argv[0], argv[1], argv[2]); return rv;}int cmd_rm(char** argv) { char* arg; struct list_data d; int i, rv = 0; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } init_list(&d); if (!mf[mode][MODE_FETCH_LIST](arg, &d)) return 0; if (d.count == 0) { cmdftp_war(CMDFTP_WAR_MASK, arg); return 1; } for (i = 0; i < d.count; i++) { int ft; if ((ft = mf[mode][MODE_FILE](d.data[i].fullname)) < 0 || (ft == FILE_ISREG && !mf[mode][MODE_UNLINK](d.data[i].fullname))) break; if (i == d.count - 1) rv = 1; } free_list(&d); return rv;}int cmd_ls(char** argv) { char* arg; struct list_data d; int rv; arg = argv[0]; init_list(&d); if (!mf[mode][MODE_FETCH_LIST](arg, &d)) return 0; if (d.count == 0) { cmdftp_war(CMDFTP_WAR_MASK, arg); return 1; } rv = ls(&d); free_list(&d); return rv;}int cmd_dir(char** argv) { char* arg; struct list_data d; int rv; arg = argv[0]; if (*arg != 0) cmdftp_war(CMDFTP_WAR_IARG, arg); init_list(&d); if (!mf[mode][MODE_FETCH_PRETTY_LIST](&d)) return 0; if (d.count == 0) { cmdftp_war(CMDFTP_WAR_MASK, ""); return 1; } rv = ls(&d); free_list(&d); return rv;}int cmd_md(char** argv) { char* arg; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } return mf[mode][MODE_MKDIR](arg);}int cmd_rd(char** argv) { char* arg; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } return mf[mode][MODE_RMDIR](arg);}int cmd_p(char** argv) { char* arg; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } return mf[mode][MODE_PRINT](arg);}int cmd_e(char** argv) { char* arg; arg = argv[0]; if (*arg == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } if (!env[CMDFTP_ENV_EDITOR]) { cmdftp_war(CMDFTP_WAR_MENV, "EDITOR"); return 0; } return mf[mode][MODE_EDIT](arg);}/**************************************//* UPLOAD AND DOWNLOAD *//**************************************/int cmd_u(char** paths) { char* source_mask; int rv; int tt; struct list_data ld; if (*paths[0] == 0 || *paths[1] == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } if ((tt = remote_file(paths[1])) < 0) return 0; if (tt != FILE_NEXIST && tt != FILE_ISDIR) { cmdftp_war(CMDFTP_WAR_TRG, "exists (not a dir)"); return 0; } source_mask = my_strdup(paths[0]); init_list(&ld); if (!local_fetch_list(paths[0], &ld)) return 0; if (ld.count == 0) { cmdftp_war(CMDFTP_WAR_MASK, paths[0]); return 1; } if (ld.count == 1) { int st = local_file(ld.data[0].fullname); if (st == FILE_ISDIR && tt == FILE_NEXIST) { free(source_mask); source_mask = fullpath(paths[0], "*"); } } free_list(&ld); rv = u_aux(paths[1], source_mask); free(source_mask); return rv;}int u_aux(char* target_dir, char* source_mask) { struct list_data ld; char* target[3]; int i, rv; if ((rv = remote_file(target_dir)) == FILE_NEXIST) { if (!remote_mkdir(target_dir)) return 0; } else if (rv != FILE_ISDIR) { return 0; } init_list(&ld); if (!local_fetch_list(source_mask, &ld)) return 0; if (ld.count == 0) return 1; canonized_fn(target, target_dir); rv = 1; for (i = 0; i < ld.count; i++) { int file_type = local_file(ld.data[i].fullname); if (file_type == FILE_ISREG) { FILE* f = fopen(ld.data[i].fullname, "rb"); if (!f) cmdftp_war(CMDFTP_WAR_OPEN, ld.data[i].fullname); else { char* fn; fn = fullpath(target[2], ld.data[i].basename); rv = upload(fn, f); fclose(f); free(fn); } } else if (file_type == FILE_ISDIR) { char* tmp_src, *tmp_trg; tmp_src = fullpath(ld.data[i].fullname, "*"); tmp_trg = fullpath(target[2], ld.data[i].basename); rv = u_aux(tmp_trg, tmp_src); free(tmp_trg); free(tmp_src); } else { cmdftp_war(CMDFTP_WAR_SKIP, ld.data[i].fullname); } if (!rv) break; } free_list(&ld); free_fn(target); return rv;}int upload(char* target, FILE* source) { off_t start_pos, total_size; char* ctarget; char* op; size_t ctarget_len; int port, rv; rv = 0; op = "Uploading"; ctarget = clean_fn(target); ctarget_len = strlen(ctarget); start_transfer: if (!send_command("TYPE I", 0)) return 0; if ((total_size = local_size(source)) < 0) return 0; start_pos = 0; if (!(port = getport())) return 0; if (!(cmdftp_data = cmdftp_connect(port))) return 0; snprintf(cmd_buffer, CMD_BUF_SIZE, "STOR %s", target); if (send_command(cmd_buffer, 0) != 150) { close(cmdftp_data); return 0; } if (!o.q) print_progress(op, ctarget, ctarget_len, start_pos, total_size); transfer_interrupted = TRAN_INTR_NO; while (start_pos < total_size) { size_t toread, bytes; ssize_t written; toread = ((total_size - start_pos) < o.b) ? total_size - start_pos : o.b; if (!(bytes = fread(buffer, 1, toread, source))) break; if ((written = my_raw_write(buffer, bytes, cmdftp_data)) != bytes) break; start_pos += bytes; if (!o.q) print_progress(op, ctarget, ctarget_len, start_pos, total_size); } if (!o.q) fputc('\n', stdout); close(cmdftp_data); if (start_pos < total_size) { if (ferror(source)) cmdftp_war(CMDFTP_WAR_READ, basename(target)); else if TRANSFER_INTERRUPTED_CHECK("data transfer", 1); else { cmdftp_err(CMDFTP_ERR_UNER, strerror(errno)); } } else { if (!recv_confirm()) cmdftp_war(CMDFTP_WAR_NOCT, ""); else rv = 1; } return rv;}int cmd_d(char** argv) { return do_d(argv, 0);}int cmd_dr(char** argv) { return do_d(argv, 1);}int do_d(char** paths, int resume) { char* source_mask; int rv; int tt; struct list_data ld; if (*paths[0] == 0 || *paths[1] == 0) { cmdftp_war(CMDFTP_WAR_MARG, ""); return 0; } if ((tt = local_file(paths[1])) != FILE_NEXIST && tt != FILE_ISDIR) { cmdftp_war(CMDFTP_WAR_TRG, "exists (not a dir)"); return 0; } source_mask = my_strdup(paths[0]); init_list(&ld); if (!remote_fetch_list(paths[0], &ld)) return 0; if (ld.count == 0) { cmdftp_war(CMDFTP_WAR_MASK, paths[0]); return 1; } if (ld.count == 1) { int st = remote_file(ld.data[0].fullname); if (st < 0) { free_list(&ld); return 0; } if (st == FILE_ISDIR && tt == FILE_NEXIST) { free(source_mask); source_mask = fullpath(paths[0], "*"); } } free_list(&ld); rv = d_aux(paths[1], source_mask, resume); free(source_mask); return rv;}int d_aux(char* target_dir, char* source_mask, int resume) { struct list_data ld; char* target[3]; int i, rv; if ((rv = local_file(target_dir)) == FILE_NEXIST) { if (!local_mkdir(target_dir)) return 0; } else if (rv != FILE_ISDIR) { return 0; } init_list(&ld); if (!remote_fetch_list(source_mask, &ld)) return 0; if (ld.count == 0) return 1; canonized_fn(target, target_dir); rv = 1; for (i = 0; i < ld.count; i++) { int file_type; if ((file_type = remote_file(ld.data[i].fullname)) < 0) { rv = 0; } else if (file_type == FILE_ISREG) { char* fn; FILE* f; fn = fullpath(target[2], ld.data[i].basename); if (!(f = fopen(fn, resume ? "ab" : "wb"))) cmdftp_war(CMDFTP_WAR_OPEN, fn); else { rv = download(f, ld.data[i].fullname); fclose(f); } free(fn); } else if (file_type == FILE_ISDIR) { char* tmp_src, *tmp_trg; tmp_src = fullpath(ld.data[i].fullname, "*"); tmp_trg = fullpath(target[2], ld.data[i].basename); rv = d_aux(tmp_trg, tmp_src, resume); free(tmp_trg); free(tmp_src); } else { cmdftp_war(CMDFTP_WAR_SKIP, ld.data[i].fullname); } if (!rv) break; } free_list(&ld); free_fn(target); return rv;}int download(FILE* target, char* source) { off_t start_pos, total_size; char* csource; char* op; size_t csource_len; int answer, port, rv; rv = 0; op = "Downloading"; csource = clean_fn(source); csource_len = strlen(csource); start_transfer: if (!send_command("TYPE I", 0)) return 0; if ((total_size = remote_size(source)) < 0) return 0; if ((start_pos = ftello(target)) == -1) return 0; if (start_pos > 0) { snprintf(cmd_buffer, CMD_BUF_SIZE, "REST " OFF_FMT, start_pos); if ((answer = send_command(cmd_buffer, 0)) != 350) { cmdftp_war(CMDFTP_WAR_REST, ""); fseeko(target, 0, SEEK_SET); start_pos = 0; } } if (!(port = getport())) return 0; if (!(cmdftp_data = cmdftp_connect(port))) return 0; snprintf(cmd_buffer, CMD_BUF_SIZE, "RETR %s", source); if (send_command(cmd_buffer, 0) != 150) { close(cmdftp_data); return 0; } if (!o.q) print_progress(op, csource, csource_len, start_pos, total_size); transfer_interrupted = TRAN_INTR_NO; while (start_pos < total_size) { ssize_t bytes; size_t toread, written; toread = ((total_size - start_pos) < o.b) ? total_size - start_pos : o.b; if ((bytes = my_raw_read(buffer, toread, cmdftp_data)) <= 0) break; if ((written = fwrite(buffer, 1, bytes, target)) != bytes) break; start_pos += bytes; if (!o.q) print_progress(op, csource, csource_len, start_pos, total_size); } if (!o.q) fputc('\n', stdout); close(cmdftp_data); if (start_pos < total_size) { if (ferror(target)) cmdftp_war(CMDFTP_WAR_WRIT, basename(source)); else if TRANSFER_INTERRUPTED_CHECK("data transfer", 1); else { cmdftp_err(CMDFTP_ERR_UNER, strerror(errno)); } } else { if (!recv_confirm()) cmdftp_war(CMDFTP_WAR_NOCT, ""); else rv = 1; } return rv;}/***********//* listing *//***********/int ls(struct list_data* d) { FILE* target; int pipe_fd[2]; int i, rv = 0; if (env[CMDFTP_ENV_PAGER]) { if (pipe(pipe_fd) < 0) return 0; if (!(target = fdopen(pipe_fd[1], "w"))) { close(pipe_fd[0]); close(pipe_fd[1]); return 0; } } else target = stdout; for (i = 0; i < d->count; i++) fprintf(target, "%s\n", d->data[i].fullname); if (!env[CMDFTP_ENV_PAGER]) return 1; fclose(target); rv = cmdftp_execute(env[CMDFTP_ENV_PAGER], 0, pipe_fd[0], -1); close(pipe_fd[0]); return rv;}/*****************************//* NETWORK RELATED FUNCTIONS *//*****************************/int cmdftp_connect(int port) { struct sockaddr_in address; int s, opvalue; socklen_t slen; opvalue = 8; slen = sizeof(opvalue); memset(&address, 0, sizeof(address)); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || setsockopt(s, IPPROTO_IP, IP_TOS, &opvalue, slen) < 0) return 0; address.sin_family = AF_INET; address.sin_port = htons((unsigned short)port); if (!server) if (!(server = gethostbyname(o.hostname))) return 0; memcpy(&address.sin_addr.s_addr, server->h_addr, server->h_length); if (connect(s, (struct sockaddr*) &address, sizeof(address)) == -1) return 0; return s;}void cmdftp_reconnect(void) { if (!(cmdftp_control = cmdftp_connect(o.p))) cmdftp_err(CMDFTP_ERR_CONN, ""); greeting(); if (!logging_in) { if (!login(user, pass)) cmdftp_err(CMDFTP_ERR_LGIN, ""); if (cwd[CMDFTP_LOCAL]) do_home(CMDFTP_LOCAL); if (cwd[CMDFTP_REMOTE]) do_home(CMDFTP_REMOTE); }}ssize_t my_raw_read(char* buf, size_t n, int sc) { ssize_t rv; rv = recv(sc, buf, n, 0); if (rv < 0) { if (transfer_interrupted != TRAN_INTR_INT) transfer_interrupted = TRAN_INTR_PIPE; } return rv;}ssize_t my_raw_write(char* buf, size_t n, int sc) { ssize_t rv; rv = send(sc, buf, n, 0); if (rv < 0) { if (transfer_interrupted != TRAN_INTR_INT) transfer_interrupted = TRAN_INTR_PIPE; } return rv;}int send_command(char* cmd, char suppress_err) { char* s; size_t len, rv = 0; s = my_malloc((len = strlen(cmd) + 2) + 1); sprintf(s, "%s\r\n", cmd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -