mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-23 15:09:24 -05:00
Implement mget and mput in PSFTP, supporting wildcards.
[originally from svn r4991] [this svn revision also touched putty-wishlist]
This commit is contained in:
parent
bee5812a49
commit
a4fe439184
@ -291,6 +291,26 @@ have to use the \c{--} special argument, which stops \c{put} from
|
|||||||
interpreting anything as a switch after it. For example, \cq{put --
|
interpreting anything as a switch after it. For example, \cq{put --
|
||||||
-silly-name-}.)
|
-silly-name-}.)
|
||||||
|
|
||||||
|
\S{psftp-cmd-mgetput} The \c{mget} and \c{mput} commands: fetch or
|
||||||
|
send multiple files
|
||||||
|
|
||||||
|
\c{mget} works almost exactly like \c{get}, except that it allows
|
||||||
|
you to specify more than one file to fetch at once. You can do this
|
||||||
|
in two ways:
|
||||||
|
|
||||||
|
\b by giving two or more explicit file names (\cq{mget file1.txt
|
||||||
|
file2.txt})
|
||||||
|
|
||||||
|
\b by using a wildcard (\cq{mget *.txt}).
|
||||||
|
|
||||||
|
Every argument to \c{mget} is treated as the name of a file to fetch
|
||||||
|
(unlike \c{get}, which will interpret at most one argument like
|
||||||
|
that, and a second argument will be treated as an alternative name
|
||||||
|
under which to store the retrieved file), or a wildcard expression
|
||||||
|
matching more than one file.
|
||||||
|
|
||||||
|
\c{mput} is similar to \c{put}, with the same differences.
|
||||||
|
|
||||||
\S{psftp-cmd-regetput} The \c{reget} and \c{reput} commands:
|
\S{psftp-cmd-regetput} The \c{reget} and \c{reput} commands:
|
||||||
resuming file transfers
|
resuming file transfers
|
||||||
|
|
||||||
|
195
psftp.c
195
psftp.c
@ -200,7 +200,8 @@ static int bare_name_compare(const void *av, const void *bv)
|
|||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* The meat of the `get' and `put' commands.
|
* The meat of the `get' and `put' commands.
|
||||||
*/
|
*/
|
||||||
int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
int sftp_get_file(char *fname, char *outfname, int recurse, int restart,
|
||||||
|
char *wildcard)
|
||||||
{
|
{
|
||||||
struct fxp_handle *fh;
|
struct fxp_handle *fh;
|
||||||
struct sftp_packet *pktin;
|
struct sftp_packet *pktin;
|
||||||
@ -215,17 +216,22 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
* (If we're not in recursive mode, we need not even check: the
|
* (If we're not in recursive mode, we need not even check: the
|
||||||
* subsequent FXP_OPEN will return a usable error message.)
|
* subsequent FXP_OPEN will return a usable error message.)
|
||||||
*/
|
*/
|
||||||
if (recurse) {
|
if (wildcard || recurse) {
|
||||||
struct fxp_attrs attrs;
|
struct fxp_attrs attrs;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
if (!wildcard) {
|
||||||
sftp_register(req = fxp_stat_send(fname));
|
sftp_register(req = fxp_stat_send(fname));
|
||||||
rreq = sftp_find_request(pktin = sftp_recv());
|
rreq = sftp_find_request(pktin = sftp_recv());
|
||||||
assert(rreq == req);
|
assert(rreq == req);
|
||||||
result = fxp_stat_recv(pktin, rreq, &attrs);
|
result = fxp_stat_recv(pktin, rreq, &attrs);
|
||||||
if (result &&
|
} else
|
||||||
|
result = 0; /* placate optimisers */
|
||||||
|
|
||||||
|
if (wildcard ||
|
||||||
|
(result &&
|
||||||
(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
|
(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
|
||||||
(attrs.permissions & 0040000)) {
|
(attrs.permissions & 0040000))) {
|
||||||
|
|
||||||
struct fxp_handle *dirhandle;
|
struct fxp_handle *dirhandle;
|
||||||
int nnames, namesize;
|
int nnames, namesize;
|
||||||
@ -235,9 +241,11 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* First, attempt to create the destination directory,
|
* First, attempt to create the destination directory,
|
||||||
* unless it already exists.
|
* unless it already exists (or this is a wildcard
|
||||||
|
* run).
|
||||||
*/
|
*/
|
||||||
if (file_type(outfname) != FILE_TYPE_DIRECTORY &&
|
if (!wildcard &&
|
||||||
|
file_type(outfname) != FILE_TYPE_DIRECTORY &&
|
||||||
!create_directory(outfname)) {
|
!create_directory(outfname)) {
|
||||||
printf("%s: Cannot create directory\n", outfname);
|
printf("%s: Cannot create directory\n", outfname);
|
||||||
return 0;
|
return 0;
|
||||||
@ -283,7 +291,9 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
ournames = sresize(ournames, namesize, struct fxp_name *);
|
ournames = sresize(ournames, namesize, struct fxp_name *);
|
||||||
}
|
}
|
||||||
for (i = 0; i < names->nnames; i++)
|
for (i = 0; i < names->nnames; i++)
|
||||||
if (!is_dots(names->names[i].filename))
|
if (!is_dots(names->names[i].filename) &&
|
||||||
|
(!wildcard || wc_match(wildcard,
|
||||||
|
names->names[i].filename)))
|
||||||
ournames[nnames++] = fxp_dup_name(&names->names[i]);
|
ournames[nnames++] = fxp_dup_name(&names->names[i]);
|
||||||
fxp_free_names(names);
|
fxp_free_names(names);
|
||||||
}
|
}
|
||||||
@ -292,6 +302,14 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
assert(rreq == req);
|
assert(rreq == req);
|
||||||
fxp_close_recv(pktin, rreq);
|
fxp_close_recv(pktin, rreq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A polite warning if nothing at all matched the
|
||||||
|
* wildcard.
|
||||||
|
*/
|
||||||
|
if (wildcard && !nnames) {
|
||||||
|
printf("%s: nothing matched\n", wildcard);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sort the names into a clear order. This ought to
|
* Sort the names into a clear order. This ought to
|
||||||
* make things more predictable when we're doing a
|
* make things more predictable when we're doing a
|
||||||
@ -313,7 +331,11 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
while (i < nnames) {
|
while (i < nnames) {
|
||||||
char *nextoutfname;
|
char *nextoutfname;
|
||||||
int ret;
|
int ret;
|
||||||
nextoutfname = dir_file_cat(outfname, ournames[i]->filename);
|
if (outfname)
|
||||||
|
nextoutfname = dir_file_cat(outfname,
|
||||||
|
ournames[i]->filename);
|
||||||
|
else
|
||||||
|
nextoutfname = dupstr(ournames[i]->filename);
|
||||||
ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT);
|
ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT);
|
||||||
sfree(nextoutfname);
|
sfree(nextoutfname);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -334,8 +356,13 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nextfname = dupcat(fname, "/", ournames[i]->filename, NULL);
|
nextfname = dupcat(fname, "/", ournames[i]->filename, NULL);
|
||||||
nextoutfname = dir_file_cat(outfname, ournames[i]->filename);
|
if (outfname)
|
||||||
ret = sftp_get_file(nextfname, nextoutfname, recurse, restart);
|
nextoutfname = dir_file_cat(outfname,
|
||||||
|
ournames[i]->filename);
|
||||||
|
else
|
||||||
|
nextoutfname = dupstr(ournames[i]->filename);
|
||||||
|
ret = sftp_get_file(nextfname, nextoutfname,
|
||||||
|
recurse, restart, NULL);
|
||||||
restart = FALSE; /* after first partial file, do full */
|
restart = FALSE; /* after first partial file, do full */
|
||||||
sfree(nextoutfname);
|
sfree(nextoutfname);
|
||||||
sfree(nextfname);
|
sfree(nextfname);
|
||||||
@ -453,7 +480,8 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
int sftp_put_file(char *fname, char *outfname, int recurse, int restart,
|
||||||
|
char *wildcard)
|
||||||
{
|
{
|
||||||
struct fxp_handle *fh;
|
struct fxp_handle *fh;
|
||||||
struct fxp_xfer *xfer;
|
struct fxp_xfer *xfer;
|
||||||
@ -468,7 +496,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
* (If we're not in recursive mode, we need not even check: the
|
* (If we're not in recursive mode, we need not even check: the
|
||||||
* subsequent fopen will return an error message.)
|
* subsequent fopen will return an error message.)
|
||||||
*/
|
*/
|
||||||
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
|
if (wildcard || (recurse && file_type(fname) == FILE_TYPE_DIRECTORY)) {
|
||||||
struct fxp_attrs attrs;
|
struct fxp_attrs attrs;
|
||||||
int result;
|
int result;
|
||||||
int nnames, namesize;
|
int nnames, namesize;
|
||||||
@ -476,6 +504,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
DirHandle *dh;
|
DirHandle *dh;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!wildcard) {
|
||||||
/*
|
/*
|
||||||
* First, attempt to create the destination directory,
|
* First, attempt to create the destination directory,
|
||||||
* unless it already exists.
|
* unless it already exists.
|
||||||
@ -493,21 +522,38 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
result = fxp_mkdir_recv(pktin, rreq);
|
result = fxp_mkdir_recv(pktin, rreq);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
printf("%s: create directory: %s\n", outfname, fxp_error());
|
printf("%s: create directory: %s\n",
|
||||||
|
outfname, fxp_error());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now get the list of filenames in the local directory.
|
* Now get the list of filenames in the local directory.
|
||||||
*/
|
*/
|
||||||
|
nnames = namesize = 0;
|
||||||
|
ournames = NULL;
|
||||||
|
if (wildcard) {
|
||||||
|
WildcardMatcher *wcm;
|
||||||
|
|
||||||
|
wcm = begin_wildcard_matching(wildcard);
|
||||||
|
if (wcm) {
|
||||||
|
while ((name = wildcard_get_filename(wcm)) != NULL) {
|
||||||
|
if (nnames >= namesize) {
|
||||||
|
namesize += 128;
|
||||||
|
ournames = sresize(ournames, namesize, char *);
|
||||||
|
}
|
||||||
|
ournames[nnames++] = name;
|
||||||
|
}
|
||||||
|
finish_wildcard_matching(wcm);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
dh = open_directory(fname);
|
dh = open_directory(fname);
|
||||||
if (!dh) {
|
if (!dh) {
|
||||||
printf("%s: unable to open directory\n", fname);
|
printf("%s: unable to open directory\n", fname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
nnames = namesize = 0;
|
|
||||||
ournames = NULL;
|
|
||||||
while ((name = read_filename(dh)) != NULL) {
|
while ((name = read_filename(dh)) != NULL) {
|
||||||
if (nnames >= namesize) {
|
if (nnames >= namesize) {
|
||||||
namesize += 128;
|
namesize += 128;
|
||||||
@ -516,6 +562,15 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
ournames[nnames++] = name;
|
ournames[nnames++] = name;
|
||||||
}
|
}
|
||||||
close_directory(dh);
|
close_directory(dh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A polite warning if nothing at all matched the
|
||||||
|
* wildcard.
|
||||||
|
*/
|
||||||
|
if (wildcard && !nnames) {
|
||||||
|
printf("%s: nothing matched\n", wildcard);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sort the names into a clear order. This ought to make
|
* Sort the names into a clear order. This ought to make
|
||||||
@ -559,9 +614,13 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
char *nextfname, *nextoutfname;
|
char *nextfname, *nextoutfname;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (fname)
|
||||||
nextfname = dir_file_cat(fname, ournames[i]);
|
nextfname = dir_file_cat(fname, ournames[i]);
|
||||||
|
else
|
||||||
|
nextfname = dupstr(ournames[i]);
|
||||||
nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
|
nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
|
||||||
ret = sftp_put_file(nextfname, nextoutfname, recurse, restart);
|
ret = sftp_put_file(nextfname, nextoutfname,
|
||||||
|
recurse, restart, NULL);
|
||||||
restart = FALSE; /* after first partial file, do full */
|
restart = FALSE; /* after first partial file, do full */
|
||||||
sfree(nextoutfname);
|
sfree(nextoutfname);
|
||||||
sfree(nextfname);
|
sfree(nextfname);
|
||||||
@ -870,14 +929,17 @@ int sftp_cmd_pwd(struct sftp_command *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a file and save it at the local end. We have two very
|
* Get a file and save it at the local end. We have three very
|
||||||
* similar commands here: `get' and `reget', which differ in that
|
* similar commands here. The basic one is `get'; `reget' differs
|
||||||
* `reget' checks for the existence of the destination file and
|
* in that it checks for the existence of the destination file and
|
||||||
* starts from where a previous aborted transfer left off.
|
* starts from where a previous aborted transfer left off; `mget'
|
||||||
|
* differs in that it interprets all its arguments as files to
|
||||||
|
* transfer (never as a different local name for a remote file) and
|
||||||
|
* can handle wildcards.
|
||||||
*/
|
*/
|
||||||
int sftp_general_get(struct sftp_command *cmd, int restart)
|
int sftp_general_get(struct sftp_command *cmd, int restart, int multiple)
|
||||||
{
|
{
|
||||||
char *fname, *origfname, *outfname;
|
char *fname, *unwcfname, *origfname, *outfname;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
int recurse = FALSE;
|
int recurse = FALSE;
|
||||||
|
|
||||||
@ -906,38 +968,62 @@ int sftp_general_get(struct sftp_command *cmd, int restart)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
unwcfname = NULL;
|
||||||
origfname = cmd->words[i++];
|
origfname = cmd->words[i++];
|
||||||
|
|
||||||
|
if (multiple &&
|
||||||
|
!wc_unescape(unwcfname = snewn(strlen(origfname)+1, char),
|
||||||
|
origfname)) {
|
||||||
|
ret = sftp_get_file(pwd, NULL, recurse, restart, origfname);
|
||||||
|
} else {
|
||||||
fname = canonify(origfname);
|
fname = canonify(origfname);
|
||||||
if (!fname) {
|
if (!fname) {
|
||||||
printf("%s: %s\n", origfname, fxp_error());
|
printf("%s: %s\n", origfname, fxp_error());
|
||||||
|
sfree(unwcfname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
outfname = (i >= cmd->nwords ?
|
if (!multiple && i < cmd->nwords)
|
||||||
stripslashes(origfname, 0) : cmd->words[i++]);
|
outfname = cmd->words[i++];
|
||||||
|
else
|
||||||
|
outfname = stripslashes(origfname, 1);
|
||||||
|
|
||||||
ret = sftp_get_file(fname, outfname, recurse, restart);
|
ret = sftp_get_file(fname, outfname, recurse, restart, NULL);
|
||||||
|
|
||||||
sfree(fname);
|
sfree(fname);
|
||||||
|
}
|
||||||
|
sfree(unwcfname);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
} while (multiple && i < cmd->nwords);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
int sftp_cmd_get(struct sftp_command *cmd)
|
int sftp_cmd_get(struct sftp_command *cmd)
|
||||||
{
|
{
|
||||||
return sftp_general_get(cmd, 0);
|
return sftp_general_get(cmd, 0, 0);
|
||||||
|
}
|
||||||
|
int sftp_cmd_mget(struct sftp_command *cmd)
|
||||||
|
{
|
||||||
|
return sftp_general_get(cmd, 0, 1);
|
||||||
}
|
}
|
||||||
int sftp_cmd_reget(struct sftp_command *cmd)
|
int sftp_cmd_reget(struct sftp_command *cmd)
|
||||||
{
|
{
|
||||||
return sftp_general_get(cmd, 1);
|
return sftp_general_get(cmd, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send a file and store it at the remote end. We have two very
|
* Send a file and store it at the remote end. We have three very
|
||||||
* similar commands here: `put' and `reput', which differ in that
|
* similar commands here. The basic one is `put'; `reput' differs
|
||||||
* `reput' checks for the existence of the destination file and
|
* in that it checks for the existence of the destination file and
|
||||||
* starts from where a previous aborted transfer left off.
|
* starts from where a previous aborted transfer left off; `mput'
|
||||||
|
* differs in that it interprets all its arguments as files to
|
||||||
|
* transfer (never as a different remote name for a local file) and
|
||||||
|
* can handle wildcards.
|
||||||
*/
|
*/
|
||||||
int sftp_general_put(struct sftp_command *cmd, int restart)
|
int sftp_general_put(struct sftp_command *cmd, int restart, int multiple)
|
||||||
{
|
{
|
||||||
char *fname, *origoutfname, *outfname;
|
char *fname, *origoutfname, *outfname;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
@ -968,28 +1054,43 @@ int sftp_general_put(struct sftp_command *cmd, int restart)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
fname = cmd->words[i++];
|
fname = cmd->words[i++];
|
||||||
origoutfname = (i >= cmd->nwords ?
|
|
||||||
stripslashes(fname, 1) : cmd->words[i++]);
|
if (multiple && test_wildcard(fname, FALSE) == WCTYPE_WILDCARD) {
|
||||||
|
ret = sftp_put_file(NULL, pwd, recurse, restart, fname);
|
||||||
|
} else {
|
||||||
|
if (!multiple && i < cmd->nwords)
|
||||||
|
origoutfname = cmd->words[i++];
|
||||||
|
else
|
||||||
|
origoutfname = stripslashes(fname, 1);
|
||||||
|
|
||||||
outfname = canonify(origoutfname);
|
outfname = canonify(origoutfname);
|
||||||
if (!outfname) {
|
if (!outfname) {
|
||||||
printf("%s: %s\n", origoutfname, fxp_error());
|
printf("%s: %s\n", origoutfname, fxp_error());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
ret = sftp_put_file(fname, outfname, recurse, restart, NULL);
|
||||||
ret = sftp_put_file(fname, outfname, recurse, restart);
|
|
||||||
|
|
||||||
sfree(outfname);
|
sfree(outfname);
|
||||||
|
}
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
} while (multiple && i < cmd->nwords);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
int sftp_cmd_put(struct sftp_command *cmd)
|
int sftp_cmd_put(struct sftp_command *cmd)
|
||||||
{
|
{
|
||||||
return sftp_general_put(cmd, 0);
|
return sftp_general_put(cmd, 0, 0);
|
||||||
|
}
|
||||||
|
int sftp_cmd_mput(struct sftp_command *cmd)
|
||||||
|
{
|
||||||
|
return sftp_general_put(cmd, 0, 1);
|
||||||
}
|
}
|
||||||
int sftp_cmd_reput(struct sftp_command *cmd)
|
int sftp_cmd_reput(struct sftp_command *cmd)
|
||||||
{
|
{
|
||||||
return sftp_general_put(cmd, 1);
|
return sftp_general_put(cmd, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sftp_cmd_mkdir(struct sftp_command *cmd)
|
int sftp_cmd_mkdir(struct sftp_command *cmd)
|
||||||
@ -1556,12 +1657,28 @@ static struct sftp_cmd_lookup {
|
|||||||
"ls", TRUE, "dir", NULL,
|
"ls", TRUE, "dir", NULL,
|
||||||
sftp_cmd_ls
|
sftp_cmd_ls
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mget", TRUE, "download multiple files at once",
|
||||||
|
" <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
||||||
|
" Downloads many files from the server, storing each one under\n"
|
||||||
|
" the same name it has on the server side. You can use wildcards\n"
|
||||||
|
" such as \"*.c\" to specify lots of files at once.\n",
|
||||||
|
sftp_cmd_mget
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mkdir", TRUE, "create a directory on the remote server",
|
"mkdir", TRUE, "create a directory on the remote server",
|
||||||
" <directory-name>\n"
|
" <directory-name>\n"
|
||||||
" Creates a directory with the given name on the server.\n",
|
" Creates a directory with the given name on the server.\n",
|
||||||
sftp_cmd_mkdir
|
sftp_cmd_mkdir
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mput", TRUE, "upload multiple files at once",
|
||||||
|
" <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
||||||
|
" Uploads many files to the server, storing each one under the\n"
|
||||||
|
" same name it has on the client side. You can use wildcards\n"
|
||||||
|
" such as \"*.c\" to specify lots of files at once.\n",
|
||||||
|
sftp_cmd_mput
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mv", TRUE, "move or rename a file on the remote server",
|
"mv", TRUE, "move or rename a file on the remote server",
|
||||||
" <source-filename> <destination-filename>\n"
|
" <source-filename> <destination-filename>\n"
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <glob.h>
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "psftp.h"
|
#include "psftp.h"
|
||||||
@ -285,30 +286,60 @@ void close_directory(DirHandle *dir)
|
|||||||
|
|
||||||
int test_wildcard(char *name, int cmdline)
|
int test_wildcard(char *name, int cmdline)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* On Unix, we currently don't support local wildcards at all.
|
|
||||||
* We will have to do so (FIXME) once PSFTP starts implementing
|
|
||||||
* mput, but until then we can assume `cmdline' is always set.
|
|
||||||
*/
|
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
assert(cmdline);
|
if (stat(name, &statbuf) == 0) {
|
||||||
if (stat(name, &statbuf) < 0)
|
|
||||||
return WCTYPE_NONEXISTENT;
|
|
||||||
else
|
|
||||||
return WCTYPE_FILENAME;
|
return WCTYPE_FILENAME;
|
||||||
|
} else if (cmdline) {
|
||||||
|
/*
|
||||||
|
* On Unix, we never need to parse wildcards coming from
|
||||||
|
* the command line, because the shell will have expanded
|
||||||
|
* them into a filename list already.
|
||||||
|
*/
|
||||||
|
return WCTYPE_NONEXISTENT;
|
||||||
|
} else {
|
||||||
|
glob_t globbed;
|
||||||
|
int ret = WCTYPE_NONEXISTENT;
|
||||||
|
|
||||||
|
if (glob(name, GLOB_ERR, NULL, &globbed) == 0) {
|
||||||
|
if (globbed.gl_pathc > 0)
|
||||||
|
ret = WCTYPE_WILDCARD;
|
||||||
|
globfree(&globbed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actually return matching file names for a local wildcard. FIXME:
|
* Actually return matching file names for a local wildcard.
|
||||||
* we currently don't support this at all.
|
|
||||||
*/
|
*/
|
||||||
struct WildcardMatcher {
|
struct WildcardMatcher {
|
||||||
int x;
|
glob_t globbed;
|
||||||
|
int i;
|
||||||
};
|
};
|
||||||
WildcardMatcher *begin_wildcard_matching(char *name) { return NULL; }
|
WildcardMatcher *begin_wildcard_matching(char *name) {
|
||||||
char *wildcard_get_filename(WildcardMatcher *dir) { return NULL; }
|
WildcardMatcher *ret = snew(WildcardMatcher);
|
||||||
void finish_wildcard_matching(WildcardMatcher *dir) {}
|
|
||||||
|
if (glob(name, 0, NULL, &ret->globbed) < 0) {
|
||||||
|
sfree(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->i = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
char *wildcard_get_filename(WildcardMatcher *dir) {
|
||||||
|
if (dir->i < dir->globbed.gl_pathc) {
|
||||||
|
return dupstr(dir->globbed.gl_pathv[dir->i++]);
|
||||||
|
} else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void finish_wildcard_matching(WildcardMatcher *dir) {
|
||||||
|
globfree(&dir->globbed);
|
||||||
|
sfree(dir);
|
||||||
|
}
|
||||||
|
|
||||||
int create_directory(char *name)
|
int create_directory(char *name)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user