📄 scp.c
字号:
fname = scp_sftp_remotepath; must_free_fname = 0; scp_sftp_donethistarget = 1; } else { /* * Even simpler case: one file _which we've done_. * Return 1 (finished). */ return 1; } } else { /* * We're now in the middle of stepping through a list * of names returned from fxp_readdir(); so let's carry * on. */ struct scp_sftp_dirstack *head = scp_sftp_dirstack_head; while (head->namepos < head->namelen && (is_dots(head->names[head->namepos].filename) || (head->wildcard && !wc_match(head->wildcard, head->names[head->namepos].filename)))) head->namepos++; /* skip . and .. */ if (head->namepos < head->namelen) { head->matched_something = 1; fname = dupcat(head->dirpath, "/", head->names[head->namepos++].filename, NULL); must_free_fname = 1; } else { /* * We've come to the end of the list; pop it off * the stack and return an ENDDIR action (or RETRY * if this was a wildcard match). */ if (head->wildcard) { act->action = SCP_SINK_RETRY; if (!head->matched_something) { tell_user(stderr, "pscp: wildcard '%s' matched " "no files", head->wildcard); errs++; } sfree(head->wildcard); } else { act->action = SCP_SINK_ENDDIR; } sfree(head->dirpath); sfree(head->names); scp_sftp_dirstack_head = head->next; sfree(head); return 0; } } /* * Now we have a filename. Stat it, and see if it's a file * or a directory. */ sftp_register(req = fxp_stat_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_stat_recv(pktin, rreq, &attrs); if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { tell_user(stderr, "unable to identify %s: %s", fname, ret ? "file type not supplied" : fxp_error()); errs++; return 1; } if (attrs.permissions & 0040000) { struct scp_sftp_dirstack *newitem; struct fxp_handle *dirhandle; int nnames, namesize; struct fxp_name *ournames; struct fxp_names *names; /* * It's a directory. If we're not in recursive mode, * this merits a complaint (which is fatal if the name * was specified directly, but not if it was matched by * a wildcard). * * We skip this complaint completely if * scp_sftp_wildcard is set, because that's an * indication that we're not actually supposed to * _recursively_ transfer the dir, just scan it for * things matching the wildcard. */ if (!scp_sftp_recursive && !scp_sftp_wildcard) { tell_user(stderr, "pscp: %s: is a directory", fname); errs++; if (must_free_fname) sfree(fname); if (scp_sftp_dirstack_head) { act->action = SCP_SINK_RETRY; return 0; } else { return 1; } } /* * Otherwise, the fun begins. We must fxp_opendir() the * directory, slurp the filenames into memory, return * SCP_SINK_DIR (unless this is a wildcard match), and * set targetisdir. The next time we're called, we will * run through the list of filenames one by one, * matching them against a wildcard if present. * * If targetisdir is _already_ set (meaning we're * already in the middle of going through another such * list), we must push the other (target,namelist) pair * on a stack. */ sftp_register(req = fxp_opendir_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirhandle = fxp_opendir_recv(pktin, rreq); if (!dirhandle) { tell_user(stderr, "scp: unable to open directory %s: %s", fname, fxp_error()); if (must_free_fname) sfree(fname); errs++; return 1; } nnames = namesize = 0; ournames = NULL; while (1) { int i; sftp_register(req = fxp_readdir_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); names = fxp_readdir_recv(pktin, rreq); if (names == NULL) { if (fxp_error_type() == SSH_FX_EOF) break; tell_user(stderr, "scp: reading directory %s: %s\n", fname, fxp_error()); if (must_free_fname) sfree(fname); sfree(ournames); errs++; return 1; } if (names->nnames == 0) { fxp_free_names(names); break; } if (nnames + names->nnames >= namesize) { namesize += names->nnames + 128; ournames = sresize(ournames, namesize, struct fxp_name); } for (i = 0; i < names->nnames; i++) ournames[nnames++] = names->names[i]; names->nnames = 0; /* prevent free_names */ fxp_free_names(names); } sftp_register(req = fxp_close_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); newitem = snew(struct scp_sftp_dirstack); newitem->next = scp_sftp_dirstack_head; newitem->names = ournames; newitem->namepos = 0; newitem->namelen = nnames; if (must_free_fname) newitem->dirpath = fname; else newitem->dirpath = dupstr(fname); if (scp_sftp_wildcard) { newitem->wildcard = scp_sftp_wildcard; newitem->matched_something = 0; scp_sftp_wildcard = NULL; } else { newitem->wildcard = NULL; } scp_sftp_dirstack_head = newitem; if (newitem->wildcard) { act->action = SCP_SINK_RETRY; } else { act->action = SCP_SINK_DIR; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; act->size = 0; /* duhh, it's a directory */ act->mode = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; act->settime = 1; } else act->settime = 0; } return 0; } else { /* * It's a file. Return SCP_SINK_FILE. */ act->action = SCP_SINK_FILE; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { if (uint64_compare(attrs.size, uint64_make(0, ULONG_MAX)) > 0) { act->size = ULONG_MAX; /* *boggle* */ } else act->size = attrs.size.lo; } else act->size = ULONG_MAX; /* no idea */ act->mode = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; act->settime = 1; } else act->settime = 0; if (must_free_fname) scp_sftp_currentname = fname; else scp_sftp_currentname = dupstr(fname); return 0; } } else { int done = 0; int i, bufsize; int action; char ch; act->settime = 0; act->buf = NULL; bufsize = 0; while (!done) { if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0) return 1; if (ch == '\n') bump("Protocol error: Unexpected newline"); i = 0; action = ch; do { if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0) bump("Lost connection"); if (i >= bufsize) { bufsize = i + 128; act->buf = sresize(act->buf, bufsize, char); } act->buf[i++] = ch; } while (ch != '\n'); act->buf[i - 1] = '\0'; switch (action) { case '\01': /* error */ tell_user(stderr, "%s\n", act->buf); errs++; continue; /* go round again */ case '\02': /* fatal error */ bump("%s", act->buf); case 'E': back->send(backhandle, "", 1); act->action = SCP_SINK_ENDDIR; return 0; case 'T': if (sscanf(act->buf, "%ld %*d %ld %*d", &act->mtime, &act->atime) == 2) { act->settime = 1; back->send(backhandle, "", 1); continue; /* go round again */ } bump("Protocol error: Illegal time format"); case 'C': case 'D': act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR); break; default: bump("Protocol error: Expected control record"); } /* * We will go round this loop only once, unless we hit * `continue' above. */ done = 1; } /* * If we get here, we must have seen SCP_SINK_FILE or * SCP_SINK_DIR. */ if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2) bump("Protocol error: Illegal file descriptor format"); act->name = act->buf + i; return 0; }}int scp_accept_filexfer(void){ if (using_sftp) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); scp_sftp_filehandle = fxp_open_recv(pktin, rreq); if (!scp_sftp_filehandle) { tell_user(stderr, "pscp: unable to open %s: %s", scp_sftp_currentname, fxp_error()); errs++; return 1; } scp_sftp_fileoffset = uint64_make(0, 0); scp_sftp_xfer = xfer_download_init(scp_sftp_filehandle, scp_sftp_fileoffset); sfree(scp_sftp_currentname); return 0; } else { back->send(backhandle, "", 1); return 0; /* can't fail */ }}int scp_recv_filedata(char *data, int len){ if (using_sftp) { struct sftp_packet *pktin; int ret, actuallen; void *vbuf; xfer_download_queue(scp_sftp_xfer); pktin = sftp_recv(); ret = xfer_download_gotpkt(scp_sftp_xfer, pktin); if (ret < 0) { tell_user(stderr, "pscp: error while reading: %s", fxp_error()); errs++; return -1; } if (xfer_download_data(scp_sftp_xfer, &vbuf, &actuallen)) { /* * This assertion relies on the fact that the natural * block size used in the xfer manager is at most that * used in this module. I don't like crossing layers in * this way, but it'll do for now. */ assert(actuallen <= len); memcpy(data, vbuf, actuallen); sfree(vbuf); } else actuallen = 0; scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen); return actuallen; } else { return ssh_scp_recv((unsigned char *) data, len); }}int scp_finish_filerecv(void){ if (using_sftp) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; /* * Ensure that xfer_done() will work correctly, so we can * clean up any outstanding requests from the file * transfer. */ xfer_set_error(scp_sftp_xfer); while (!xfer_done(scp_sftp_xfer)) { void *vbuf; int len; pktin = sftp_recv(); xfer_download_gotpkt(scp_sftp_xfer, pktin); if (xfer_download_data(scp_sftp_xfer, &vbuf, &len)) sfree(vbuf); } xfer_cleanup(scp_sftp_xfer); sftp_register(req = fxp_close_send(scp_sftp_filehandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); return 0; } else { back->send(backhandle, "", 1); return response(); }}/* ---------------------------------------------------------------------- * Send an error message to the other side and to the screen. * Increment error counter. */static void run_err(const char *fmt, ...){ char *str, *str2; va_list ap; va_start(ap, fmt); errs++; str = dupvprintf(fmt, ap); str2 = dupcat("scp: ", str, "\n", NULL); sfree(str); scp_send_errmsg(str2); tell_user(stderr, "%s", str2); va_end(ap); sfree(str2);}/* * Execute the source part of the SCP protocol. */static void source(char *src){ unsigned long size; unsigned long mtime, atime; char *last; RFile *f; int attr; unsigned long i; unsigned long stat_bytes; time_t stat_starttime, stat_lasttime; attr = file_type(src); if (attr == FILE_TYPE_NONEXISTENT || attr == FILE_TYPE_WEIRD) { run_err("%s: %s file or directory", src, (attr == FILE_TYPE_WEIRD ? "Not a" : "No such")); return; } if (attr == FILE_TYPE_DIRECTORY) { if (recursive) { /* * Avoid . and .. directories. */ char *p; p = strrchr(src, '/'); if (!p) p = strrchr(src, '\\'); if (!p) p = src; else p++; if (!strcmp(p, ".") || !strcmp(p, "..")) /* skip . and .. */ ; else rsource(src); } else { run_err("%s: not a regular file", src); } return; } if ((last = strrchr(src, '/')) == NULL) last = src; else last++; if (strrchr(last, '\\') != NULL) last = strrchr(last, '\\') + 1; if (last == src && strchr(src, ':') != NULL) last = strchr(src, ':') + 1; f = open_existing_file(src, &size, &mtime, &atime); if (f == NULL) { run_err("%s: Cannot open file", src); return; } if (preserve) { if (scp_send_filetimes(mtime, atime)) return; } if (verbose) tell_user(stderr, "Sending file %s, size=%lu", last, size); if (scp_send_filename(last, size, 0644)) return; stat_bytes = 0; stat_starttime = time(NULL); stat_lasttime = 0; for (i = 0; i < size; i += 4096) { char transbuf[4096]; int j, k = 4096; if (i + k > size) k = size - i; if ((j = read_from_file(f, transbuf, k)) != k) { if (statistics) printf("\n"); bump("%s: Read error", src); } if (scp_send_filedata(transbuf, k)) bump("%s: Network error occurred", src); if (statistics) { stat_bytes += k; if (time(NULL) != stat_lasttime || i + k == size) { stat_lasttime = time(NULL); print_stats(last, size, stat_bytes, stat_starttime, stat_lasttime); } } } close_rfile(f); (void) scp_send_finish();}/* * Recursively send the contents of a directory. */static void rsource(char *src){ char *last; char *save_target; DirHandle *dir; if ((last = strrchr(src, '/')) == NULL) last = src; else last++; if (strrchr(last, '\\') != NULL) last = strrchr(last, '\\') + 1; if (last == src && strchr(src, ':') != NULL) last = strchr(src, ':') + 1; /* maybe send filetime */ save_target = scp_save_remotepath(); if (verbose) tell_user(stderr, "Entering directory: %s", last); if (scp_send_dirname(last, 0755)) return; dir = open_directory(src); if (dir != NULL) { char *filename; while ((filename = read_filename(dir)) != NULL) { char *foundfile = dupcat(src, "/", filename, NULL); source(foundfile); sfree(foundfile); sfree(filename); } } close_directory(dir); (void) scp_send_enddir(); scp_restore_remotepath(save_target);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -