]> andersk Git - openssh.git/blobdiff - sftp-client.c
- djm@cvs.openbsd.org 2001/03/16 08:16:18
[openssh.git] / sftp-client.c
index e4282384147fea5e906cf3df401c3e81c10d02b9..b0007a7345c56bb54b8877f007710636cfb81825 100644 (file)
@@ -29,7 +29,7 @@
 /* XXX: copy between two remote sites */
 
 #include "includes.h"
-RCSID("$OpenBSD: sftp-client.c,v 1.3 2001/02/04 15:32:25 stevesk Exp $");
+RCSID("$OpenBSD: sftp-client.c,v 1.14 2001/03/16 08:16:17 djm Exp $");
 
 #include "ssh.h"
 #include "buffer.h"
@@ -48,6 +48,9 @@ RCSID("$OpenBSD: sftp-client.c,v 1.3 2001/02/04 15:32:25 stevesk Exp $");
 /* XXX: what should this be? */
 #define COPY_SIZE      8192
 
+/* Message ID */
+static u_int msg_id = 1;
+
 void
 send_msg(int fd, Buffer *m)
 {
@@ -177,7 +180,7 @@ get_handle(int fd, u_int expected_id, u_int *len)
 }
 
 Attrib *
-get_decode_stat(int fd, u_int expected_id)
+get_decode_stat(int fd, u_int expected_id, int quiet)
 {
        Buffer msg;
        u_int type, id;
@@ -195,7 +198,10 @@ get_decode_stat(int fd, u_int expected_id)
        if (type == SSH2_FXP_STATUS) {
                int status = buffer_get_int(&msg);
 
-               error("Couldn't stat remote file: %s", fx2txt(status));
+               if (quiet)
+                       debug("Couldn't stat remote file: %s", fx2txt(status));
+               else
+                       error("Couldn't stat remote file: %s", fx2txt(status));
                return(NULL);
        } else if (type != SSH2_FXP_ATTRS) {
                fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
@@ -244,7 +250,8 @@ do_init(int fd_in, int fd_out)
        }
 
        buffer_free(&msg);
-       return(0);
+
+       return(version);
 }
 
 int
@@ -255,7 +262,7 @@ do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
 
        buffer_init(&msg);
 
-       id = arc4random();
+       id = msg_id++;
        buffer_put_char(&msg, SSH2_FXP_CLOSE);
        buffer_put_int(&msg, id);
        buffer_put_string(&msg, handle, handle_len);
@@ -271,14 +278,16 @@ do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
        return(status);
 }
 
+
 int
-do_ls(int fd_in, int fd_out, char *path)
+do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, 
+    SFTP_DIRENT ***dir)
 {
        Buffer msg;
-       u_int type, id, handle_len, i, expected_id;
+       u_int type, id, handle_len, i, expected_id, ents = 0;
        char *handle;
 
-       id = arc4random();
+       id = msg_id++;
 
        buffer_init(&msg);
        buffer_put_char(&msg, SSH2_FXP_OPENDIR);
@@ -292,10 +301,17 @@ do_ls(int fd_in, int fd_out, char *path)
        if (handle == NULL)
                return(-1);
 
+       if (dir) {
+               ents = 0;
+               *dir = xmalloc(sizeof(**dir));
+               (*dir)[0] = NULL;
+       }
+       
+
        for(;;) {
                int count;
 
-               expected_id = ++id;
+               id = expected_id = msg_id++;
 
                debug3("Sending SSH2_FXP_READDIR I:%d", id);
 
@@ -328,14 +344,16 @@ do_ls(int fd_in, int fd_out, char *path)
                                error("Couldn't read directory: %s",
                                    fx2txt(status));
                                do_close(fd_in, fd_out, handle, handle_len);
-                               return(NULL);
+                               return(status);
                        }
                } else if (type != SSH2_FXP_NAME)
                        fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                            SSH2_FXP_NAME, type);
 
                count = buffer_get_int(&msg);
-               debug3("Received %i SSH2_FXP_NAME responses", count);
+               if (count == 0)
+                       break;
+               debug3("Received %d SSH2_FXP_NAME responses", count);
                for(i = 0; i < count; i++) {
                        char *filename, *longname;
                        Attrib *a;
@@ -344,7 +362,18 @@ do_ls(int fd_in, int fd_out, char *path)
                        longname = buffer_get_string(&msg, NULL);
                        a = decode_attrib(&msg);
 
-                       printf("%s\n", longname);
+                       if (printflag)
+                               printf("%s\n", longname);
+
+                       if (dir) {
+                               *dir = xrealloc(*dir, sizeof(**dir) * 
+                                   (ents + 2));
+                               (*dir)[ents] = xmalloc(sizeof(***dir));
+                               (*dir)[ents]->filename = xstrdup(filename);
+                               (*dir)[ents]->longname = xstrdup(longname);
+                               memcpy(&(*dir)[ents]->a, a, sizeof(*a));
+                               (*dir)[++ents] = NULL;
+                       }
 
                        xfree(filename);
                        xfree(longname);
@@ -358,6 +387,30 @@ do_ls(int fd_in, int fd_out, char *path)
        return(0);
 }
 
+int
+do_ls(int fd_in, int fd_out, char *path)
+{
+       return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
+}
+
+int
+do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
+{
+       return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
+}
+
+void free_sftp_dirents(SFTP_DIRENT **s)
+{
+       int i;
+       
+       for(i = 0; s[i]; i++) {
+               xfree(s[i]->filename);
+               xfree(s[i]->longname);
+               xfree(s[i]);
+       }
+       xfree(s);
+}
+
 int
 do_rm(int fd_in, int fd_out, char *path)
 {
@@ -365,7 +418,7 @@ do_rm(int fd_in, int fd_out, char *path)
 
        debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
 
-       id = arc4random();
+       id = msg_id++;
        send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
        status = get_status(fd_in, id);
        if (status != SSH2_FX_OK)
@@ -378,7 +431,7 @@ do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
 {
        u_int status, id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
            strlen(path), a);
 
@@ -394,7 +447,7 @@ do_rmdir(int fd_in, int fd_out, char *path)
 {
        u_int status, id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
 
        status = get_status(fd_in, id);
@@ -405,34 +458,33 @@ do_rmdir(int fd_in, int fd_out, char *path)
 }
 
 Attrib *
-do_stat(int fd_in, int fd_out, char *path)
+do_stat(int fd_in, int fd_out, char *path, int quiet)
 {
        u_int id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
-       return(get_decode_stat(fd_in, id));
+       return(get_decode_stat(fd_in, id, quiet));
 }
 
 Attrib *
-do_lstat(int fd_in, int fd_out, char *path)
+do_lstat(int fd_in, int fd_out, char *path, int quiet)
 {
        u_int id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
-       return(get_decode_stat(fd_in, id));
+       return(get_decode_stat(fd_in, id, quiet));
 }
 
 Attrib *
-do_fstat(int fd_in, int fd_out, char *handle,
-    u_int handle_len)
+do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
 {
        u_int id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
-       return(get_decode_stat(fd_in, id));
+       return(get_decode_stat(fd_in, id, quiet));
 }
 
 int
@@ -440,7 +492,7 @@ do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
 {
        u_int status, id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
            strlen(path), a);
 
@@ -458,7 +510,7 @@ do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
 {
        u_int status, id;
 
-       id = arc4random();
+       id = msg_id++;
        send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
            handle_len, a);
 
@@ -477,9 +529,8 @@ do_realpath(int fd_in, int fd_out, char *path)
        char *filename, *longname;
        Attrib *a;
 
-       expected_id = id = arc4random();
-       send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
-           strlen(path));
+       expected_id = id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
 
        buffer_init(&msg);
 
@@ -525,7 +576,7 @@ do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
        buffer_init(&msg);
 
        /* Send rename request */
-       id = arc4random();
+       id = msg_id++;
        buffer_put_char(&msg, SSH2_FXP_RENAME);
        buffer_put_int(&msg, id);
        buffer_put_cstring(&msg, oldpath);
@@ -543,6 +594,79 @@ do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
        return(status);
 }
 
+int
+do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       buffer_init(&msg);
+
+       /* Send rename request */
+       id = msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_SYMLINK);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, oldpath);
+       buffer_put_cstring(&msg, newpath);
+       send_msg(fd_out, &msg);
+       debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
+           newpath);
+       buffer_free(&msg);
+
+       status = get_status(fd_in, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
+                   fx2txt(status));
+
+       return(status);
+}
+
+char *
+do_readlink(int fd_in, int fd_out, char *path)
+{
+       Buffer msg;
+       u_int type, expected_id, count, id;
+       char *filename, *longname;
+       Attrib *a;
+
+       expected_id = id = msg_id++;
+       send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
+
+       buffer_init(&msg);
+
+       get_msg(fd_in, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%d != %d)", id, expected_id);
+
+       if (type == SSH2_FXP_STATUS) {
+               u_int status = buffer_get_int(&msg);
+
+               error("Couldn't readlink: %s", fx2txt(status));
+               return(NULL);
+       } else if (type != SSH2_FXP_NAME)
+               fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
+                   SSH2_FXP_NAME, type);
+
+       count = buffer_get_int(&msg);
+       if (count != 1)
+               fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
+
+       filename = buffer_get_string(&msg, NULL);
+       longname = buffer_get_string(&msg, NULL);
+       a = decode_attrib(&msg);
+
+       debug3("SSH_FXP_READLINK %s -> %s", path, filename);
+
+       xfree(longname);
+
+       buffer_free(&msg);
+
+       return(filename);
+}
+
 int
 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
     int pflag)
@@ -553,8 +677,9 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
        char *handle;
        Buffer msg;
        Attrib junk, *a;
+       int status;
 
-       a = do_stat(fd_in, fd_out, remote_path);
+       a = do_stat(fd_in, fd_out, remote_path, 0);
        if (a == NULL)
                return(-1);
 
@@ -564,31 +689,23 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
        else
                mode = 0666;
 
+       if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+           (a->perm & S_IFDIR)) {
+               error("Cannot download a directory: %s", remote_path);
+               return(-1);
+       }
+
        local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
        if (local_fd == -1) {
                error("Couldn't open local file \"%s\" for writing: %s",
                    local_path, strerror(errno));
-               return(errno);
-       }
-
-       /* Override umask and utimes if asked */
-       if (pflag && fchmod(local_fd, mode) == -1)
-               error("Couldn't set mode on \"%s\": %s", local_path,
-                   strerror(errno));
-       if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
-               struct timeval tv;
-
-               tv.tv_sec = a->atime;
-               tv.tv_usec = a->mtime;
-               if (utimes(local_path, &tv) == -1)
-                       error("Can't set times on \"%s\": %s", local_path,
-                           strerror(errno));
+               return(-1);
        }
 
        buffer_init(&msg);
 
        /* Send open request */
-       id = arc4random();
+       id = msg_id++;
        buffer_put_char(&msg, SSH2_FXP_OPEN);
        buffer_put_int(&msg, id);
        buffer_put_cstring(&msg, remote_path);
@@ -611,7 +728,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                u_int len;
                char *data;
 
-               expected_id = ++id;
+               id = expected_id = msg_id++;
 
                buffer_clear(&msg);
                buffer_put_char(&msg, SSH2_FXP_READ);
@@ -621,7 +738,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                buffer_put_int(&msg, COPY_SIZE);
                send_msg(fd_out, &msg);
                debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
-                   id, (unsigned long long)offset, COPY_SIZE);
+                   id, (u_int64_t)offset, COPY_SIZE);
 
                buffer_clear(&msg);
 
@@ -632,7 +749,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                if (id != expected_id)
                        fatal("ID mismatch (%d != %d)", id, expected_id);
                if (type == SSH2_FXP_STATUS) {
-                       int status = buffer_get_int(&msg);
+                       status = buffer_get_int(&msg);
 
                        if (status == SSH2_FX_EOF)
                                break;
@@ -641,10 +758,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                                    "file \"%s\" : %s", remote_path,
                                     fx2txt(status));
                                do_close(fd_in, fd_out, handle, handle_len);
-                               xfree(handle);
-                               close(local_fd);
-                               buffer_free(&msg);
-                               return(status);
+                               goto done;
                        }
                } else if (type != SSH2_FXP_DATA) {
                        fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
@@ -656,27 +770,45 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                        fatal("Received more data than asked for %d > %d",
                            len, COPY_SIZE);
 
-               debug3("In read loop, got %d offset %lld", len,
-                   (unsigned long long)offset);
+               debug3("In read loop, got %d offset %llu", len,
+                   (u_int64_t)offset);
                if (atomicio(write, local_fd, data, len) != len) {
                        error("Couldn't write to \"%s\": %s", local_path,
                            strerror(errno));
                        do_close(fd_in, fd_out, handle, handle_len);
-                       xfree(handle);
-                       close(local_fd);
+                       status = -1;
                        xfree(data);
-                       buffer_free(&msg);
-                       return(-1);
+                       goto done;
                }
 
                offset += len;
                xfree(data);
        }
-       xfree(handle);
-       buffer_free(&msg);
-       close(local_fd);
+       status = do_close(fd_in, fd_out, handle, handle_len);
 
-       return(do_close(fd_in, fd_out, handle, handle_len));
+       /* Override umask and utimes if asked */
+#ifdef HAVE_FCHMOD
+       if (pflag && fchmod(local_fd, mode) == -1)
+#else 
+       if (pflag && chmod(local_path, mode) == -1)
+#endif /* HAVE_FCHMOD */
+               error("Couldn't set mode on \"%s\": %s", local_path,
+                   strerror(errno));
+       if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
+               struct timeval tv[2];
+               tv[0].tv_sec = a->atime;
+               tv[1].tv_sec = a->mtime;
+               tv[0].tv_usec = tv[1].tv_usec = 0;
+               if (utimes(local_path, tv) == -1)
+                       error("Can't set times on \"%s\": %s", local_path,
+                           strerror(errno));
+       }
+
+done:
+       close(local_fd);
+       buffer_free(&msg);
+       xfree(handle);
+       return status;
 }
 
 int
@@ -690,6 +822,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
        Buffer msg;
        struct stat sb;
        Attrib a;
+       int status;
 
        if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
                error("Couldn't open local file \"%s\" for reading: %s",
@@ -713,7 +846,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
        buffer_init(&msg);
 
        /* Send open request */
-       id = arc4random();
+       id = msg_id++;
        buffer_put_char(&msg, SSH2_FXP_OPEN);
        buffer_put_int(&msg, id);
        buffer_put_cstring(&msg, remote_path);
@@ -731,16 +864,11 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
                return(-1);
        }
 
-       /* Override umask and utimes if asked */
-       if (pflag)
-               do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
-
        /* Read from local and write to remote */
        offset = 0;
        for(;;) {
                int len;
                char data[COPY_SIZE];
-               u_int status;
 
                /*
                 * Can't use atomicio here because it returns 0 on EOF, thus losing
@@ -764,31 +892,39 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
                buffer_put_string(&msg, data, len);
                send_msg(fd_out, &msg);
                debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
-                   id, (unsigned long long)offset, len);
+                   id, (u_int64_t)offset, len);
 
                status = get_status(fd_in, id);
                if (status != SSH2_FX_OK) {
                        error("Couldn't write to remote file \"%s\": %s",
                            remote_path, fx2txt(status));
                        do_close(fd_in, fd_out, handle, handle_len);
-                       xfree(handle);
                        close(local_fd);
-                       return(-1);
+                       goto done;
                }
                debug3("In write loop, got %d offset %llu", len,
-                   (unsigned long long)offset);
+                   (u_int64_t)offset);
 
                offset += len;
        }
-       xfree(handle);
-       buffer_free(&msg);
 
        if (close(local_fd) == -1) {
                error("Couldn't close local file \"%s\": %s", local_path,
                    strerror(errno));
                do_close(fd_in, fd_out, handle, handle_len);
-               return(-1);
+               status = -1;
+               goto done;
        }
 
-       return(do_close(fd_in, fd_out, handle, handle_len));
+       /* Override umask and utimes if asked */
+       if (pflag)
+               do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
+
+       status = do_close(fd_in, fd_out, handle, handle_len);
+
+done:
+       xfree(handle);
+       buffer_free(&msg);
+       return status;
 }
+
This page took 0.06099 seconds and 4 git commands to generate.