*/
/*
- * Determine whether a string is entirely composed of dots.
- */
-static int is_dots(char *str)
-{
- return str[strspn(str, ".")] == '\0';
-}
-
-/*
* Attempt to canonify a pathname starting from the pwd. If
* canonification fails, at least fall back to returning a _valid_
* pathname (though it may be ugly, eg /home/simon/../foobar).
struct fxp_xfer *xfer;
uint64 offset;
FILE *fp;
- int ret;
+ int ret, shown_err = FALSE;
/*
* In recursive mode, see if we're dealing with a directory.
ournames = sresize(ournames, namesize, struct fxp_name *);
}
for (i = 0; i < names->nnames; i++)
- if (!is_dots(names->names[i].filename) &&
+ if (strcmp(names->names[i].filename, ".") &&
+ strcmp(names->names[i].filename, "..") &&
(!wildcard || wc_match(wildcard,
- names->names[i].filename)))
- ournames[nnames++] = fxp_dup_name(&names->names[i]);
+ names->names[i].filename))) {
+ if (!vet_filename(names->names[i].filename)) {
+ printf("ignoring potentially dangerous server-"
+ "supplied filename '%s'\n",
+ names->names[i].filename);
+ } else {
+ ournames[nnames++] =
+ fxp_dup_name(&names->names[i]);
+ }
+ }
fxp_free_names(names);
}
sftp_register(req = fxp_close_send(dirhandle));
ret = xfer_download_gotpkt(xfer, pktin);
if (ret < 0) {
- printf("error while reading: %s\n", fxp_error());
+ if (!shown_err) {
+ printf("error while reading: %s\n", fxp_error());
+ shown_err = TRUE;
+ }
ret = 0;
}
} else if (!strcmp(cmd->words[i], "-r")) {
recurse = TRUE;
} else {
- printf("get: unrecognised option '%s'\n", cmd->words[i]);
+ printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]);
return 0;
}
i++;
}
if (i >= cmd->nwords) {
- printf("get: expects a filename\n");
+ printf("%s: expects a filename\n", cmd->words[0]);
return 0;
}
} else if (!strcmp(cmd->words[i], "-r")) {
recurse = TRUE;
} else {
- printf("put: unrecognised option '%s'\n", cmd->words[i]);
+ printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]);
return 0;
}
i++;
}
if (i >= cmd->nwords) {
- printf("put: expects a filename\n");
+ printf("%s: expects a filename\n", cmd->words[0]);
return 0;
}
},
{
"dir", TRUE, "list contents of a remote directory",
- " [ <directory-name> ]\n"
+ " [ <directory-name> ]/[ <wildcard> ]\n"
" List the contents of a specified directory on the server.\n"
" If <directory-name> is not given, the current working directory\n"
- " will be listed.\n",
+ " is assumed.\n"
+ " If <wildcard> is given, it is treated as a set of files to\n"
+ " list; otherwise, all files are listed.\n",
sftp_cmd_ls
},
{
},
{
"get", TRUE, "download a file from the server to your local machine",
- " <filename> [ <local-filename> ]\n"
+ " [ -r ] [ -- ] <filename> [ <local-filename> ]\n"
" Downloads a file on the server and stores it locally under\n"
" the same name, or under a different one if you supply the\n"
- " argument <local-filename>.\n",
+ " argument <local-filename>.\n"
+ " If -r specified, recursively fetch a directory.\n",
sftp_cmd_get
},
{
},
{
"mget", TRUE, "download multiple files at once",
- " <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
+ " [ -r ] [ -- ] <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",
+ " such as \"*.c\" to specify lots of files at once.\n"
+ " If -r specified, recursively fetch files and directories.\n",
sftp_cmd_mget
},
{
},
{
"mput", TRUE, "upload multiple files at once",
- " <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
+ " [ -r ] [ -- ] <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",
+ " such as \"*.c\" to specify lots of files at once.\n"
+ " If -r specified, recursively store files and directories.\n",
sftp_cmd_mput
},
{
},
{
"put", TRUE, "upload a file from your local machine to the server",
- " <filename> [ <remote-filename> ]\n"
+ " [ -r ] [ -- ] <filename> [ <remote-filename> ]\n"
" Uploads a file to the server and stores it there under\n"
" the same name, or under a different one if you supply the\n"
- " argument <remote-filename>.\n",
+ " argument <remote-filename>.\n"
+ " If -r specified, recursively store a directory.\n",
sftp_cmd_put
},
{
},
{
"reget", TRUE, "continue downloading a file",
- " <filename> [ <local-filename> ]\n"
+ " [ -r ] [ -- ] <filename> [ <local-filename> ]\n"
" Works exactly like the \"get\" command, but the local file\n"
" must already exist. The download will begin at the end of the\n"
- " file. This is for resuming a download that was interrupted.\n",
+ " file. This is for resuming a download that was interrupted.\n"
+ " If -r specified, resume interrupted \"get -r\".\n",
sftp_cmd_reget
},
{
},
{
"reput", TRUE, "continue uploading a file",
- " <filename> [ <remote-filename> ]\n"
+ " [ -r ] [ -- ] <filename> [ <remote-filename> ]\n"
" Works exactly like the \"put\" command, but the remote file\n"
" must already exist. The upload will begin at the end of the\n"
- " file. This is for resuming an upload that was interrupted.\n",
+ " file. This is for resuming an upload that was interrupted.\n"
+ " If -r specified, resume interrupted \"put -r\".\n",
sftp_cmd_reput
},
{