📄 sftp.c
字号:
break; case I_MKDIR: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; err = do_mkdir(conn, path1, &a); break; case I_RMDIR: path1 = make_absolute(path1, *pwd); err = do_rmdir(conn, path1); break; case I_CHDIR: path1 = make_absolute(path1, *pwd); if ((tmp = do_realpath(conn, path1)) == NULL) { err = 1; break; } if ((aa = do_stat(conn, tmp, 0)) == NULL) { xfree(tmp); err = 1; break; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); xfree(tmp); err = 1; break; } if (!S_ISDIR(aa->perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); xfree(tmp); err = 1; break; } xfree(*pwd); *pwd = tmp; break; case I_LS: if (!path1) { do_globbed_ls(conn, *pwd, *pwd, lflag); break; } /* Strip pwd off beginning of non-absolute paths */ tmp = NULL; if (*path1 != '/') tmp = *pwd; path1 = make_absolute(path1, *pwd); err = do_globbed_ls(conn, path1, tmp, lflag); break; case I_LCHDIR: if (chdir(path1) == -1) { error("Couldn't change local directory to " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LMKDIR: if (mkdir(path1, 0777) == -1) { error("Couldn't create local directory " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LLS: local_do_ls(cmd); break; case I_SHELL: local_do_shell(cmd); break; case I_LUMASK: umask(n_arg); printf("Local umask: %03lo\n", n_arg); break; case I_CHMOD: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = n_arg; remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { printf("Changing mode on %s\n", g.gl_pathv[i]); err = do_setstat(conn, g.gl_pathv[i], &a); if (err != 0 && err_abort) break; } break; case I_CHOWN: case I_CHGRP: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { if (err != 0 && err_abort) break; else continue; } if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); if (err != 0 && err_abort) break; else continue; } aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; if (cmdnum == I_CHOWN) { printf("Changing owner on %s\n", g.gl_pathv[i]); aa->uid = n_arg; } else { printf("Changing group on %s\n", g.gl_pathv[i]); aa->gid = n_arg; } err = do_setstat(conn, g.gl_pathv[i], aa); if (err != 0 && err_abort) break; } break; case I_PWD: printf("Remote working directory: %s\n", *pwd); break; case I_LPWD: if (!getcwd(path_buf, sizeof(path_buf))) { error("Couldn't get local cwd: %s", strerror(errno)); err = -1; break; } printf("Local working directory: %s\n", path_buf); break; case I_QUIT: /* Processed below */ break; case I_HELP: help(); break; case I_VERSION: printf("SFTP protocol version %u\n", sftp_proto_version(conn)); break; case I_PROGRESS: showprogress = !showprogress; if (showprogress) printf("Progress meter enabled\n"); else printf("Progress meter disabled\n"); break; default: fatal("%d is not implemented", cmdnum); } if (g.gl_pathc) globfree(&g); if (path1) xfree(path1); if (path2) xfree(path2); /* If an unignored error occurs in batch mode we should abort. */ if (err_abort && err != 0) return (-1); else if (cmdnum == I_QUIT) return (1); return (0);}#ifdef USE_LIBEDITstatic char *prompt(EditLine *el){ return ("sftp> ");}#endifintinteractive_loop(int fd_in, int fd_out, char *file1, char *file2){ char *pwd; char *dir = NULL; char cmd[2048]; struct sftp_conn *conn; int err; EditLine *el = NULL;#ifdef USE_LIBEDIT History *hl = NULL; HistEvent hev; extern char *__progname; if (!batchmode && isatty(STDIN_FILENO)) { if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) fatal("Couldn't initialise editline"); if ((hl = history_init()) == NULL) fatal("Couldn't initialise editline history"); history(hl, &hev, H_SETSIZE, 100); el_set(el, EL_HIST, history, hl); el_set(el, EL_PROMPT, prompt); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_TERMINAL, NULL); el_set(el, EL_SIGNAL, 1); el_source(el, NULL); }#endif /* USE_LIBEDIT */ conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); if (conn == NULL) fatal("Couldn't initialise connection to server"); pwd = do_realpath(conn, "."); if (pwd == NULL) fatal("Need cwd"); if (file1 != NULL) { dir = xstrdup(file1); dir = make_absolute(dir, pwd); if (remote_is_dir(conn, dir) && file2 == NULL) { printf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { xfree(dir); xfree(pwd); return (-1); } } else { if (file2 == NULL) snprintf(cmd, sizeof cmd, "get %s", dir); else snprintf(cmd, sizeof cmd, "get %s %s", dir, file2); err = parse_dispatch_command(conn, cmd, &pwd, 1); xfree(dir); xfree(pwd); return (err); } xfree(dir); }#if HAVE_SETVBUF setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0);#else setlinebuf(stdout); setlinebuf(infile);#endif err = 0; for (;;) { char *cp; signal(SIGINT, SIG_IGN); if (el == NULL) { printf("sftp> "); if (fgets(cmd, sizeof(cmd), infile) == NULL) { printf("\n"); break; } if (batchmode) /* Echo command */ printf("%s", cmd); } else {#ifdef USE_LIBEDIT const char *line; int count = 0; if ((line = el_gets(el, &count)) == NULL || count <= 0) break; history(hl, &hev, H_ENTER, line); if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { fprintf(stderr, "Error: input line too long\n"); continue; }#endif /* USE_LIBEDIT */ } cp = strrchr(cmd, '\n'); if (cp) *cp = '\0'; /* Handle user interrupts gracefully during commands */ interrupted = 0; signal(SIGINT, cmd_interrupt); err = parse_dispatch_command(conn, cmd, &pwd, batchmode); if (err != 0) break; } xfree(pwd); /* err == 1 signifies normal "quit" exit */ return (err >= 0 ? 0 : -1);}static voidconnect_to_server(char *path, char **args, int *in, int *out){ int c_in, c_out;#ifdef USE_PIPES int pin[2], pout[2]; if ((pipe(pin) == -1) || (pipe(pout) == -1)) fatal("pipe: %s", strerror(errno)); *in = pin[0]; *out = pout[1]; c_in = pout[0]; c_out = pin[1];#else /* USE_PIPES */ int inout[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) fatal("socketpair: %s", strerror(errno)); *in = *out = inout[0]; c_in = c_out = inout[1];#endif /* USE_PIPES */ if ((sshpid = fork()) == -1) fatal("fork: %s", strerror(errno)); else if (sshpid == 0) { if ((dup2(c_in, STDIN_FILENO) == -1) || (dup2(c_out, STDOUT_FILENO) == -1)) { fprintf(stderr, "dup2: %s\n", strerror(errno)); _exit(1); } close(*in); close(*out); close(c_in); close(c_out); /* * The underlying ssh is in the same process group, so we must * ignore SIGINT if we want to gracefully abort commands, * otherwise the signal will make it to the ssh process and * kill it too */ signal(SIGINT, SIG_IGN); execvp(path, args); fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); _exit(1); } signal(SIGTERM, killchild); signal(SIGINT, killchild); signal(SIGHUP, killchild); close(c_in); close(c_out);}static voidusage(void){ extern char *__progname; fprintf(stderr, "usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n" " [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n" " [-S program] [-s subsystem | sftp_server] host\n" " %s [[user@]host[:file [file]]]\n" " %s [[user@]host[:dir[/]]]\n" " %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname); exit(1);}intmain(int argc, char **argv){ int in, out, ch, err; char *host, *userhost, *cp, *file2 = NULL; int debug_level = 0, sshver = 2; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; LogLevel ll = SYSLOG_LEVEL_INFO; arglist args; extern int optind; extern char *optarg; __progname = ssh_get_progname(argv[0]); args.list = NULL; addargs(&args, "ssh"); /* overwritten with ssh_program */ addargs(&args, "-oForwardX11 no"); addargs(&args, "-oForwardAgent no"); addargs(&args, "-oClearAllForwardings yes"); ll = SYSLOG_LEVEL_INFO; infile = stdin; while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { switch (ch) { case 'C': addargs(&args, "-C"); break; case 'v': if (debug_level < 3) { addargs(&args, "-v"); ll = SYSLOG_LEVEL_DEBUG1 + debug_level; } debug_level++; break; case 'F': case 'o': addargs(&args, "-%c%s", ch, optarg); break; case '1': sshver = 1; if (sftp_server == NULL) sftp_server = _PATH_SFTP_SERVER; break; case 's': sftp_server = optarg; break; case 'S': ssh_program = optarg; break; case 'b': if (batchmode) fatal("Batch file already specified."); /* Allow "-" as stdin */ if (strcmp(optarg, "-") != 0 && (infile = fopen(optarg, "r")) == NULL) fatal("%s (%s).", strerror(errno), optarg); showprogress = 0; batchmode = 1; addargs(&args, "-obatchmode yes"); break; case 'P': sftp_direct = optarg; break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') fatal("Invalid buffer size \"%s\"", optarg); break; case 'R': num_requests = strtol(optarg, &cp, 10); if (num_requests == 0 || *cp != '\0') fatal("Invalid number of requests \"%s\"", optarg); break; case 'h': default: usage(); } } if (!isatty(STDERR_FILENO)) showprogress = 0; log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); if (sftp_direct == NULL) { if (optind == argc || argc > (optind + 2)) usage(); userhost = xstrdup(argv[optind]); file2 = argv[optind+1]; if ((host = strrchr(userhost, '@')) == NULL) host = userhost; else { *host++ = '\0'; if (!userhost[0]) { fprintf(stderr, "Missing username\n"); usage(); } addargs(&args, "-l%s",userhost); } if ((cp = colon(host)) != NULL) { *cp++ = '\0'; file1 = cp; } host = cleanhostname(host); if (!*host) { fprintf(stderr, "Missing hostname\n"); usage(); } addargs(&args, "-oProtocol %d", sshver); /* no subsystem if the server-spec contains a '/' */ if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); args.list[0] = ssh_program; if (!batchmode) fprintf(stderr, "Connecting to %s...\n", host); connect_to_server(ssh_program, args.list, &in, &out); } else { args.list = NULL; addargs(&args, "sftp-server"); if (!batchmode) fprintf(stderr, "Attaching to %s...\n", sftp_direct); connect_to_server(sftp_direct, args.list, &in, &out); } err = interactive_loop(in, out, file1, file2);#if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); shutdown(out, SHUT_RDWR);#endif close(in); close(out); if (batchmode) fclose(infile); while (waitpid(sshpid, NULL, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for ssh process: %s", strerror(errno)); exit(err == 0 ? 0 : 1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -