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

📄 psftp.c

📁 putty
💻 C
📖 第 1 页 / 共 5 页
字号:

    /*
     * In recursive mode, see if we're dealing with a directory.
     * (If we're not in recursive mode, we need not even check: the
     * subsequent fopen will return an error message.)
     */
    if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
	struct fxp_attrs attrs;
	int result;
	int nnames, namesize;
	char *name, **ournames;
	DirHandle *dh;
	int i;

	/*
	 * First, attempt to create the destination directory,
	 * unless it already exists.
	 */
	sftp_register(req = fxp_stat_send(outfname));
	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)) {
	    sftp_register(req = fxp_mkdir_send(outfname));
	    rreq = sftp_find_request(pktin = sftp_recv());
	    assert(rreq == req);
	    result = fxp_mkdir_recv(pktin, rreq);

	    if (!result) {
		printf("%s: create directory: %s\n",
		       outfname, fxp_error());
		return 0;
	    }
	}

	/*
	 * Now get the list of filenames in the local directory.
	 */
	nnames = namesize = 0;
	ournames = NULL;

	dh = open_directory(fname);
	if (!dh) {
	    printf("%s: unable to open directory\n", fname);
	    return 0;
	}
	while ((name = read_filename(dh)) != NULL) {
	    if (nnames >= namesize) {
		namesize += 128;
		ournames = sresize(ournames, namesize, char *);
	    }
	    ournames[nnames++] = name;
	}
	close_directory(dh);

	/*
	 * Sort the names into a clear order. This ought to make
	 * things more predictable when we're doing a reput of the
	 * same directory, just in case two readdirs on the same
	 * local directory return a different order.
	 */
	qsort(ournames, nnames, sizeof(*ournames), bare_name_compare);

	/*
	 * If we're in restart mode, find the last filename on this
	 * list that already exists. We may have to do a reput on
	 * _that_ file, but shouldn't have to do anything on the
	 * previous files.
	 *
	 * If none of them exists, of course, we start at 0.
	 */
	i = 0;
        if (restart) {
            while (i < nnames) {
                char *nextoutfname;
                nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
                sftp_register(req = fxp_stat_send(nextoutfname));
                rreq = sftp_find_request(pktin = sftp_recv());
                assert(rreq == req);
                result = fxp_stat_recv(pktin, rreq, &attrs);
                sfree(nextoutfname);
                if (!result)
                    break;
                i++;
            }
            if (i > 0)
                i--;
        }

        /*
         * Now we're ready to recurse. Starting at ournames[i]
	 * and continuing on to the end of the list, we
	 * construct a new source and target file name, and
	 * call sftp_put_file again.
	 */
	for (; i < nnames; i++) {
	    char *nextfname, *nextoutfname;
	    int ret;

	    if (fname)
		nextfname = dir_file_cat(fname, ournames[i]);
	    else
		nextfname = dupstr(ournames[i]);
	    nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
	    ret = sftp_put_file(nextfname, nextoutfname, recurse, restart);
	    restart = FALSE;	       /* after first partial file, do full */
	    sfree(nextoutfname);
	    sfree(nextfname);
	    if (!ret) {
		for (i = 0; i < nnames; i++) {
		    sfree(ournames[i]);
		}
		sfree(ournames);
		return 0;
	    }
	}

	/*
	 * Done this recursion level. Free everything.
	 */
	for (i = 0; i < nnames; i++) {
	    sfree(ournames[i]);
	}
	sfree(ournames);

	return 1;
    }

    file = open_existing_file(fname, NULL, NULL, NULL);
    if (!file) {
	printf("local: unable to open %s\n", fname);
	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: open for write: %s\n", outfname, fxp_error());
	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());
	    return 0;
	}
	if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) {
	    printf("read size of %s: size was not given\n", outfname);
	    return 0;
	}
	offset = attrs.size;
	uint64_decimal(offset, decbuf);
	printf("reput: restarting at file position %s\n", decbuf);

	if (seek_file((WFile *)file, offset, FROM_START) != 0)
	    seek_file((WFile *)file, uint64_make(0,0), FROM_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 = read_from_file(file, buffer, sizeof(buffer));
	    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);

    close_rfile(file);

    return ret;
}

/* ----------------------------------------------------------------------
 * A remote wildcard matcher, providing a similar interface to the
 * local one in psftp.h.
 */

typedef struct SftpWildcardMatcher {
    struct fxp_handle *dirh;
    struct fxp_names *names;
    int namepos;
    char *wildcard, *prefix;
} SftpWildcardMatcher;

SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name)
{
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    char *wildcard;
    char *unwcdir, *tmpdir, *cdir;
    int len, check;
    SftpWildcardMatcher *swcm;
    struct fxp_handle *dirh;

    /*
     * We don't handle multi-level wildcards; so we expect to find
     * a fully specified directory part, followed by a wildcard
     * after that.
     */
    wildcard = stripslashes(name, 0);

    unwcdir = dupstr(name);
    len = wildcard - name;
    unwcdir[len] = '\0';
    if (len > 0 && unwcdir[len-1] == '/')
	unwcdir[len-1] = '\0';
    tmpdir = snewn(1 + len, char);
    check = wc_unescape(tmpdir, unwcdir);
    sfree(tmpdir);

    if (!check) {
	printf("Multiple-level wildcards are not supported\n");
	sfree(unwcdir);
	return NULL;
    }

    cdir = canonify(unwcdir);

    sftp_register(req = fxp_opendir_send(cdir));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    dirh = fxp_opendir_recv(pktin, rreq);

    if (dirh) {
	swcm = snew(SftpWildcardMatcher);
	swcm->dirh = dirh;
	swcm->names = NULL;
	swcm->wildcard = dupstr(wildcard);
	swcm->prefix = unwcdir;
    } else {
	printf("Unable to open %s: %s\n", cdir, fxp_error());
	swcm = NULL;
	sfree(unwcdir);
    }

    sfree(cdir);

    return swcm;
}

char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm)
{
    struct fxp_name *name;
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;

    while (1) {
	if (swcm->names && swcm->namepos >= swcm->names->nnames) {
	    fxp_free_names(swcm->names);
	    swcm->names = NULL;
	}

	if (!swcm->names) {
	    sftp_register(req = fxp_readdir_send(swcm->dirh));
	    rreq = sftp_find_request(pktin = sftp_recv());
	    assert(rreq == req);
	    swcm->names = fxp_readdir_recv(pktin, rreq);

	    if (!swcm->names) {
		if (fxp_error_type() != SSH_FX_EOF)
		    printf("%s: reading directory: %s\n", swcm->prefix,
			   fxp_error());
		return NULL;
	    }

	    swcm->namepos = 0;
	}

	assert(swcm->names && swcm->namepos < swcm->names->nnames);

	name = &swcm->names->names[swcm->namepos++];

	if (!strcmp(name->filename, ".") || !strcmp(name->filename, ".."))
	    continue;		       /* expected bad filenames */

	if (!vet_filename(name->filename)) {
	    printf("ignoring potentially dangerous server-"
		   "supplied filename '%s'\n", name->filename);
	    continue;		       /* unexpected bad filename */
	}

	if (!wc_match(swcm->wildcard, name->filename))
	    continue;		       /* doesn't match the wildcard */

	/*
	 * We have a working filename. Return it.
	 */
	return dupprintf("%s%s%s", swcm->prefix,
			 (!swcm->prefix[0] ||
			  swcm->prefix[strlen(swcm->prefix)-1]=='/' ?
			  "" : "/"),
			 name->filename);
    }
}

void sftp_finish_wildcard_matching(SftpWildcardMatcher *swcm)
{
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;

    sftp_register(req = fxp_close_send(swcm->dirh));
    rreq = sftp_find_request(pktin = sftp_recv());
    assert(rreq == req);
    fxp_close_recv(pktin, rreq);

    if (swcm->names)
	fxp_free_names(swcm->names);

    sfree(swcm->prefix);
    sfree(swcm->wildcard);

    sfree(swcm);
}

/*
 * General function to match a potential wildcard in a filename
 * argument and iterate over every matching file. Used in several
 * PSFTP commands (rmdir, rm, chmod, mv).
 */
int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx)
{
    char *unwcfname, *newname, *cname;
    int is_wc, ret;

    unwcfname = snewn(strlen(filename)+1, char);
    is_wc = !wc_unescape(unwcfname, filename);

    if (is_wc) {
	SftpWildcardMatcher *swcm = sftp_begin_wildcard_matching(filename);
	int matched = FALSE;
	sfree(unwcfname);

	if (!swcm)
	    return 0;

	ret = 1;

	while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) {
	    cname = canonify(newname);
	    if (!cname) {
		printf("%s: canonify: %s\n", newname, fxp_error());
		ret = 0;
	    }
	    matched = TRUE;
	    ret &= func(ctx, cname);
	    sfree(cname);
	}

	if (!matched) {
	    /* Politely warn the user that nothing matched. */
	    printf("%s: nothing matched\n", filename);
	}

	sftp_finish_wildcard_matching(swcm);
    } else {
	cname = canonify(unwcfname);
	if (!cname) {
	    printf("%s: canonify: %s\n", filename, fxp_error());
	    ret = 0;
	}
	ret = func(ctx, cname);
	sfree(cname);
	sfree(unwcfname);
    }

    return ret;
}

/*
 * Handy helper function.
 */
int is_wildcard(char *name)
{
    char *unwcfname = snewn(strlen(name)+1, char);
    int is_wc = !wc_unescape(unwcfname, name);
    sfree(unwcfname);
    return is_wc;
}

/* ----------------------------------------------------------------------
 * Actual sftp commands.
 */
struct sftp_command {
    char **words;
    int nwords, wordssize;
    int (*obey) (struct sftp_command *);	/* returns <0 to quit */
};

int sftp_cmd_null(struct sftp_command *cmd)
{
    return 1;			       /* success */
}

int sftp_cmd_unknown(struct sftp_command *cmd)
{
    printf("psftp: unknown command \"%s\"\n", cmd->words[0]);
    return 0;			       /* failure */
}

int sftp_cmd_quit(struct sftp_command *cmd)
{
    return -1;
}

int sftp_cmd_close(struct sftp_command *cmd)
{
    if (back == NULL) {
	not_connected();
	return 0;
    }

    if (back != NULL && back->connected(backhandle)) {
	char ch;
	back->special(backhandle, TS_EOF);
	sftp_recvdata(&ch, 1);
    }
    do_sftp_cleanup();

    return 0;
}

/*
 * List a directory. If no arguments are given, list pwd; otherwise
 * list the directory given in words[1].
 */
int sftp_cmd_ls(struct sftp_command *cmd)
{
    struct fxp_handle *dirh;
    struct fxp_names *names;
    struct fxp_name **ournames;
    int nnames, namesize;
    char *dir, *cdir, *unwcdir, *wildcard;
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    int i;

    if (back == NULL) {
	not_connected();
	return 0;
    }

    if (cmd->nwords < 2)
	dir = ".";
    else
	dir = cmd->words[1];

⌨️ 快捷键说明

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