📄 psftp.c
字号:
fname = cmd->words[1]; origoutfname = (cmd->nwords == 2 ? stripslashes(cmd->words[1], 1) : cmd->words[2]); outfname = canonify(origoutfname); if (!outfname) { printf("%s: %s\n", origoutfname, fxp_error()); return 0; } fp = fopen(fname, "rb"); if (!fp) { printf("local: unable to open %s\n", fname); sfree(outfname); return 0; } if (restart) { sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE)); } else { sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC)); } rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fh = fxp_open_recv(pktin, rreq); if (!fh) { printf("%s: %s\n", outfname, fxp_error()); sfree(outfname); return 0; } if (restart) { char decbuf[30]; struct fxp_attrs attrs; int ret; sftp_register(req = fxp_fstat_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_fstat_recv(pktin, rreq, &attrs); if (!ret) { printf("read size of %s: %s\n", outfname, fxp_error()); sfree(outfname); return 0; } if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) { printf("read size of %s: size was not given\n", outfname); sfree(outfname); return 0; } offset = attrs.size; uint64_decimal(offset, decbuf); printf("reput: restarting at file position %s\n", decbuf); if (uint64_compare(offset, uint64_make(0, LONG_MAX)) > 0) { printf("reput: remote file is larger than we can deal with\n"); sfree(outfname); return 0; } if (fseek(fp, offset.lo, SEEK_SET) != 0) fseek(fp, 0, SEEK_END); /* *shrug* */ } else { offset = uint64_make(0, 0); } printf("local:%s => remote:%s\n", fname, outfname); /* * FIXME: we can use FXP_FSTAT here to get the file size, and * thus put up a progress bar. */ ret = 1; xfer = xfer_upload_init(fh, offset); err = eof = 0; while ((!err && !eof) || !xfer_done(xfer)) { char buffer[4096]; int len, ret; while (xfer_upload_ready(xfer) && !err && !eof) { len = fread(buffer, 1, sizeof(buffer), fp); if (len == -1) { printf("error while reading local file\n"); err = 1; } else if (len == 0) { eof = 1; } else { xfer_upload_data(xfer, buffer, len); } } if (!xfer_done(xfer)) { pktin = sftp_recv(); ret = xfer_upload_gotpkt(xfer, pktin); if (!ret) { printf("error while writing: %s\n", fxp_error()); err = 1; } } } xfer_cleanup(xfer); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); fclose(fp); sfree(outfname); return ret;}int sftp_cmd_put(struct sftp_command *cmd){ return sftp_general_put(cmd, 0);}int sftp_cmd_reput(struct sftp_command *cmd){ return sftp_general_put(cmd, 1);}int sftp_cmd_mkdir(struct sftp_command *cmd){ char *dir; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); return 0; } if (cmd->nwords < 2) { printf("mkdir: expects a directory\n"); return 0; } dir = canonify(cmd->words[1]); if (!dir) { printf("%s: %s\n", dir, fxp_error()); return 0; } sftp_register(req = fxp_mkdir_send(dir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_mkdir_recv(pktin, rreq); if (!result) { printf("mkdir %s: %s\n", dir, fxp_error()); sfree(dir); return 0; } sfree(dir); return 1;}int sftp_cmd_rmdir(struct sftp_command *cmd){ char *dir; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); return 0; } if (cmd->nwords < 2) { printf("rmdir: expects a directory\n"); return 0; } dir = canonify(cmd->words[1]); if (!dir) { printf("%s: %s\n", dir, fxp_error()); return 0; } sftp_register(req = fxp_rmdir_send(dir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_rmdir_recv(pktin, rreq); if (!result) { printf("rmdir %s: %s\n", dir, fxp_error()); sfree(dir); return 0; } sfree(dir); return 1;}int sftp_cmd_rm(struct sftp_command *cmd){ char *fname; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); return 0; } if (cmd->nwords < 2) { printf("rm: expects a filename\n"); return 0; } fname = canonify(cmd->words[1]); if (!fname) { printf("%s: %s\n", fname, fxp_error()); return 0; } sftp_register(req = fxp_remove_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_remove_recv(pktin, rreq); if (!result) { printf("rm %s: %s\n", fname, fxp_error()); sfree(fname); return 0; } sfree(fname); return 1;}int sftp_cmd_mv(struct sftp_command *cmd){ char *srcfname, *dstfname; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); return 0; } if (cmd->nwords < 3) { printf("mv: expects two filenames\n"); return 0; } srcfname = canonify(cmd->words[1]); if (!srcfname) { printf("%s: %s\n", srcfname, fxp_error()); return 0; } dstfname = canonify(cmd->words[2]); if (!dstfname) { printf("%s: %s\n", dstfname, fxp_error()); return 0; } sftp_register(req = fxp_rename_send(srcfname, dstfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_rename_recv(pktin, rreq); if (!result) { char const *error = fxp_error(); struct fxp_attrs attrs; /* * The move might have failed because dstfname pointed at a * directory. We check this possibility now: if dstfname * _is_ a directory, we re-attempt the move by appending * the basename of srcfname to dstfname. */ sftp_register(req = fxp_stat_send(dstfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (result && (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && (attrs.permissions & 0040000)) { char *p; char *newname, *newcanon; printf("(destination %s is a directory)\n", dstfname); p = srcfname + strlen(srcfname); while (p > srcfname && p[-1] != '/') p--; newname = dupcat(dstfname, "/", p, NULL); newcanon = canonify(newname); sfree(newname); if (newcanon) { sfree(dstfname); dstfname = newcanon; sftp_register(req = fxp_rename_send(srcfname, dstfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_rename_recv(pktin, rreq); error = result ? NULL : fxp_error(); } } if (error) { printf("mv %s %s: %s\n", srcfname, dstfname, error); sfree(srcfname); sfree(dstfname); return 0; } } printf("%s -> %s\n", srcfname, dstfname); sfree(srcfname); sfree(dstfname); return 1;}int sftp_cmd_chmod(struct sftp_command *cmd){ char *fname, *mode; int result; struct fxp_attrs attrs; unsigned attrs_clr, attrs_xor, oldperms, newperms; struct sftp_packet *pktin; struct sftp_request *req, *rreq; if (back == NULL) { printf("psftp: not connected to a host; use \"open host.name\"\n"); return 0; } if (cmd->nwords < 3) { printf("chmod: expects a mode specifier and a filename\n"); return 0; } /* * Attempt to parse the mode specifier in cmd->words[1]. We * don't support the full horror of Unix chmod; instead we * support a much simpler syntax in which the user can either * specify an octal number, or a comma-separated sequence of * [ugoa]*[-+=][rwxst]+. (The initial [ugoa] sequence may * _only_ be omitted if the only attribute mentioned is t, * since all others require a user/group/other specification. * Additionally, the s attribute may not be specified for any * [ugoa] specifications other than exactly u or exactly g. */ attrs_clr = attrs_xor = 0; mode = cmd->words[1]; if (mode[0] >= '0' && mode[0] <= '9') { if (mode[strspn(mode, "01234567")]) { printf("chmod: numeric file modes should" " contain digits 0-7 only\n"); return 0; } attrs_clr = 07777; sscanf(mode, "%o", &attrs_xor); attrs_xor &= attrs_clr; } else { while (*mode) { char *modebegin = mode; unsigned subset, perms; int action; subset = 0; while (*mode && *mode != ',' && *mode != '+' && *mode != '-' && *mode != '=') { switch (*mode) { case 'u': subset |= 04700; break; /* setuid, user perms */ case 'g': subset |= 02070; break; /* setgid, group perms */ case 'o': subset |= 00007; break; /* just other perms */ case 'a': subset |= 06777; break; /* all of the above */ default: printf("chmod: file mode '%.*s' contains unrecognised" " user/group/other specifier '%c'\n", (int)strcspn(modebegin, ","), modebegin, *mode); return 0; } mode++; } if (!*mode || *mode == ',') { printf("chmod: file mode '%.*s' is incomplete\n", (int)strcspn(modebegin, ","), modebegin); return 0; } action = *mode++; if (!*mode || *mode == ',') { printf("chmod: file mode '%.*s' is incomplete\n", (int)strcspn(modebegin, ","), modebegin); return 0; } perms = 0; while (*mode && *mode != ',') { switch (*mode) { case 'r': perms |= 00444; break; case 'w': perms |= 00222; break; case 'x': perms |= 00111; break; case 't': perms |= 01000; subset |= 01000; break; case 's': if ((subset & 06777) != 04700 && (subset & 06777) != 02070) { printf("chmod: file mode '%.*s': set[ug]id bit should" " be used with exactly one of u or g only\n", (int)strcspn(modebegin, ","), modebegin); return 0; } perms |= 06000; break; default: printf("chmod: file mode '%.*s' contains unrecognised" " permission specifier '%c'\n", (int)strcspn(modebegin, ","), modebegin, *mode); return 0; } mode++; } if (!(subset & 06777) && (perms &~ subset)) { printf("chmod: file mode '%.*s' contains no user/group/other" " specifier and permissions other than 't' \n", (int)strcspn(modebegin, ","), modebegin); return 0; } perms &= subset; switch (action) { case '+': attrs_clr |= perms; attrs_xor |= perms; break; case '-': attrs_clr |= perms; attrs_xor &= ~perms; break; case '=': attrs_clr |= subset; attrs_xor |= perms; break; } if (*mode) mode++; /* eat comma */ } } fname = canonify(cmd->words[2]); if (!fname) { printf("%s: %s\n", fname, fxp_error()); return 0; } sftp_register(req = fxp_stat_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { printf("get attrs for %s: %s\n", fname, result ? "file permissions not provided" : fxp_error()); sfree(fname); return 0; } attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS; /* perms _only_ */ oldperms = attrs.permissions & 07777; attrs.permissions &= ~attrs_clr; attrs.permissions ^= attrs_xor; newperms = attrs.permissions & 07777; sftp_register(req = fxp_setstat_send(fname, attrs)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_setstat_recv(pktin, rreq); if (!result) { printf("set attrs for %s: %s\n", fname, fxp_error()); sfree(fname); return 0; } printf("%s: %04o -> %04o\n", fname, oldperms, newperms); sfree(fname); return 1;}static int sftp_cmd_open(struct sftp_command *cmd){ int portnumber; if (back != NULL) { printf("psftp: already connected\n"); return 0; } if (cmd->nwords < 2) { printf("open: expects a host name\n"); return 0; } if (cmd->nwords > 2) { portnumber = atoi(cmd->words[2]); if (portnumber == 0) { printf("open: invalid port number\n"); return 0; } } else portnumber = 0; if (psftp_connect(cmd->words[1], NULL, portnumber)) { back = NULL; /* connection is already closed */ return -1; /* this is fatal */ } do_sftp_init(); return 1;}static int sftp_cmd_lcd(struct sftp_command *cmd){ char *currdir, *errmsg; if (cmd->nwords < 2) { printf("lcd: expects a local directory name\n"); return 0; } errmsg = psftp_lcd(cmd->words[1]); if (errmsg) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -