📄 psftp.c
字号:
printf("lcd: unable to change directory: %s\n", errmsg); sfree(errmsg); return 0; } currdir = psftp_getcwd(); printf("New local directory is %s\n", currdir); sfree(currdir); return 1;}static int sftp_cmd_lpwd(struct sftp_command *cmd){ char *currdir; currdir = psftp_getcwd(); 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 { char *name; /* * For help purposes, there are two kinds of command: * * - primary commands, in which `longhelp' is non-NULL. In * this case `shorthelp' is descriptive text, and `longhelp' * is longer descriptive text intended to be printed after * the command name. * * - alias commands, in which `longhelp' is NULL. In this case * `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 *);} sftp_lookup[] = { /* * List of sftp commands. This is binary-searched so it MUST be * in ASCII order. */ { "!", TRUE, "run a local command", "<command>\n" /* FIXME: this example is crap for non-Windows. */ " Runs a local 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", 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" " returned to your home directory.\n", sftp_cmd_cd }, { "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" " Alternatively, <modifiers> can include:\n" " u+r make file readable by owning user\n" " u+w make file writable by owning user\n" " u+x make file executable by owning user\n" " u-r make file not readable by owning user\n" " [also u-w, u-x]\n" " g+r make file readable by members of owning group\n" " [also g+w, g+x, g-r, g-w, g-x]\n" " o+r make file readable by all other users\n" " [also o+w, o+x, o-r, o-w, o-x]\n" " a+r make file readable by absolutely everybody\n" " [also a+w, a+x, a-r, a-w, a-x]\n" " u+s enable the Unix set-user-ID bit\n" " u-s disable the Unix set-user-ID bit\n" " g+s enable the Unix set-group-ID bit\n" " g-s disable the Unix set-group-ID bit\n" " +t enable the Unix \"sticky bit\"\n" " You can give more than one modifier for the same user (\"g-rwx\"), and\n" " more than one user for the same modifier (\"ug+w\"). You can\n" " use commas to separate different modifiers (\"u+rwx,g+s\").\n", sftp_cmd_chmod }, { "del", TRUE, "delete a file", " <filename>\n" " Delete a file.\n", sftp_cmd_rm }, { "delete", FALSE, "del", NULL, sftp_cmd_rm }, { "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" " will be listed.\n", sftp_cmd_ls }, { "exit", TRUE, "bye", NULL, sftp_cmd_quit }, { "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" " argument <local-filename>.\n", sftp_cmd_get }, { "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" " 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 }, { "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", 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 }, { "open", TRUE, "connect to a host", " [<user>@]<hostname> [<port>]\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" " line.\n", sftp_cmd_open }, { "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" " argument <remote-filename>.\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 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" " file. This is for resuming a download that was interrupted.\n", sftp_cmd_reget }, { "ren", TRUE, "mv", NULL, sftp_cmd_mv }, { "rename", FALSE, "mv", NULL, sftp_cmd_mv }, { "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" " file. This is for resuming an upload that was interrupted.\n", sftp_cmd_reput }, { "rm", TRUE, "del", NULL, sftp_cmd_rm }, { "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", 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; int linelen, linesize; struct sftp_command *cmd; char *p, *q, *r; int quoting; if ((mode == 0) || (modeflags & 1)) { printf("psftp> "); } fflush(stdout); cmd = snew(struct sftp_command); cmd->words = NULL; cmd->nwords = 0; cmd->wordssize = 0; line = NULL; linesize = linelen = 0; while (1) { int len; char *ret; linesize += 512; line = sresize(line, linesize, char); ret = fgets(line + linelen, linesize - linelen, fp); if (!ret || (linelen == 0 && line[0] == '\0')) { cmd->obey = sftp_cmd_quit; if ((mode == 0) || (modeflags & 1)) printf("quit\n"); return cmd; /* eof */ } len = linelen + strlen(line + linelen); linelen += len; if (line[linelen - 1] == '\n') { linelen--; line[linelen] = '\0'; break; } } 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(); } 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(stdin, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -