📄 sftp-int.c
字号:
/* * Copyright (c) 2001,2002 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* XXX: globbed ls *//* XXX: recursive operations */#include "includes.h"RCSID("$OpenBSD: sftp-int.c,v 1.46 2002/03/30 18:51:15 markus Exp $");#include "buffer.h"#include "xmalloc.h"#include "log.h"#include "pathnames.h"#include "sftp.h"#include "sftp-common.h"#include "sftp-glob.h"#include "sftp-client.h"#include "sftp-int.h"/* File to read commands from */extern FILE *infile;/* Size of buffer used when copying files */extern size_t copy_buffer_len;/* Number of concurrent outstanding requests */extern int num_requests;/* Seperators for interactive commands */#define WHITESPACE " \t\r\n"/* Commands for interactive mode */#define I_CHDIR 1#define I_CHGRP 2#define I_CHMOD 3#define I_CHOWN 4#define I_GET 5#define I_HELP 6#define I_LCHDIR 7#define I_LLS 8#define I_LMKDIR 9#define I_LPWD 10#define I_LS 11#define I_LUMASK 12#define I_MKDIR 13#define I_PUT 14#define I_PWD 15#define I_QUIT 16#define I_RENAME 17#define I_RM 18#define I_RMDIR 19#define I_SHELL 20#define I_SYMLINK 21#define I_VERSION 22struct CMD { const char *c; const int n;};const struct CMD cmds[] = { { "bye", I_QUIT }, { "cd", I_CHDIR }, { "chdir", I_CHDIR }, { "chgrp", I_CHGRP }, { "chmod", I_CHMOD }, { "chown", I_CHOWN }, { "dir", I_LS }, { "exit", I_QUIT }, { "get", I_GET }, { "mget", I_GET }, { "help", I_HELP }, { "lcd", I_LCHDIR }, { "lchdir", I_LCHDIR }, { "lls", I_LLS }, { "lmkdir", I_LMKDIR }, { "ln", I_SYMLINK }, { "lpwd", I_LPWD }, { "ls", I_LS }, { "lumask", I_LUMASK }, { "mkdir", I_MKDIR }, { "put", I_PUT }, { "mput", I_PUT }, { "pwd", I_PWD }, { "quit", I_QUIT }, { "rename", I_RENAME }, { "rm", I_RM }, { "rmdir", I_RMDIR }, { "symlink", I_SYMLINK }, { "version", I_VERSION }, { "!", I_SHELL }, { "?", I_HELP }, { NULL, -1}};static voidhelp(void){ printf("Available commands:\n"); printf("cd path Change remote directory to 'path'\n"); printf("lcd path Change local directory to 'path'\n"); printf("chgrp grp path Change group of file 'path' to 'grp'\n"); printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); printf("chown own path Change owner of file 'path' to 'own'\n"); printf("help Display this help text\n"); printf("get remote-path [local-path] Download file\n"); printf("lls [ls-options [path]] Display local directory listing\n"); printf("ln oldpath newpath Symlink remote file\n"); printf("lmkdir path Create local directory\n"); printf("lpwd Print local working directory\n"); printf("ls [path] Display remote directory listing\n"); printf("lumask umask Set local umask to 'umask'\n"); printf("mkdir path Create remote directory\n"); printf("put local-path [remote-path] Upload file\n"); printf("pwd Display remote working directory\n"); printf("exit Quit sftp\n"); printf("quit Quit sftp\n"); printf("rename oldpath newpath Rename remote file\n"); printf("rmdir path Remove remote directory\n"); printf("rm path Delete remote file\n"); printf("symlink oldpath newpath Symlink remote file\n"); printf("version Show SFTP version\n"); printf("!command Execute 'command' in local shell\n"); printf("! Escape to local shell\n"); printf("? Synonym for help\n");}static voidlocal_do_shell(const char *args){ int status; char *shell; pid_t pid; if (!*args) args = NULL; if ((shell = getenv("SHELL")) == NULL) shell = _PATH_BSHELL; if ((pid = fork()) == -1) fatal("Couldn't fork: %s", strerror(errno)); if (pid == 0) { /* XXX: child has pipe fds to ssh subproc open - issue? */ if (args) { debug3("Executing %s -c \"%s\"", shell, args); execl(shell, shell, "-c", args, (char *)NULL); } else { debug3("Executing %s", shell); execl(shell, shell, (char *)NULL); } fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, strerror(errno)); _exit(1); } while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for child: %s", strerror(errno)); if (!WIFEXITED(status)) error("Shell exited abormally"); else if (WEXITSTATUS(status)) error("Shell exited with status %d", WEXITSTATUS(status));}static voidlocal_do_ls(const char *args){ if (!args || !*args) local_do_shell(_PATH_LS); else { int len = strlen(_PATH_LS " ") + strlen(args) + 1; char *buf = xmalloc(len); /* XXX: quoting - rip quoting code from ftp? */ snprintf(buf, len, _PATH_LS " %s", args); local_do_shell(buf); xfree(buf); }}static char *path_append(char *p1, char *p2){ char *ret; int len = strlen(p1) + strlen(p2) + 2; ret = xmalloc(len); strlcpy(ret, p1, len); if (strcmp(p1, "/") != 0) strlcat(ret, "/", len); strlcat(ret, p2, len); return(ret);}static char *make_absolute(char *p, char *pwd){ char *abs; /* Derelativise */ if (p && p[0] != '/') { abs = path_append(pwd, p); xfree(p); return(abs); } else return(p);}static intinfer_path(const char *p, char **ifp){ char *cp; cp = strrchr(p, '/'); if (cp == NULL) { *ifp = xstrdup(p); return(0); } if (!cp[1]) { error("Invalid path"); return(-1); } *ifp = xstrdup(cp + 1); return(0);}static intparse_getput_flags(const char **cpp, int *pflag){ const char *cp = *cpp; /* Check for flags */ if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { switch (cp[1]) { case 'p': case 'P': *pflag = 1; break; default: error("Invalid flag -%c", cp[1]); return(-1); } cp += 2; *cpp = cp + strspn(cp, WHITESPACE); } return(0);}static intget_pathname(const char **cpp, char **path){ const char *cp = *cpp, *end; char quot; int i; cp += strspn(cp, WHITESPACE); if (!*cp) { *cpp = cp; *path = NULL; return (0); } /* Check for quoted filenames */ if (*cp == '\"' || *cp == '\'') { quot = *cp++; end = strchr(cp, quot); if (end == NULL) { error("Unterminated quote"); goto fail; } if (cp == end) { error("Empty quotes"); goto fail; } *cpp = end + 1 + strspn(end + 1, WHITESPACE); } else { /* Read to end of filename */ end = strpbrk(cp, WHITESPACE); if (end == NULL) end = strchr(cp, '\0'); *cpp = end + strspn(end, WHITESPACE); } i = end - cp; *path = xmalloc(i + 1); memcpy(*path, cp, i); (*path)[i] = '\0'; return(0); fail: *path = NULL; return (-1);}static intis_dir(char *path){ struct stat sb; /* XXX: report errors? */ if (stat(path, &sb) == -1) return(0); return(sb.st_mode & S_IFDIR);}static intremote_is_dir(struct sftp_conn *conn, char *path){ Attrib *a; /* XXX: report errors? */ if ((a = do_stat(conn, path, 1)) == NULL) return(0); if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) return(0); return(a->perm & S_IFDIR);}static intprocess_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag){ char *abs_src = NULL; char *abs_dst = NULL; char *tmp; glob_t g; int err = 0; int i; abs_src = xstrdup(src); abs_src = make_absolute(abs_src, pwd); memset(&g, 0, sizeof(g)); debug3("Looking up %s", abs_src); if (remote_glob(conn, abs_src, 0, NULL, &g)) { error("File \"%s\" not found.", abs_src); err = -1; goto out; } /* Only one match, dst may be file, directory or unspecified */ if (g.gl_pathv[0] && g.gl_matchc == 1) { if (dst) { /* If directory specified, append filename */ if (is_dir(dst)) { if (infer_path(g.gl_pathv[0], &tmp)) { err = 1; goto out; } abs_dst = path_append(dst, tmp); xfree(tmp); } else abs_dst = xstrdup(dst); } else if (infer_path(g.gl_pathv[0], &abs_dst)) { err = -1; goto out; } printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); err = do_download(conn, g.gl_pathv[0], abs_dst, pflag); goto out; } /* Multiple matches, dst may be directory or unspecified */ if (dst && !is_dir(dst)) { error("Multiple files match, but \"%s\" is not a directory", dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i]; i++) { if (infer_path(g.gl_pathv[i], &tmp)) { err = -1; goto out; } if (dst) { abs_dst = path_append(dst, tmp); xfree(tmp); } else abs_dst = tmp; printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) err = -1; xfree(abs_dst); abs_dst = NULL; }out: xfree(abs_src); if (abs_dst) xfree(abs_dst); globfree(&g); return(err);}static intprocess_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag){ char *tmp_dst = NULL; char *abs_dst = NULL; char *tmp; glob_t g; int err = 0; int i; if (dst) { tmp_dst = xstrdup(dst); tmp_dst = make_absolute(tmp_dst, pwd); } memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); if (glob(src, 0, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; } /* Only one match, dst may be file, directory or unspecified */ if (g.gl_pathv[0] && g.gl_matchc == 1) { if (tmp_dst) { /* If directory specified, append filename */ if (remote_is_dir(conn, tmp_dst)) { if (infer_path(g.gl_pathv[0], &tmp)) { err = 1; goto out; } abs_dst = path_append(tmp_dst, tmp); xfree(tmp); } else abs_dst = xstrdup(tmp_dst); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -