Remove ghastly hack involving fxp_error_message.
[u/mdw/putty] / sftp.c
diff --git a/sftp.c b/sftp.c
index 4491349..78fbd32 100644 (file)
--- a/sftp.c
+++ b/sftp.c
@@ -7,13 +7,10 @@
 #include <string.h>
 #include <assert.h>
 
+#include "misc.h"
 #include "int64.h"
 #include "sftp.h"
 
-#define smalloc malloc
-#define srealloc realloc
-#define sfree free
-
 #define GET_32BIT(cp) \
     (((unsigned long)(unsigned char)(cp)[0] << 24) | \
     ((unsigned long)(unsigned char)(cp)[1] << 16) | \
@@ -65,7 +62,6 @@ static struct sftp_packet *sftp_pkt_init(int pkt_type)
     pkt->length = 0;
     pkt->maxlen = 0;
     sftp_pkt_addbyte(pkt, (unsigned char) pkt_type);
-    fxp_error_message = NULL;
     return pkt;
 }
 static void sftp_pkt_addbool(struct sftp_packet *pkt, unsigned char value)
@@ -107,6 +103,31 @@ static void sftp_pkt_addstring(struct sftp_packet *pkt, char *data)
     sftp_pkt_addstring_start(pkt);
     sftp_pkt_addstring_str(pkt, data);
 }
+static void sftp_pkt_addattrs(struct sftp_packet *pkt, struct fxp_attrs attrs)
+{
+    sftp_pkt_adduint32(pkt, attrs.flags);
+    if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
+       sftp_pkt_adduint32(pkt, attrs.size.hi);
+       sftp_pkt_adduint32(pkt, attrs.size.lo);
+    }
+    if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) {
+       sftp_pkt_adduint32(pkt, attrs.uid);
+       sftp_pkt_adduint32(pkt, attrs.gid);
+    }
+    if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
+       sftp_pkt_adduint32(pkt, attrs.permissions);
+    }
+    if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) {
+       sftp_pkt_adduint32(pkt, attrs.atime);
+       sftp_pkt_adduint32(pkt, attrs.mtime);
+    }
+    if (attrs.flags & SSH_FILEXFER_ATTR_EXTENDED) {
+       /*
+        * We currently don't support sending any extended
+        * attributes.
+        */
+    }
+}
 
 /* ----------------------------------------------------------------------
  * SFTP packet decode functions.
@@ -348,6 +369,10 @@ char *fxp_realpath(char *path)
     sftp_pkt_addstring_str(pktout, path);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return NULL;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x123) {
        fxp_internal_error("request ID mismatch\n");
@@ -392,6 +417,10 @@ struct fxp_handle *fxp_open(char *path, int type)
     sftp_pkt_adduint32(pktout, 0);     /* (FIXME) empty ATTRS structure */
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return NULL;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x567) {
        fxp_internal_error("request ID mismatch\n");
@@ -431,6 +460,10 @@ struct fxp_handle *fxp_opendir(char *path)
     sftp_pkt_addstring(pktout, path);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return NULL;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x456) {
        fxp_internal_error("request ID mismatch\n");
@@ -471,6 +504,10 @@ void fxp_close(struct fxp_handle *handle)
     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x789) {
        fxp_internal_error("request ID mismatch\n");
@@ -488,11 +525,14 @@ int fxp_mkdir(char *path)
 
     pktout = sftp_pkt_init(SSH_FXP_MKDIR);
     sftp_pkt_adduint32(pktout, 0x234); /* request id */
-    sftp_pkt_addstring_start(pktout);
-    sftp_pkt_addstring_data(pktout, path, strlen(path));
+    sftp_pkt_addstring(pktout, path);
     sftp_pkt_adduint32(pktout, 0);     /* (FIXME) empty ATTRS structure */
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x234) {
        fxp_internal_error("request ID mismatch\n");
@@ -512,10 +552,13 @@ int fxp_rmdir(char *path)
 
     pktout = sftp_pkt_init(SSH_FXP_RMDIR);
     sftp_pkt_adduint32(pktout, 0x345); /* request id */
-    sftp_pkt_addstring_start(pktout);
-    sftp_pkt_addstring_data(pktout, path, strlen(path));
+    sftp_pkt_addstring(pktout, path);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x345) {
        fxp_internal_error("request ID mismatch\n");
@@ -528,17 +571,167 @@ int fxp_rmdir(char *path)
     return 1;
 }
 
-int fxp_rm(char *fname)
+int fxp_remove(char *fname)
 {
     struct sftp_packet *pktin, *pktout;
     int id;
 
     pktout = sftp_pkt_init(SSH_FXP_REMOVE);
     sftp_pkt_adduint32(pktout, 0x678); /* request id */
+    sftp_pkt_addstring(pktout, fname);
+    sftp_send(pktout);
+    pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
+    id = sftp_pkt_getuint32(pktin);
+    if (id != 0x678) {
+       fxp_internal_error("request ID mismatch\n");
+       return 0;
+    }
+    id = fxp_got_status(pktin);
+    if (id != 1) {
+       return 0;
+    }
+    return 1;
+}
+
+int fxp_rename(char *srcfname, char *dstfname)
+{
+    struct sftp_packet *pktin, *pktout;
+    int id;
+
+    pktout = sftp_pkt_init(SSH_FXP_RENAME);
+    sftp_pkt_adduint32(pktout, 0x678); /* request id */
+    sftp_pkt_addstring(pktout, srcfname);
+    sftp_pkt_addstring(pktout, dstfname);
+    sftp_send(pktout);
+    pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
+    id = sftp_pkt_getuint32(pktin);
+    if (id != 0x678) {
+       fxp_internal_error("request ID mismatch\n");
+       return 0;
+    }
+    id = fxp_got_status(pktin);
+    if (id != 1) {
+       return 0;
+    }
+    return 1;
+}
+
+/*
+ * Retrieve the attributes of a file. We have fxp_stat which works
+ * on filenames, and fxp_fstat which works on open file handles.
+ */
+int fxp_stat(char *fname, struct fxp_attrs *attrs)
+{
+    struct sftp_packet *pktin, *pktout;
+    int id;
+
+    pktout = sftp_pkt_init(SSH_FXP_STAT);
+    sftp_pkt_adduint32(pktout, 0x678); /* request id */
+    sftp_pkt_addstring(pktout, fname);
+    sftp_send(pktout);
+    pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
+    id = sftp_pkt_getuint32(pktin);
+    if (id != 0x678) {
+       fxp_internal_error("request ID mismatch\n");
+       return 0;
+    }
+
+    if (pktin->type == SSH_FXP_ATTRS) {
+       *attrs = sftp_pkt_getattrs(pktin);
+       return 1;
+    } else {
+       fxp_got_status(pktin);
+       return 0;
+    }
+}
+
+int fxp_fstat(struct fxp_handle *handle, struct fxp_attrs *attrs)
+{
+    struct sftp_packet *pktin, *pktout;
+    int id;
+
+    pktout = sftp_pkt_init(SSH_FXP_FSTAT);
+    sftp_pkt_adduint32(pktout, 0x678); /* request id */
+    sftp_pkt_addstring_start(pktout);
+    sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
+    sftp_send(pktout);
+    pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
+    id = sftp_pkt_getuint32(pktin);
+    if (id != 0x678) {
+       fxp_internal_error("request ID mismatch\n");
+       return 0;
+    }
+
+    if (pktin->type == SSH_FXP_ATTRS) {
+       *attrs = sftp_pkt_getattrs(pktin);
+       return 1;
+    } else {
+       fxp_got_status(pktin);
+       return 0;
+    }
+}
+
+/*
+ * Set the attributes of a file.
+ */
+int fxp_setstat(char *fname, struct fxp_attrs attrs)
+{
+    struct sftp_packet *pktin, *pktout;
+    int id;
+
+    pktout = sftp_pkt_init(SSH_FXP_SETSTAT);
+    sftp_pkt_adduint32(pktout, 0x678); /* request id */
+    sftp_pkt_addstring(pktout, fname);
+    sftp_pkt_addattrs(pktout, attrs);
+    sftp_send(pktout);
+    pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
+    id = sftp_pkt_getuint32(pktin);
+    if (id != 0x678) {
+       fxp_internal_error("request ID mismatch\n");
+       return 0;
+    }
+    id = fxp_got_status(pktin);
+    if (id != 1) {
+       return 0;
+    }
+    return 1;
+}
+int fxp_fsetstat(struct fxp_handle *handle, struct fxp_attrs attrs)
+{
+    struct sftp_packet *pktin, *pktout;
+    int id;
+
+    pktout = sftp_pkt_init(SSH_FXP_FSETSTAT);
+    sftp_pkt_adduint32(pktout, 0x678); /* request id */
     sftp_pkt_addstring_start(pktout);
-    sftp_pkt_addstring_data(pktout, fname, strlen(fname));
+    sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
+    sftp_pkt_addattrs(pktout, attrs);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0x678) {
        fxp_internal_error("request ID mismatch\n");
@@ -571,6 +764,10 @@ int fxp_read(struct fxp_handle *handle, char *buffer, uint64 offset,
     sftp_pkt_adduint32(pktout, len);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return -1;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0xBCD) {
        fxp_internal_error("request ID mismatch");
@@ -610,6 +807,10 @@ struct fxp_names *fxp_readdir(struct fxp_handle *handle)
     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return NULL;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0xABC) {
        fxp_internal_error("request ID mismatch\n");
@@ -655,6 +856,10 @@ int fxp_write(struct fxp_handle *handle, char *buffer, uint64 offset,
     sftp_pkt_addstring_data(pktout, buffer, len);
     sftp_send(pktout);
     pktin = sftp_recv();
+    if (!pktin) {
+       fxp_internal_error("did not receive a valid SFTP packet\n");
+       return 0;
+    }
     id = sftp_pkt_getuint32(pktin);
     if (id != 0xDCB) {
        fxp_internal_error("request ID mismatch\n");