⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pscp.c

📁 putty
💻 C
📖 第 1 页 / 共 4 页
字号:
		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++) {
		    if (!strcmp(names->names[i].filename, ".") ||
			!strcmp(names->names[i].filename, "..")) {
			/*
			 * . and .. are normal consequences of
			 * reading a directory, and aren't worth
			 * complaining about.
			 */
		    } else if (!vet_filename(names->names[i].filename)) {
			tell_user(stderr, "ignoring potentially dangerous server-"
				  "supplied filename '%s'\n",
				  names->names[i].filename);
		    } else
			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 = uint64_make(0,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) {
		act->size = attrs.size;
	    } else
		act->size = uint64_make(ULONG_MAX,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.
	 */
	{
	    char sizestr[40];
	
	    if (sscanf(act->buf, "%o %s %n", &act->mode, sizestr, &i) != 2)
		bump("Protocol error: Illegal file descriptor format");
	    act->size = uint64_from_decimal(sizestr);
	    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)
{
    uint64 size;
    unsigned long mtime, atime;
    char *last;
    RFile *f;
    int attr;
    uint64 i;
    uint64 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) {
	char sizestr[40];
	uint64_decimal(size, sizestr);
	tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
    }
    if (scp_send_filename(last, size, 0644))
	return;

    stat_bytes = uint64_make(0,0);
    stat_starttime = time(NULL);
    stat_lasttime = 0;

    for (i = uint64_make(0,0);
	 uint64_compare(i,size) < 0;
	 i = uint64_add32(i,4096)) {
	char transbuf[4096];
	int j, k = 4096;

	if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */ 
	    k = (uint64_subtract(size, i)).lo; 	/* 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 = uint64_add32(stat_bytes, k);
	    if (time(NULL) != stat_lasttime ||
		(uint64_compare(uint64_add32(i, k), size) == 0)) {
		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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -