1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Add the `local' command set to PSFTP: lcd, lpwd, and ! to spawn a

Windows command.

[originally from svn r1501]
This commit is contained in:
Simon Tatham 2001-12-16 13:33:04 +00:00
parent c64d6871f6
commit 0d7dc070d5
2 changed files with 233 additions and 71 deletions

View File

@ -1,4 +1,4 @@
\versionid $Id: psftp.but,v 1.2 2001/12/14 12:22:09 simon Exp $
\versionid $Id: psftp.but,v 1.3 2001/12/16 13:33:04 simon Exp $
\C{psftp} Using PSFTP to transfer files securely
@ -159,6 +159,40 @@ Once you have started your PSFTP session, you will see a \c{psftp>}
prompt. You can now type commands to perform file-transfer
functions. This section lists all the available commands.
\S{psftp-quoting} General quoting rules for PSFTP commands
Most PSFTP commands are considered by the PSFTP command interpreter
as a sequence of words, separated by spaces. For example, the
command \c{ren oldfilename newfilename} splits up into three words:
\c{ren} (the command name), \c{oldfilename} (the name of the file to
be renamed), and \c{newfilename} (the new name to give the file).
Sometimes you will need to specify file names that \e{contain}
spaces. In order to do this, you can surround the file name with
double quotes. This works equally well for local file names and
remote file names:
\c psftp> get "spacey file name.txt" "save it under this name.txt"
The double quotes themselves will not appear as part of the file
names; they are removed by PSFTP and their only effect is to stop
the spaces inside them from acting as word separators.
If you need to \e{use} a double quote (on some types of remote
system, such as Unix, you are allowed to use double quotes in file
names), you can do this by doubling it. This works both inside and
outside double quotes. For example, this command
\c psftp> ren ""this"" "a file with ""quotes"" in it"
will take a file whose current name is \c{"this"} (with a double
quote character at the beginning and the end) and rename it to a
file whose name is \c{a file with "quotes" in it}.
(The one exception to the PSFTP quoting rules is the \c{!} command,
which passes its command line straight to Windows without splitting
it up into words at all. See \k{psftp-cmd-pling}.)
\S{psftp-cmd-open} The \c{open} command: start a session
If you started PSFTP by double-clicking in the GUI, or just by
@ -198,11 +232,24 @@ remote working directory
PSFTP maintains a notion of your \q{working directory} on the
server. This is the default directory that other commands will
operate on. For example, if you type \c{get filename.dat} then PSFTP
will look for \c{filename.dat} in your working directory on the
server.
will look for \c{filename.dat} in your remote working directory on
the server.
To change your working directory, use the \c{cd} command. To display
your current working directory, type \c{pwd}.
To change your remote working directory, use the \c{cd} command. To
display your current remote working directory, type \c{pwd}.
\S{psftp-cmd-lcd} The \c{lcd} and \c{lpwd} commands: changing the
local working directory
As well as having a working directory on the remote server, PSFTP
also has a working directory on your local machine (just like any
other Windows process). This is the default local directory that
other commands will operate on. For example, if you type \c{get
filename.dat} then PSFTP will save the resulting file as
\c{filename.dat} in your local working directory.
To change your local working directory, use the \c{lcd} command. To
display your current local working directory, type \c{lpwd}.
\S{psftp-cmd-get} The \c{get} command: fetch a file from the server
@ -363,6 +410,22 @@ name, and then the new file name:
The \c{rename} and \c{mv} commands work exactly the same way as
\c{ren}.
\S{psftp-cmd-pling} The \c{!} command: run a local Windows command
You can run local Windows commands using the \c{!} command. This is
the only PSFTP command that is not subject to the command quoting
rules given in \k{psftp-quoting}. If any command line begins with
the \c{!} character, then the rest of the line will be passed
straight to Windows without further translation.
For example, if you want to move an existing copy of a file out of
the way before downloading an updated version, you might type:
\c psftp> !ren myfile.dat myfile.bak
\c psftp> get myfile.dat
using the Windows \c{ren} command to rename files on your local PC.
\H{psftp-pubkey} Using public key authentication with PSFTP
Like PuTTY, PSFTP can authenticate using a public key instead of a

231
psftp.c
View File

@ -904,6 +904,66 @@ static int sftp_cmd_open(struct sftp_command *cmd)
return 1;
}
static int sftp_cmd_lcd(struct sftp_command *cmd)
{
char *currdir;
int len;
if (cmd->nwords < 2) {
printf("lcd: expects a local directory name\n");
return 0;
}
if (!SetCurrentDirectory(cmd->words[1])) {
LPVOID message;
int i;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&message, 0, NULL);
i = strcspn((char *)message, "\n");
printf("lcd: unable to change directory: %.*s\n", i, (LPCTSTR)message);
LocalFree(message);
return 0;
}
currdir = smalloc(256);
len = GetCurrentDirectory(256, currdir);
if (len > 256)
currdir = srealloc(currdir, len);
GetCurrentDirectory(len, currdir);
printf("New local directory is %s\n", currdir);
sfree(currdir);
return 1;
}
static int sftp_cmd_lpwd(struct sftp_command *cmd)
{
char *currdir;
int len;
currdir = smalloc(256);
len = GetCurrentDirectory(256, currdir);
if (len > 256)
currdir = srealloc(currdir, len);
GetCurrentDirectory(len, currdir);
printf("Current local directory is %s\n", currdir);
sfree(currdir);
return 1;
}
static int sftp_cmd_pling(struct sftp_command *cmd)
{
int exitcode;
exitcode = system(cmd->words[1]);
return (exitcode == 0);
}
static int sftp_cmd_help(struct sftp_command *cmd);
static struct sftp_cmd_lookup {
@ -920,6 +980,7 @@ static struct sftp_cmd_lookup {
* `shorthelp' is the name of a primary command, which
* contains the help that should double up for this command.
*/
int listed; /* do we list this in primary help? */
char *shorthelp;
char *longhelp;
int (*obey) (struct sftp_command *);
@ -929,13 +990,19 @@ static struct sftp_cmd_lookup {
* in ASCII order.
*/
{
"bye", "finish your SFTP session",
"!", TRUE, "run a local Windows command",
"<command>\n"
" Runs a local Windows command. For example, \"!del myfile\".\n",
sftp_cmd_pling
},
{
"bye", TRUE, "finish your SFTP session",
"\n"
" Terminates your SFTP session and quits the PSFTP program.\n",
sftp_cmd_quit
},
{
"cd", "change your remote working directory",
"cd", TRUE, "change your remote working directory",
" [ <New working directory> ]\n"
" Change the remote working directory for your SFTP session.\n"
" If a new working directory is not supplied, you will be\n"
@ -943,7 +1010,7 @@ static struct sftp_cmd_lookup {
sftp_cmd_cd
},
{
"chmod", "change file permissions and modes",
"chmod", TRUE, "change file permissions and modes",
" ( <octal-digits> | <modifiers> ) <filename>\n"
" Change the file permissions on a file or directory.\n"
" <octal-digits> can be any octal Unix permission specifier.\n"
@ -970,19 +1037,16 @@ static struct sftp_cmd_lookup {
sftp_cmd_chmod
},
{
"del", "delete a file",
"del", TRUE, "delete a file",
" <filename>\n"
" Delete a file.\n",
sftp_cmd_rm
},
{
"delete", "delete a file",
"\n"
" Delete a file.\n",
sftp_cmd_rm
"delete", FALSE, "del", NULL, sftp_cmd_rm
},
{
"dir", "list contents of a remote directory",
"dir", TRUE, "list contents of a remote directory",
" [ <directory-name> ]\n"
" List the contents of a specified directory on the server.\n"
" If <directory-name> is not given, the current working directory\n"
@ -990,10 +1054,10 @@ static struct sftp_cmd_lookup {
sftp_cmd_ls
},
{
"exit", "bye", NULL, sftp_cmd_quit
"exit", TRUE, "bye", NULL, sftp_cmd_quit
},
{
"get", "download a file from the server to your local machine",
"get", TRUE, "download a file from the server to your local machine",
" <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"
@ -1001,7 +1065,7 @@ static struct sftp_cmd_lookup {
sftp_cmd_get
},
{
"help", "give help",
"help", TRUE, "give help",
" [ <command> [ <command> ... ] ]\n"
" Give general help if no commands are specified.\n"
" If one or more commands are specified, give specific help on\n"
@ -1009,24 +1073,38 @@ static struct sftp_cmd_lookup {
sftp_cmd_help
},
{
"ls", "dir", NULL,
"lcd", TRUE, "change local working directory",
" <local-directory-name>\n"
" Change the local working directory of the PSFTP program (the\n"
" default location where the \"get\" command will save files).\n",
sftp_cmd_lcd
},
{
"lpwd", TRUE, "print local working directory",
"\n"
" Print the local working directory of the PSFTP program (the\n"
" default location where the \"get\" command will save files).\n",
sftp_cmd_lpwd
},
{
"ls", TRUE, "dir", NULL,
sftp_cmd_ls
},
{
"mkdir", "create a directory on the remote server",
"mkdir", TRUE, "create a directory on the remote server",
" <directory-name>\n"
" Creates a directory with the given name on the server.\n",
sftp_cmd_mkdir
},
{
"mv", "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"
" Moves or renames the file <source-filename> on the server,\n"
" so that it is accessible under the name <destination-filename>.\n",
sftp_cmd_mv
},
{
"put", "upload a file from your local machine to the server",
"put", TRUE, "upload a file from your local machine to the server",
" <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"
@ -1034,7 +1112,7 @@ static struct sftp_cmd_lookup {
sftp_cmd_put
},
{
"open", "connect to a host",
"open", TRUE, "connect to a host",
" [<user>@]<hostname>\n"
" Establishes an SFTP connection to a given host. Only usable\n"
" when you did not already specify a host name on the command\n"
@ -1042,17 +1120,17 @@ static struct sftp_cmd_lookup {
sftp_cmd_open
},
{
"pwd", "print your remote working directory",
"pwd", TRUE, "print your remote working directory",
"\n"
" Print the current remote working directory for your SFTP session.\n",
sftp_cmd_pwd
},
{
"quit", "bye", NULL,
"quit", TRUE, "bye", NULL,
sftp_cmd_quit
},
{
"reget", "continue downloading a file",
"reget", TRUE, "continue downloading a file",
" <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"
@ -1060,15 +1138,15 @@ static struct sftp_cmd_lookup {
sftp_cmd_reget
},
{
"ren", "mv", NULL,
"ren", TRUE, "mv", NULL,
sftp_cmd_mv
},
{
"rename", "mv", NULL,
"rename", FALSE, "mv", NULL,
sftp_cmd_mv
},
{
"reput", "continue uploading a file",
"reput", TRUE, "continue uploading a file",
" <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"
@ -1076,11 +1154,11 @@ static struct sftp_cmd_lookup {
sftp_cmd_reput
},
{
"rm", "del", NULL,
"rm", TRUE, "del", NULL,
sftp_cmd_rm
},
{
"rmdir", "remove a directory on the remote server",
"rmdir", TRUE, "remove a directory on the remote server",
" <directory-name>\n"
" Removes the directory with the given name on the server.\n"
" The directory will not be removed unless it is empty.\n",
@ -1118,12 +1196,17 @@ static int sftp_cmd_help(struct sftp_command *cmd)
int maxlen;
maxlen = 0;
for (i = 0; i < sizeof(sftp_lookup) / sizeof(*sftp_lookup); i++) {
int len = strlen(sftp_lookup[i].name);
int len;
if (!sftp_lookup[i].listed)
continue;
len = strlen(sftp_lookup[i].name);
if (maxlen < len)
maxlen = len;
}
for (i = 0; i < sizeof(sftp_lookup) / sizeof(*sftp_lookup); i++) {
const struct sftp_cmd_lookup *lookup;
if (!sftp_lookup[i].listed)
continue;
lookup = &sftp_lookup[i];
printf("%-*s", maxlen+2, lookup->name);
if (lookup->longhelp == NULL)
@ -1199,49 +1282,65 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
printf("%s\n", line);
}
/*
* Parse the command line into words. The syntax is:
* - double quotes are removed, but cause spaces within to be
* treated as non-separating.
* - a double-doublequote pair is a literal double quote, inside
* _or_ outside quotes. Like this:
*
* firstword "second word" "this has ""quotes"" in" sodoes""this""
*
* becomes
*
* >firstword<
* >second word<
* >this has "quotes" in<
* >sodoes"this"<
*/
p = line;
while (*p) {
/* skip whitespace */
while (*p && (*p == ' ' || *p == '\t'))
p++;
/* mark start of word */
q = r = p; /* q sits at start, r writes word */
quoting = 0;
while (*p && (*p == ' ' || *p == '\t'))
p++;
if (*p == '!') {
/*
* Special case: the ! command. This is always parsed as
* exactly two words: one containing the !, and the second
* containing everything else on the line.
*/
cmd->nwords = cmd->wordssize = 2;
cmd->words = srealloc(cmd->words, cmd->wordssize * sizeof(char *));
cmd->words[0] = "!";
cmd->words[1] = p+1;
} else {
/*
* Parse the command line into words. The syntax is:
* - double quotes are removed, but cause spaces within to be
* treated as non-separating.
* - a double-doublequote pair is a literal double quote, inside
* _or_ outside quotes. Like this:
*
* firstword "second word" "this has ""quotes"" in" and""this""
*
* becomes
*
* >firstword<
* >second word<
* >this has "quotes" in<
* >and"this"<
*/
while (*p) {
if (!quoting && (*p == ' ' || *p == '\t'))
break; /* reached end of word */
else if (*p == '"' && p[1] == '"')
p += 2, *r++ = '"'; /* a literal quote */
else if (*p == '"')
p++, quoting = !quoting;
else
*r++ = *p++;
/* skip whitespace */
while (*p && (*p == ' ' || *p == '\t'))
p++;
/* mark start of word */
q = r = p; /* q sits at start, r writes word */
quoting = 0;
while (*p) {
if (!quoting && (*p == ' ' || *p == '\t'))
break; /* reached end of word */
else if (*p == '"' && p[1] == '"')
p += 2, *r++ = '"'; /* a literal quote */
else if (*p == '"')
p++, quoting = !quoting;
else
*r++ = *p++;
}
if (*p)
p++; /* skip over the whitespace */
*r = '\0';
if (cmd->nwords >= cmd->wordssize) {
cmd->wordssize = cmd->nwords + 16;
cmd->words =
srealloc(cmd->words, cmd->wordssize * sizeof(char *));
}
cmd->words[cmd->nwords++] = q;
}
if (*p)
p++; /* skip over the whitespace */
*r = '\0';
if (cmd->nwords >= cmd->wordssize) {
cmd->wordssize = cmd->nwords + 16;
cmd->words =
srealloc(cmd->words, cmd->wordssize * sizeof(char *));
}
cmd->words[cmd->nwords++] = q;
}
/*