📄 psftp.c
字号:
" those particular commands.\n",
sftp_cmd_help
},
{
"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
},
{
"mget", TRUE, "download multiple files at once",
" [ -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"
" If -r specified, recursively fetch files and directories.\n",
sftp_cmd_mget
},
{
"mkdir", TRUE, "create directories on the remote server",
" <directory-name> [ <directory-name>... ]\n"
" Creates directories with the given names on the server.\n",
sftp_cmd_mkdir
},
{
"mput", TRUE, "upload multiple files at once",
" [ -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"
" If -r specified, recursively store files and directories.\n",
sftp_cmd_mput
},
{
"mv", TRUE, "move or rename file(s) on the remote server",
" <source> [ <source>... ] <destination>\n"
" Moves or renames <source>(s) on the server to <destination>,\n"
" also on the server.\n"
" If <destination> specifies an existing directory, then <source>\n"
" may be a wildcard, and multiple <source>s may be given; all\n"
" source files are moved into <destination>.\n"
" Otherwise, <source> must specify a single file, which is moved\n"
" or renamed so that it is accessible under the name <destination>.\n",
sftp_cmd_mv
},
{
"open", TRUE, "connect to a host",
" [<user>@]<hostname> [<port>]\n"
" Establishes an SFTP connection to a given host. Only usable\n"
" when you are not already connected to a server.\n",
sftp_cmd_open
},
{
"put", TRUE, "upload a file from your local machine to the server",
" [ -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"
" If -r specified, recursively store a directory.\n",
sftp_cmd_put
},
{
"pwd", TRUE, "print your remote working directory",
"\n"
" Print the current remote working directory for your SFTP session.\n",
sftp_cmd_pwd
},
{
"quit", TRUE, "bye", NULL,
sftp_cmd_quit
},
{
"reget", TRUE, "continue downloading files",
" [ -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"
" If -r specified, resume interrupted \"get -r\".\n",
sftp_cmd_reget
},
{
"ren", TRUE, "mv", NULL,
sftp_cmd_mv
},
{
"rename", FALSE, "mv", NULL,
sftp_cmd_mv
},
{
"reput", TRUE, "continue uploading files",
" [ -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"
" If -r specified, resume interrupted \"put -r\".\n",
sftp_cmd_reput
},
{
"rm", TRUE, "del", NULL,
sftp_cmd_rm
},
{
"rmdir", TRUE, "remove directories on the remote server",
" <directory-name> [ <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"
" Wildcards may be used to specify multiple directories.\n",
sftp_cmd_rmdir
}
};
const struct sftp_cmd_lookup *lookup_command(char *name)
{
int i, j, k, cmp;
i = -1;
j = sizeof(sftp_lookup) / sizeof(*sftp_lookup);
while (j - i > 1) {
k = (j + i) / 2;
cmp = strcmp(name, sftp_lookup[k].name);
if (cmp < 0)
j = k;
else if (cmp > 0)
i = k;
else {
return &sftp_lookup[k];
}
}
return NULL;
}
static int sftp_cmd_help(struct sftp_command *cmd)
{
int i;
if (cmd->nwords == 1) {
/*
* Give short help on each command.
*/
int maxlen;
maxlen = 0;
for (i = 0; i < sizeof(sftp_lookup) / sizeof(*sftp_lookup); i++) {
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)
lookup = lookup_command(lookup->shorthelp);
printf("%s\n", lookup->shorthelp);
}
} else {
/*
* Give long help on specific commands.
*/
for (i = 1; i < cmd->nwords; i++) {
const struct sftp_cmd_lookup *lookup;
lookup = lookup_command(cmd->words[i]);
if (!lookup) {
printf("help: %s: command not found\n", cmd->words[i]);
} else {
printf("%s", lookup->name);
if (lookup->longhelp == NULL)
lookup = lookup_command(lookup->shorthelp);
printf("%s", lookup->longhelp);
}
}
}
return 1;
}
/* ----------------------------------------------------------------------
* Command line reading and parsing.
*/
struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
{
char *line;
struct sftp_command *cmd;
char *p, *q, *r;
int quoting;
cmd = snew(struct sftp_command);
cmd->words = NULL;
cmd->nwords = 0;
cmd->wordssize = 0;
line = NULL;
if (fp) {
if (modeflags & 1)
printf("psftp> ");
line = fgetline(fp);
} else {
line = ssh_sftp_get_cmdline("psftp> ", back == NULL);
}
if (!line || !*line) {
cmd->obey = sftp_cmd_quit;
if ((mode == 0) || (modeflags & 1))
printf("quit\n");
return cmd; /* eof */
}
line[strcspn(line, "\r\n")] = '\0';
if (modeflags & 1) {
printf("%s\n", line);
}
p = line;
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 = sresize(cmd->words, cmd->wordssize, char *);
cmd->words[0] = dupstr("!");
cmd->words[1] = dupstr(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) {
/* 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 = sresize(cmd->words, cmd->wordssize, char *);
}
cmd->words[cmd->nwords++] = dupstr(q);
}
}
sfree(line);
/*
* Now parse the first word and assign a function.
*/
if (cmd->nwords == 0)
cmd->obey = sftp_cmd_null;
else {
const struct sftp_cmd_lookup *lookup;
lookup = lookup_command(cmd->words[0]);
if (!lookup)
cmd->obey = sftp_cmd_unknown;
else
cmd->obey = lookup->obey;
}
return cmd;
}
static int do_sftp_init(void)
{
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
/*
* Do protocol initialisation.
*/
if (!fxp_init()) {
fprintf(stderr,
"Fatal: unable to initialise SFTP: %s\n", fxp_error());
return 1; /* failure */
}
/*
* Find out where our home directory is.
*/
sftp_register(req = fxp_realpath_send("."));
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
homedir = fxp_realpath_recv(pktin, rreq);
if (!homedir) {
fprintf(stderr,
"Warning: failed to resolve home directory: %s\n",
fxp_error());
homedir = dupstr(".");
} else {
printf("Remote working directory is %s\n", homedir);
}
pwd = dupstr(homedir);
return 0;
}
void do_sftp_cleanup()
{
char ch;
if (back) {
back->special(backhandle, TS_EOF);
sftp_recvdata(&ch, 1);
back->free(backhandle);
sftp_cleanup_request();
back = NULL;
backhandle = NULL;
}
if (pwd) {
sfree(pwd);
pwd = NULL;
}
if (homedir) {
sfree(homedir);
homedir = NULL;
}
}
void do_sftp(int mode, int modeflags, char *batchfile)
{
FILE *fp;
int ret;
/*
* Batch mode?
*/
if (mode == 0) {
/* ------------------------------------------------------------------
* Now we're ready to do Real Stuff.
*/
while (1) {
struct sftp_command *cmd;
cmd = sftp_getcmd(NULL, 0, 0);
if (!cmd)
break;
ret = cmd->obey(cmd);
if (cmd->words) {
int i;
for(i = 0; i < cmd->nwords; i++)
sfree(cmd->words[i]);
sfree(cmd->words);
}
sfree(cmd);
if (ret < 0)
break;
}
} else {
fp = fopen(batchfile, "r");
if (!fp) {
printf("Fatal: unable to open %s\n", batchfile);
return;
}
while (1) {
struct sftp_command *cmd;
cmd = sftp_getcmd(fp, mode, modeflags);
if (!cmd)
break;
ret = cmd->obey(cmd);
if (ret < 0)
break;
if (ret == 0) {
if (!(modeflags & 2))
break;
}
}
fclose(fp);
}
}
/* ----------------------------------------------------------------------
* Dirty bits: integration with PuTTY.
*/
static int verbose = 0;
/*
* Print an error message and perform a fatal exit.
*/
void fatalbox(char *fmt, ...)
{
char *str, *str2;
va_list ap;
va_start(ap, fmt);
str = dupvprintf(fmt, ap);
str2 = dupcat("Fatal: ", str, "\n", NULL);
sfree(str);
va_end(ap);
fputs(str2, stderr);
sfree(str2);
cleanup_exit(1);
}
void modalfatalbox(char *fmt, ...)
{
char *str, *str2;
va_list ap;
va_start(ap, fmt);
str = dupvprintf(fmt, ap);
str2 = dupcat("Fatal: ", str, "\n", NULL);
sfree(str);
va_end(ap);
fputs(str2, stderr);
sfree(str2);
cleanup_exit(1);
}
void connection_fatal(void *frontend, char *fmt, ...)
{
char *str, *str2;
va_list ap;
va_start(ap, fmt);
str = dupvprintf(fmt, ap);
str2 = dupcat("Fatal: ", str, "\n", NULL);
sfree(str);
va_end(ap);
fputs(str2, stderr);
sfree(str2);
cleanup_exit(1);
}
void ldisc_send(void *handle, char *buf, int len, int interactive)
{
/*
* This is only here because of the calls to ldisc_send(NULL,
* 0) in ssh.c. Nothing in PSFTP actually needs to use the
* ldisc as an ldisc. So if we get called with any real data, I
* want to know about it.
*/
assert(len == 0);
}
/*
* In psftp, all agent requests should be synchronous, so this is a
* never-called stub.
*/
void agent_schedule_callback(void (*callback)(void *, void *, int),
void *callback_ctx, void *data, int len)
{
assert(!"We shouldn't be here");
}
/*
* Receive a block of data from the SSH link. Block until all data
* is available.
*
* To do this, we repeatedly call the SSH protocol module, with our
* own tr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -