⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sftp.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */#include "includes.h"RCSID("$OpenBSD: sftp.c,v 1.62 2005/02/20 22:59:06 djm Exp $");#ifdef USE_LIBEDIT#include <histedit.h>#elsetypedef void EditLine;#endif#include "buffer.h"#include "xmalloc.h"#include "log.h"#include "pathnames.h"#include "misc.h"#include "sftp.h"#include "sftp-common.h"#include "sftp-client.h"/* File to read commands from */FILE* infile;/* Are we in batchfile mode? */int batchmode = 0;/* Size of buffer used when copying files */size_t copy_buffer_len = 32768;/* Number of concurrent outstanding requests */size_t num_requests = 16;/* PID of ssh transport process */static pid_t sshpid = -1;/* This is set to 0 if the progressmeter is not desired. */int showprogress = 1;/* SIGINT received during command processing */volatile sig_atomic_t interrupted = 0;/* I wish qsort() took a separate ctx for the comparison function...*/int sort_flag;int remote_glob(struct sftp_conn *, const char *, int,    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */extern char *__progname;/* Separators for interactive commands */#define WHITESPACE " \t\r\n"/* ls flags */#define LS_LONG_VIEW	0x01	/* Full view ala ls -l */#define LS_SHORT_VIEW	0x02	/* Single row view ala ls -1 */#define LS_NUMERIC_VIEW	0x04	/* Long view with numeric uid/gid */#define LS_NAME_SORT	0x08	/* Sort by name (default) */#define LS_TIME_SORT	0x10	/* Sort by mtime */#define LS_SIZE_SORT	0x20	/* Sort by file size */#define LS_REVERSE_SORT	0x40	/* Reverse sort order */#define LS_SHOW_ALL	0x80	/* Don't skip filenames starting with '.' */#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW)#define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)/* 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	22#define I_PROGRESS	23struct CMD {	const char *c;	const int n;};static 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 },	{ "progress",	I_PROGRESS },	{ "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}};int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);static voidkillchild(int signo){	if (sshpid > 1) {		kill(sshpid, SIGTERM);		waitpid(sshpid, NULL, 0);	}	_exit(1);}static voidcmd_interrupt(int signo){	const char msg[] = "\rInterrupt  \n";	int olderrno = errno;	write(STDERR_FILENO, msg, sizeof(msg) - 1);	interrupted = 1;	errno = olderrno;}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("progress                      Toggle display of progress meter\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);	}}/* Strip one path (usually the pwd) from the start of another */static char *path_strip(char *path, char *strip){	size_t len;	if (strip == NULL)		return (xstrdup(path));	len = strlen(strip);	if (strncmp(path, strip, len) == 0) {		if (strip[len - 1] != '/' && path[len] == '/')			len++;		return (xstrdup(path + len));	}	return (xstrdup(path));}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 (p1[strlen(p1) - 1] != '/')		strlcat(ret, "/", len);	strlcat(ret, p2, len);	return(ret);}static char *make_absolute(char *p, char *pwd){	char *abs_str;	/* Derelativise */	if (p && p[0] != '/') {		abs_str = path_append(pwd, p);		xfree(p);		return(abs_str);	} 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 intparse_ls_flags(const char **cpp, int *lflag){	const char *cp = *cpp;	/* Defaults */	*lflag = LS_NAME_SORT;	/* Check for flags */	if (cp++[0] == '-') {		for(; strchr(WHITESPACE, *cp) == NULL; cp++) {			switch (*cp) {			case 'l':				*lflag &= ~VIEW_FLAGS;				*lflag |= LS_LONG_VIEW;				break;			case '1':				*lflag &= ~VIEW_FLAGS;				*lflag |= LS_SHORT_VIEW;				break;			case 'n':				*lflag &= ~VIEW_FLAGS;				*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;				break;			case 'S':				*lflag &= ~SORT_FLAGS;				*lflag |= LS_SIZE_SORT;				break;			case 't':				*lflag &= ~SORT_FLAGS;				*lflag |= LS_TIME_SORT;				break;			case 'r':				*lflag |= LS_REVERSE_SORT;				break;			case 'f':				*lflag &= ~SORT_FLAGS;				break;			case 'a':				*lflag |= LS_SHOW_ALL;				break;			default:				error("Invalid flag -%c", *cp);				return(-1);			}		}		*cpp = cp + strspn(cp, WHITESPACE);	}	return(0);}static intget_pathname(const char **cpp, char **path){	const char *cp = *cpp, *end;	char quot;	int i, j;	cp += strspn(cp, WHITESPACE);	if (!*cp) {		*cpp = cp;		*path = NULL;		return (0);	}	*path = xmalloc(strlen(cp) + 1);	/* Check for quoted filenames */	if (*cp == '\"' || *cp == '\'') {		quot = *cp++;		/* Search for terminating quote, unescape some chars */		for (i = j = 0; i <= strlen(cp); i++) {			if (cp[i] == quot) {	/* Found quote */				i++;				(*path)[j] = '\0';				break;			}			if (cp[i] == '\0') {	/* End of string */				error("Unterminated quote");				goto fail;			}			if (cp[i] == '\\') {	/* Escaped characters */				i++;				if (cp[i] != '\'' && cp[i] != '\"' &&				    cp[i] != '\\') {					error("Bad escaped character '\\%c'",					    cp[i]);					goto fail;				}			}			(*path)[j++] = cp[i];		}		if (j == 0) {			error("Empty quotes");			goto fail;		}		*cpp = cp + i + strspn(cp + i, WHITESPACE);	} else {		/* Read to end of filename */		end = strpbrk(cp, WHITESPACE);		if (end == NULL)			end = strchr(cp, '\0');		*cpp = end + strspn(end, WHITESPACE);		memcpy(*path, cp, end - cp);		(*path)[end - cp] = '\0';	}	return (0); fail:	xfree(*path);	*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 intis_reg(char *path){	struct stat sb;	if (stat(path, &sb) == -1)		fatal("stat %s: %s", path, strerror(errno));	return(S_ISREG(sb.st_mode));}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;	}	/* If multiple matches, dst must be a directory or unspecified */	if (g.gl_matchc > 1 && dst && !is_dir(dst)) {		error("Multiple files match, but \"%s\" is not a directory",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -