]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sftp.c
Fix Makefile warning about circular empty.h dependency.
[PuTTY.git] / sftp.c
1 /*
2  * sftp.c: SFTP generic client code.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <limits.h>
10
11 #include "misc.h"
12 #include "int64.h"
13 #include "tree234.h"
14 #include "sftp.h"
15
16 struct sftp_packet {
17     char *data;
18     unsigned length, maxlen;
19     unsigned savedpos;
20     int type;
21 };
22
23 static const char *fxp_error_message;
24 static int fxp_errtype;
25
26 static void fxp_internal_error(const char *msg);
27
28 /* ----------------------------------------------------------------------
29  * SFTP packet construction functions.
30  */
31 static void sftp_pkt_ensure(struct sftp_packet *pkt, int length)
32 {
33     if ((int)pkt->maxlen < length) {
34         pkt->maxlen = length + 256;
35         pkt->data = sresize(pkt->data, pkt->maxlen, char);
36     }
37 }
38 static void sftp_pkt_adddata(struct sftp_packet *pkt,
39                              const void *data, int len)
40 {
41     pkt->length += len;
42     sftp_pkt_ensure(pkt, pkt->length);
43     memcpy(pkt->data + pkt->length - len, data, len);
44 }
45 static void sftp_pkt_addbyte(struct sftp_packet *pkt, unsigned char byte)
46 {
47     sftp_pkt_adddata(pkt, &byte, 1);
48 }
49 static void sftp_pkt_adduint32(struct sftp_packet *pkt,
50                                unsigned long value)
51 {
52     unsigned char x[4];
53     PUT_32BIT(x, value);
54     sftp_pkt_adddata(pkt, x, 4);
55 }
56 static struct sftp_packet *sftp_pkt_init(int pkt_type)
57 {
58     struct sftp_packet *pkt;
59     pkt = snew(struct sftp_packet);
60     pkt->data = NULL;
61     pkt->savedpos = -1;
62     pkt->length = 0;
63     pkt->maxlen = 0;
64     sftp_pkt_adduint32(pkt, 0); /* length field will be filled in later */
65     sftp_pkt_addbyte(pkt, (unsigned char) pkt_type);
66     return pkt;
67 }
68 /*
69 static void sftp_pkt_addbool(struct sftp_packet *pkt, unsigned char value)
70 {
71     sftp_pkt_adddata(pkt, &value, 1);
72 }
73 */
74 static void sftp_pkt_adduint64(struct sftp_packet *pkt, uint64 value)
75 {
76     unsigned char x[8];
77     PUT_32BIT(x, value.hi);
78     PUT_32BIT(x + 4, value.lo);
79     sftp_pkt_adddata(pkt, x, 8);
80 }
81 static void sftp_pkt_addstring_start(struct sftp_packet *pkt)
82 {
83     sftp_pkt_adduint32(pkt, 0);
84     pkt->savedpos = pkt->length;
85 }
86 static void sftp_pkt_addstring_str(struct sftp_packet *pkt, const char *data)
87 {
88     sftp_pkt_adddata(pkt, data, strlen(data));
89     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
90 }
91 static void sftp_pkt_addstring_data(struct sftp_packet *pkt,
92                                     const char *data, int len)
93 {
94     sftp_pkt_adddata(pkt, data, len);
95     PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
96 }
97 static void sftp_pkt_addstring(struct sftp_packet *pkt, const char *data)
98 {
99     sftp_pkt_addstring_start(pkt);
100     sftp_pkt_addstring_str(pkt, data);
101 }
102 static void sftp_pkt_addattrs(struct sftp_packet *pkt, struct fxp_attrs attrs)
103 {
104     sftp_pkt_adduint32(pkt, attrs.flags);
105     if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
106         sftp_pkt_adduint32(pkt, attrs.size.hi);
107         sftp_pkt_adduint32(pkt, attrs.size.lo);
108     }
109     if (attrs.flags & SSH_FILEXFER_ATTR_UIDGID) {
110         sftp_pkt_adduint32(pkt, attrs.uid);
111         sftp_pkt_adduint32(pkt, attrs.gid);
112     }
113     if (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
114         sftp_pkt_adduint32(pkt, attrs.permissions);
115     }
116     if (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME) {
117         sftp_pkt_adduint32(pkt, attrs.atime);
118         sftp_pkt_adduint32(pkt, attrs.mtime);
119     }
120     if (attrs.flags & SSH_FILEXFER_ATTR_EXTENDED) {
121         /*
122          * We currently don't support sending any extended
123          * attributes.
124          */
125     }
126 }
127
128 /* ----------------------------------------------------------------------
129  * SFTP packet decode functions.
130  */
131
132 static int sftp_pkt_getbyte(struct sftp_packet *pkt, unsigned char *ret)
133 {
134     if (pkt->length - pkt->savedpos < 1)
135         return 0;
136     *ret = (unsigned char) pkt->data[pkt->savedpos];
137     pkt->savedpos++;
138     return 1;
139 }
140 static int sftp_pkt_getuint32(struct sftp_packet *pkt, unsigned long *ret)
141 {
142     if (pkt->length - pkt->savedpos < 4)
143         return 0;
144     *ret = GET_32BIT(pkt->data + pkt->savedpos);
145     pkt->savedpos += 4;
146     return 1;
147 }
148 static int sftp_pkt_getstring(struct sftp_packet *pkt,
149                               char **p, int *length)
150 {
151     *p = NULL;
152     if (pkt->length - pkt->savedpos < 4)
153         return 0;
154     *length = toint(GET_32BIT(pkt->data + pkt->savedpos));
155     pkt->savedpos += 4;
156     if ((int)(pkt->length - pkt->savedpos) < *length || *length < 0) {
157         *length = 0;
158         return 0;
159     }
160     *p = pkt->data + pkt->savedpos;
161     pkt->savedpos += *length;
162     return 1;
163 }
164 static int sftp_pkt_getattrs(struct sftp_packet *pkt, struct fxp_attrs *ret)
165 {
166     if (!sftp_pkt_getuint32(pkt, &ret->flags))
167         return 0;
168     if (ret->flags & SSH_FILEXFER_ATTR_SIZE) {
169         unsigned long hi, lo;
170         if (!sftp_pkt_getuint32(pkt, &hi) ||
171             !sftp_pkt_getuint32(pkt, &lo))
172             return 0;
173         ret->size = uint64_make(hi, lo);
174     }
175     if (ret->flags & SSH_FILEXFER_ATTR_UIDGID) {
176         if (!sftp_pkt_getuint32(pkt, &ret->uid) ||
177             !sftp_pkt_getuint32(pkt, &ret->gid))
178             return 0;
179     }
180     if (ret->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
181         if (!sftp_pkt_getuint32(pkt, &ret->permissions))
182             return 0;
183     }
184     if (ret->flags & SSH_FILEXFER_ATTR_ACMODTIME) {
185         if (!sftp_pkt_getuint32(pkt, &ret->atime) ||
186             !sftp_pkt_getuint32(pkt, &ret->mtime))
187             return 0;
188     }
189     if (ret->flags & SSH_FILEXFER_ATTR_EXTENDED) {
190         unsigned long count;
191         if (!sftp_pkt_getuint32(pkt, &count))
192             return 0;
193         while (count--) {
194             char *str;
195             int len;
196             /*
197              * We should try to analyse these, if we ever find one
198              * we recognise.
199              */
200             if (!sftp_pkt_getstring(pkt, &str, &len) ||
201                 !sftp_pkt_getstring(pkt, &str, &len))
202                 return 0;
203         }
204     }
205     return 1;
206 }
207 static void sftp_pkt_free(struct sftp_packet *pkt)
208 {
209     if (pkt->data)
210         sfree(pkt->data);
211     sfree(pkt);
212 }
213
214 /* ----------------------------------------------------------------------
215  * Send and receive packet functions.
216  */
217 int sftp_send(struct sftp_packet *pkt)
218 {
219     int ret;
220     PUT_32BIT(pkt->data, pkt->length - 4);
221     ret = sftp_senddata(pkt->data, pkt->length);
222     sftp_pkt_free(pkt);
223     return ret;
224 }
225 struct sftp_packet *sftp_recv(void)
226 {
227     struct sftp_packet *pkt;
228     char x[4];
229     unsigned char uc;
230
231     if (!sftp_recvdata(x, 4))
232         return NULL;
233
234     pkt = snew(struct sftp_packet);
235     pkt->savedpos = 0;
236     pkt->length = pkt->maxlen = GET_32BIT(x);
237     pkt->data = snewn(pkt->length, char);
238
239     if (!sftp_recvdata(pkt->data, pkt->length)) {
240         sftp_pkt_free(pkt);
241         return NULL;
242     }
243
244     if (!sftp_pkt_getbyte(pkt, &uc)) {
245         sftp_pkt_free(pkt);
246         return NULL;
247     } else {
248         pkt->type = uc;
249     }
250
251     return pkt;
252 }
253
254 /* ----------------------------------------------------------------------
255  * Request ID allocation and temporary dispatch routines.
256  */
257
258 #define REQUEST_ID_OFFSET 256
259
260 struct sftp_request {
261     unsigned id;
262     int registered;
263     void *userdata;
264 };
265
266 static int sftp_reqcmp(void *av, void *bv)
267 {
268     struct sftp_request *a = (struct sftp_request *)av;
269     struct sftp_request *b = (struct sftp_request *)bv;
270     if (a->id < b->id)
271         return -1;
272     if (a->id > b->id)
273         return +1;
274     return 0;
275 }
276 static int sftp_reqfind(void *av, void *bv)
277 {
278     unsigned *a = (unsigned *) av;
279     struct sftp_request *b = (struct sftp_request *)bv;
280     if (*a < b->id)
281         return -1;
282     if (*a > b->id)
283         return +1;
284     return 0;
285 }
286
287 static tree234 *sftp_requests;
288
289 static struct sftp_request *sftp_alloc_request(void)
290 {
291     unsigned low, high, mid;
292     int tsize;
293     struct sftp_request *r;
294
295     if (sftp_requests == NULL)
296         sftp_requests = newtree234(sftp_reqcmp);
297
298     /*
299      * First-fit allocation of request IDs: always pick the lowest
300      * unused one. To do this, binary-search using the counted
301      * B-tree to find the largest ID which is in a contiguous
302      * sequence from the beginning. (Precisely everything in that
303      * sequence must have ID equal to its tree index plus
304      * REQUEST_ID_OFFSET.)
305      */
306     tsize = count234(sftp_requests);
307
308     low = -1;
309     high = tsize;
310     while (high - low > 1) {
311         mid = (high + low) / 2;
312         r = index234(sftp_requests, mid);
313         if (r->id == mid + REQUEST_ID_OFFSET)
314             low = mid;                 /* this one is fine */
315         else
316             high = mid;                /* this one is past it */
317     }
318     /*
319      * Now low points to either -1, or the tree index of the
320      * largest ID in the initial sequence.
321      */
322     {
323         unsigned i = low + 1 + REQUEST_ID_OFFSET;
324         assert(NULL == find234(sftp_requests, &i, sftp_reqfind));
325     }
326
327     /*
328      * So the request ID we need to create is
329      * low + 1 + REQUEST_ID_OFFSET.
330      */
331     r = snew(struct sftp_request);
332     r->id = low + 1 + REQUEST_ID_OFFSET;
333     r->registered = 0;
334     r->userdata = NULL;
335     add234(sftp_requests, r);
336     return r;
337 }
338
339 void sftp_cleanup_request(void)
340 {
341     if (sftp_requests != NULL) {
342         freetree234(sftp_requests);
343         sftp_requests = NULL;
344     }
345 }
346
347 void sftp_register(struct sftp_request *req)
348 {
349     req->registered = 1;
350 }
351
352 struct sftp_request *sftp_find_request(struct sftp_packet *pktin)
353 {
354     unsigned long id;
355     unsigned fid;
356     struct sftp_request *req;
357
358     if (!pktin) {
359         fxp_internal_error("did not receive a valid SFTP packet\n");
360         return NULL;
361     }
362
363     if (!sftp_pkt_getuint32(pktin, &id)) {
364         fxp_internal_error("did not receive a valid SFTP packet\n");
365         return NULL;
366     }
367     fid = (unsigned)id;
368     req = find234(sftp_requests, &fid, sftp_reqfind);
369
370     if (!req || !req->registered) {
371         fxp_internal_error("request ID mismatch\n");
372         return NULL;
373     }
374
375     del234(sftp_requests, req);
376
377     return req;
378 }
379
380 /* ----------------------------------------------------------------------
381  * String handling routines.
382  */
383
384 static char *mkstr(char *s, int len)
385 {
386     char *p = snewn(len + 1, char);
387     memcpy(p, s, len);
388     p[len] = '\0';
389     return p;
390 }
391
392 /* ----------------------------------------------------------------------
393  * SFTP primitives.
394  */
395
396 /*
397  * Deal with (and free) an FXP_STATUS packet. Return 1 if
398  * SSH_FX_OK, 0 if SSH_FX_EOF, and -1 for anything else (error).
399  * Also place the status into fxp_errtype.
400  */
401 static int fxp_got_status(struct sftp_packet *pktin)
402 {
403     static const char *const messages[] = {
404         /* SSH_FX_OK. The only time we will display a _message_ for this
405          * is if we were expecting something other than FXP_STATUS on
406          * success, so this is actually an error message! */
407         "unexpected OK response",
408         "end of file",
409         "no such file or directory",
410         "permission denied",
411         "failure",
412         "bad message",
413         "no connection",
414         "connection lost",
415         "operation unsupported",
416     };
417
418     if (pktin->type != SSH_FXP_STATUS) {
419         fxp_error_message = "expected FXP_STATUS packet";
420         fxp_errtype = -1;
421     } else {
422         unsigned long ul;
423         if (!sftp_pkt_getuint32(pktin, &ul)) {
424             fxp_error_message = "malformed FXP_STATUS packet";
425             fxp_errtype = -1;
426         } else {
427             fxp_errtype = ul;
428             if (fxp_errtype < 0 ||
429                 fxp_errtype >= sizeof(messages) / sizeof(*messages))
430                 fxp_error_message = "unknown error code";
431             else
432                 fxp_error_message = messages[fxp_errtype];
433         }
434     }
435
436     if (fxp_errtype == SSH_FX_OK)
437         return 1;
438     else if (fxp_errtype == SSH_FX_EOF)
439         return 0;
440     else
441         return -1;
442 }
443
444 static void fxp_internal_error(const char *msg)
445 {
446     fxp_error_message = msg;
447     fxp_errtype = -1;
448 }
449
450 const char *fxp_error(void)
451 {
452     return fxp_error_message;
453 }
454
455 int fxp_error_type(void)
456 {
457     return fxp_errtype;
458 }
459
460 /*
461  * Perform exchange of init/version packets. Return 0 on failure.
462  */
463 int fxp_init(void)
464 {
465     struct sftp_packet *pktout, *pktin;
466     unsigned long remotever;
467
468     pktout = sftp_pkt_init(SSH_FXP_INIT);
469     sftp_pkt_adduint32(pktout, SFTP_PROTO_VERSION);
470     sftp_send(pktout);
471
472     pktin = sftp_recv();
473     if (!pktin) {
474         fxp_internal_error("could not connect");
475         return 0;
476     }
477     if (pktin->type != SSH_FXP_VERSION) {
478         fxp_internal_error("did not receive FXP_VERSION");
479         sftp_pkt_free(pktin);
480         return 0;
481     }
482     if (!sftp_pkt_getuint32(pktin, &remotever)) {
483         fxp_internal_error("malformed FXP_VERSION packet");
484         sftp_pkt_free(pktin);
485         return 0;
486     }
487     if (remotever > SFTP_PROTO_VERSION) {
488         fxp_internal_error
489             ("remote protocol is more advanced than we support");
490         sftp_pkt_free(pktin);
491         return 0;
492     }
493     /*
494      * In principle, this packet might also contain extension-
495      * string pairs. We should work through them and look for any
496      * we recognise. In practice we don't currently do so because
497      * we know we don't recognise _any_.
498      */
499     sftp_pkt_free(pktin);
500
501     return 1;
502 }
503
504 /*
505  * Canonify a pathname.
506  */
507 struct sftp_request *fxp_realpath_send(const char *path)
508 {
509     struct sftp_request *req = sftp_alloc_request();
510     struct sftp_packet *pktout;
511
512     pktout = sftp_pkt_init(SSH_FXP_REALPATH);
513     sftp_pkt_adduint32(pktout, req->id);
514     sftp_pkt_addstring_start(pktout);
515     sftp_pkt_addstring_str(pktout, path);
516     sftp_send(pktout);
517
518     return req;
519 }
520
521 char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req)
522 {
523     sfree(req);
524
525     if (pktin->type == SSH_FXP_NAME) {
526         unsigned long count;
527         char *path;
528         int len;
529
530         if (!sftp_pkt_getuint32(pktin, &count) || count != 1) {
531             fxp_internal_error("REALPATH did not return name count of 1\n");
532             sftp_pkt_free(pktin);
533             return NULL;
534         }
535         if (!sftp_pkt_getstring(pktin, &path, &len)) {
536             fxp_internal_error("REALPATH returned malformed FXP_NAME\n");
537             sftp_pkt_free(pktin);
538             return NULL;
539         }
540         path = mkstr(path, len);
541         sftp_pkt_free(pktin);
542         return path;
543     } else {
544         fxp_got_status(pktin);
545         sftp_pkt_free(pktin);
546         return NULL;
547     }
548 }
549
550 /*
551  * Open a file.
552  */
553 struct sftp_request *fxp_open_send(const char *path, int type,
554                                    struct fxp_attrs *attrs)
555 {
556     struct sftp_request *req = sftp_alloc_request();
557     struct sftp_packet *pktout;
558
559     pktout = sftp_pkt_init(SSH_FXP_OPEN);
560     sftp_pkt_adduint32(pktout, req->id);
561     sftp_pkt_addstring(pktout, path);
562     sftp_pkt_adduint32(pktout, type);
563     if (attrs)
564         sftp_pkt_addattrs(pktout, *attrs);
565     else
566         sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
567     sftp_send(pktout);
568
569     return req;
570 }
571
572 struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
573                                  struct sftp_request *req)
574 {
575     sfree(req);
576
577     if (pktin->type == SSH_FXP_HANDLE) {
578         char *hstring;
579         struct fxp_handle *handle;
580         int len;
581
582         if (!sftp_pkt_getstring(pktin, &hstring, &len)) {
583             fxp_internal_error("OPEN returned malformed FXP_HANDLE\n");
584             sftp_pkt_free(pktin);
585             return NULL;
586         }
587         handle = snew(struct fxp_handle);
588         handle->hstring = mkstr(hstring, len);
589         handle->hlen = len;
590         sftp_pkt_free(pktin);
591         return handle;
592     } else {
593         fxp_got_status(pktin);
594         sftp_pkt_free(pktin);
595         return NULL;
596     }
597 }
598
599 /*
600  * Open a directory.
601  */
602 struct sftp_request *fxp_opendir_send(const char *path)
603 {
604     struct sftp_request *req = sftp_alloc_request();
605     struct sftp_packet *pktout;
606
607     pktout = sftp_pkt_init(SSH_FXP_OPENDIR);
608     sftp_pkt_adduint32(pktout, req->id);
609     sftp_pkt_addstring(pktout, path);
610     sftp_send(pktout);
611
612     return req;
613 }
614
615 struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin,
616                                     struct sftp_request *req)
617 {
618     sfree(req);
619     if (pktin->type == SSH_FXP_HANDLE) {
620         char *hstring;
621         struct fxp_handle *handle;
622         int len;
623
624         if (!sftp_pkt_getstring(pktin, &hstring, &len)) {
625             fxp_internal_error("OPENDIR returned malformed FXP_HANDLE\n");
626             sftp_pkt_free(pktin);
627             return NULL;
628         }
629         handle = snew(struct fxp_handle);
630         handle->hstring = mkstr(hstring, len);
631         handle->hlen = len;
632         sftp_pkt_free(pktin);
633         return handle;
634     } else {
635         fxp_got_status(pktin);
636         sftp_pkt_free(pktin);
637         return NULL;
638     }
639 }
640
641 /*
642  * Close a file/dir.
643  */
644 struct sftp_request *fxp_close_send(struct fxp_handle *handle)
645 {
646     struct sftp_request *req = sftp_alloc_request();
647     struct sftp_packet *pktout;
648
649     pktout = sftp_pkt_init(SSH_FXP_CLOSE);
650     sftp_pkt_adduint32(pktout, req->id);
651     sftp_pkt_addstring_start(pktout);
652     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
653     sftp_send(pktout);
654
655     sfree(handle->hstring);
656     sfree(handle);
657
658     return req;
659 }
660
661 int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req)
662 {
663     sfree(req);
664     fxp_got_status(pktin);
665     sftp_pkt_free(pktin);
666     return fxp_errtype == SSH_FX_OK;
667 }
668
669 struct sftp_request *fxp_mkdir_send(const char *path)
670 {
671     struct sftp_request *req = sftp_alloc_request();
672     struct sftp_packet *pktout;
673
674     pktout = sftp_pkt_init(SSH_FXP_MKDIR);
675     sftp_pkt_adduint32(pktout, req->id);
676     sftp_pkt_addstring(pktout, path);
677     sftp_pkt_adduint32(pktout, 0);     /* (FIXME) empty ATTRS structure */
678     sftp_send(pktout);
679
680     return req;
681 }
682
683 int fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req)
684 {
685     int id;
686     sfree(req);
687     id = fxp_got_status(pktin);
688     sftp_pkt_free(pktin);
689     if (id != 1) {
690         return 0;
691     }
692     return 1;
693 }
694
695 struct sftp_request *fxp_rmdir_send(const char *path)
696 {
697     struct sftp_request *req = sftp_alloc_request();
698     struct sftp_packet *pktout;
699
700     pktout = sftp_pkt_init(SSH_FXP_RMDIR);
701     sftp_pkt_adduint32(pktout, req->id);
702     sftp_pkt_addstring(pktout, path);
703     sftp_send(pktout);
704
705     return req;
706 }
707
708 int fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req)
709 {
710     int id;
711     sfree(req);
712     id = fxp_got_status(pktin);
713     sftp_pkt_free(pktin);
714     if (id != 1) {
715         return 0;
716     }
717     return 1;
718 }
719
720 struct sftp_request *fxp_remove_send(const char *fname)
721 {
722     struct sftp_request *req = sftp_alloc_request();
723     struct sftp_packet *pktout;
724
725     pktout = sftp_pkt_init(SSH_FXP_REMOVE);
726     sftp_pkt_adduint32(pktout, req->id);
727     sftp_pkt_addstring(pktout, fname);
728     sftp_send(pktout);
729
730     return req;
731 }
732
733 int fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req)
734 {
735     int id;
736     sfree(req);
737     id = fxp_got_status(pktin);
738     sftp_pkt_free(pktin);
739     if (id != 1) {
740         return 0;
741     }
742     return 1;
743 }
744
745 struct sftp_request *fxp_rename_send(const char *srcfname,
746                                      const char *dstfname)
747 {
748     struct sftp_request *req = sftp_alloc_request();
749     struct sftp_packet *pktout;
750
751     pktout = sftp_pkt_init(SSH_FXP_RENAME);
752     sftp_pkt_adduint32(pktout, req->id);
753     sftp_pkt_addstring(pktout, srcfname);
754     sftp_pkt_addstring(pktout, dstfname);
755     sftp_send(pktout);
756
757     return req;
758 }
759
760 int fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req)
761 {
762     int id;
763     sfree(req);
764     id = fxp_got_status(pktin);
765     sftp_pkt_free(pktin);
766     if (id != 1) {
767         return 0;
768     }
769     return 1;
770 }
771
772 /*
773  * Retrieve the attributes of a file. We have fxp_stat which works
774  * on filenames, and fxp_fstat which works on open file handles.
775  */
776 struct sftp_request *fxp_stat_send(const char *fname)
777 {
778     struct sftp_request *req = sftp_alloc_request();
779     struct sftp_packet *pktout;
780
781     pktout = sftp_pkt_init(SSH_FXP_STAT);
782     sftp_pkt_adduint32(pktout, req->id);
783     sftp_pkt_addstring(pktout, fname);
784     sftp_send(pktout);
785
786     return req;
787 }
788
789 int fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req,
790                   struct fxp_attrs *attrs)
791 {
792     sfree(req);
793     if (pktin->type == SSH_FXP_ATTRS) {
794         if (!sftp_pkt_getattrs(pktin, attrs)) {
795             fxp_internal_error("malformed SSH_FXP_ATTRS packet");
796             sftp_pkt_free(pktin);
797             return 0;
798         }
799         sftp_pkt_free(pktin);
800         return 1;
801     } else {
802         fxp_got_status(pktin);
803         sftp_pkt_free(pktin);
804         return 0;
805     }
806 }
807
808 struct sftp_request *fxp_fstat_send(struct fxp_handle *handle)
809 {
810     struct sftp_request *req = sftp_alloc_request();
811     struct sftp_packet *pktout;
812
813     pktout = sftp_pkt_init(SSH_FXP_FSTAT);
814     sftp_pkt_adduint32(pktout, req->id);
815     sftp_pkt_addstring_start(pktout);
816     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
817     sftp_send(pktout);
818
819     return req;
820 }
821
822 int fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req,
823                    struct fxp_attrs *attrs)
824 {
825     sfree(req);
826     if (pktin->type == SSH_FXP_ATTRS) {
827         if (!sftp_pkt_getattrs(pktin, attrs)) {
828             fxp_internal_error("malformed SSH_FXP_ATTRS packet");
829             sftp_pkt_free(pktin);
830             return 0;
831         }
832         sftp_pkt_free(pktin);
833         return 1;
834     } else {
835         fxp_got_status(pktin);
836         sftp_pkt_free(pktin);
837         return 0;
838     }
839 }
840
841 /*
842  * Set the attributes of a file.
843  */
844 struct sftp_request *fxp_setstat_send(const char *fname,
845                                       struct fxp_attrs attrs)
846 {
847     struct sftp_request *req = sftp_alloc_request();
848     struct sftp_packet *pktout;
849
850     pktout = sftp_pkt_init(SSH_FXP_SETSTAT);
851     sftp_pkt_adduint32(pktout, req->id);
852     sftp_pkt_addstring(pktout, fname);
853     sftp_pkt_addattrs(pktout, attrs);
854     sftp_send(pktout);
855
856     return req;
857 }
858
859 int fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req)
860 {
861     int id;
862     sfree(req);
863     id = fxp_got_status(pktin);
864     sftp_pkt_free(pktin);
865     if (id != 1) {
866         return 0;
867     }
868     return 1;
869 }
870
871 struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle,
872                                        struct fxp_attrs attrs)
873 {
874     struct sftp_request *req = sftp_alloc_request();
875     struct sftp_packet *pktout;
876
877     pktout = sftp_pkt_init(SSH_FXP_FSETSTAT);
878     sftp_pkt_adduint32(pktout, req->id);
879     sftp_pkt_addstring_start(pktout);
880     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
881     sftp_pkt_addattrs(pktout, attrs);
882     sftp_send(pktout);
883
884     return req;
885 }
886
887 int fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req)
888 {
889     int id;
890     sfree(req);
891     id = fxp_got_status(pktin);
892     sftp_pkt_free(pktin);
893     if (id != 1) {
894         return 0;
895     }
896     return 1;
897 }
898
899 /*
900  * Read from a file. Returns the number of bytes read, or -1 on an
901  * error, or possibly 0 if EOF. (I'm not entirely sure whether it
902  * will return 0 on EOF, or return -1 and store SSH_FX_EOF in the
903  * error indicator. It might even depend on the SFTP server.)
904  */
905 struct sftp_request *fxp_read_send(struct fxp_handle *handle,
906                                    uint64 offset, int len)
907 {
908     struct sftp_request *req = sftp_alloc_request();
909     struct sftp_packet *pktout;
910
911     pktout = sftp_pkt_init(SSH_FXP_READ);
912     sftp_pkt_adduint32(pktout, req->id);
913     sftp_pkt_addstring_start(pktout);
914     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
915     sftp_pkt_adduint64(pktout, offset);
916     sftp_pkt_adduint32(pktout, len);
917     sftp_send(pktout);
918
919     return req;
920 }
921
922 int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req,
923                   char *buffer, int len)
924 {
925     sfree(req);
926     if (pktin->type == SSH_FXP_DATA) {
927         char *str;
928         int rlen;
929
930         if (!sftp_pkt_getstring(pktin, &str, &rlen)) {
931             fxp_internal_error("READ returned malformed SSH_FXP_DATA packet");
932             sftp_pkt_free(pktin);
933             return -1;
934         }
935
936         if (rlen > len || rlen < 0) {
937             fxp_internal_error("READ returned more bytes than requested");
938             sftp_pkt_free(pktin);
939             return -1;
940         }
941
942         memcpy(buffer, str, rlen);
943         sftp_pkt_free(pktin);
944         return rlen;
945     } else {
946         fxp_got_status(pktin);
947         sftp_pkt_free(pktin);
948         return -1;
949     }
950 }
951
952 /*
953  * Read from a directory.
954  */
955 struct sftp_request *fxp_readdir_send(struct fxp_handle *handle)
956 {
957     struct sftp_request *req = sftp_alloc_request();
958     struct sftp_packet *pktout;
959
960     pktout = sftp_pkt_init(SSH_FXP_READDIR);
961     sftp_pkt_adduint32(pktout, req->id);
962     sftp_pkt_addstring_start(pktout);
963     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
964     sftp_send(pktout);
965
966     return req;
967 }
968
969 struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin,
970                                    struct sftp_request *req)
971 {
972     sfree(req);
973     if (pktin->type == SSH_FXP_NAME) {
974         struct fxp_names *ret;
975         unsigned long i;
976
977         /*
978          * Sanity-check the number of names. Minimum is obviously
979          * zero. Maximum is the remaining space in the packet
980          * divided by the very minimum length of a name, which is
981          * 12 bytes (4 for an empty filename, 4 for an empty
982          * longname, 4 for a set of attribute flags indicating that
983          * no other attributes are supplied).
984          */
985         if (!sftp_pkt_getuint32(pktin, &i) ||
986             i > (pktin->length-pktin->savedpos)/12) {
987             fxp_internal_error("malformed FXP_NAME packet");
988             sftp_pkt_free(pktin);
989             return NULL;
990         }
991
992         /*
993          * Ensure the implicit multiplication in the snewn() call
994          * doesn't suffer integer overflow and cause us to malloc
995          * too little space.
996          */
997         if (i > INT_MAX / sizeof(struct fxp_name)) {
998             fxp_internal_error("unreasonably large FXP_NAME packet");
999             sftp_pkt_free(pktin);
1000             return NULL;
1001         }
1002
1003         ret = snew(struct fxp_names);
1004         ret->nnames = i;
1005         ret->names = snewn(ret->nnames, struct fxp_name);
1006         for (i = 0; i < (unsigned long)ret->nnames; i++) {
1007             char *str1, *str2;
1008             int len1, len2;
1009             if (!sftp_pkt_getstring(pktin, &str1, &len1) ||
1010                 !sftp_pkt_getstring(pktin, &str2, &len2) ||
1011                 !sftp_pkt_getattrs(pktin, &ret->names[i].attrs)) {
1012                 fxp_internal_error("malformed FXP_NAME packet");
1013                 while (i--) {
1014                     sfree(ret->names[i].filename);
1015                     sfree(ret->names[i].longname);
1016                 }
1017                 sfree(ret->names);
1018                 sfree(ret);
1019                 sfree(pktin);
1020                 return NULL;
1021             }
1022             ret->names[i].filename = mkstr(str1, len1);
1023             ret->names[i].longname = mkstr(str2, len2);
1024         }
1025         sftp_pkt_free(pktin);
1026         return ret;
1027     } else {
1028         fxp_got_status(pktin);
1029         sftp_pkt_free(pktin);
1030         return NULL;
1031     }
1032 }
1033
1034 /*
1035  * Write to a file. Returns 0 on error, 1 on OK.
1036  */
1037 struct sftp_request *fxp_write_send(struct fxp_handle *handle,
1038                                     char *buffer, uint64 offset, int len)
1039 {
1040     struct sftp_request *req = sftp_alloc_request();
1041     struct sftp_packet *pktout;
1042
1043     pktout = sftp_pkt_init(SSH_FXP_WRITE);
1044     sftp_pkt_adduint32(pktout, req->id);
1045     sftp_pkt_addstring_start(pktout);
1046     sftp_pkt_addstring_data(pktout, handle->hstring, handle->hlen);
1047     sftp_pkt_adduint64(pktout, offset);
1048     sftp_pkt_addstring_start(pktout);
1049     sftp_pkt_addstring_data(pktout, buffer, len);
1050     sftp_send(pktout);
1051
1052     return req;
1053 }
1054
1055 int fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req)
1056 {
1057     sfree(req);
1058     fxp_got_status(pktin);
1059     sftp_pkt_free(pktin);
1060     return fxp_errtype == SSH_FX_OK;
1061 }
1062
1063 /*
1064  * Free up an fxp_names structure.
1065  */
1066 void fxp_free_names(struct fxp_names *names)
1067 {
1068     int i;
1069
1070     for (i = 0; i < names->nnames; i++) {
1071         sfree(names->names[i].filename);
1072         sfree(names->names[i].longname);
1073     }
1074     sfree(names->names);
1075     sfree(names);
1076 }
1077
1078 /*
1079  * Duplicate an fxp_name structure.
1080  */
1081 struct fxp_name *fxp_dup_name(struct fxp_name *name)
1082 {
1083     struct fxp_name *ret;
1084     ret = snew(struct fxp_name);
1085     ret->filename = dupstr(name->filename);
1086     ret->longname = dupstr(name->longname);
1087     ret->attrs = name->attrs;          /* structure copy */
1088     return ret;
1089 }
1090
1091 /*
1092  * Free up an fxp_name structure.
1093  */
1094 void fxp_free_name(struct fxp_name *name)
1095 {
1096     sfree(name->filename);
1097     sfree(name->longname);
1098     sfree(name);
1099 }
1100
1101 /*
1102  * Store user data in an sftp_request structure.
1103  */
1104 void *fxp_get_userdata(struct sftp_request *req)
1105 {
1106     return req->userdata;
1107 }
1108
1109 void fxp_set_userdata(struct sftp_request *req, void *data)
1110 {
1111     req->userdata = data;
1112 }
1113
1114 /*
1115  * A wrapper to go round fxp_read_* and fxp_write_*, which manages
1116  * the queueing of multiple read/write requests.
1117  */
1118
1119 struct req {
1120     char *buffer;
1121     int len, retlen, complete;
1122     uint64 offset;
1123     struct req *next, *prev;
1124 };
1125
1126 struct fxp_xfer {
1127     uint64 offset, furthestdata, filesize;
1128     int req_totalsize, req_maxsize, eof, err;
1129     struct fxp_handle *fh;
1130     struct req *head, *tail;
1131 };
1132
1133 static struct fxp_xfer *xfer_init(struct fxp_handle *fh, uint64 offset)
1134 {
1135     struct fxp_xfer *xfer = snew(struct fxp_xfer);
1136
1137     xfer->fh = fh;
1138     xfer->offset = offset;
1139     xfer->head = xfer->tail = NULL;
1140     xfer->req_totalsize = 0;
1141     xfer->req_maxsize = 1048576;
1142     xfer->err = 0;
1143     xfer->filesize = uint64_make(ULONG_MAX, ULONG_MAX);
1144     xfer->furthestdata = uint64_make(0, 0);
1145
1146     return xfer;
1147 }
1148
1149 int xfer_done(struct fxp_xfer *xfer)
1150 {
1151     /*
1152      * We're finished if we've seen EOF _and_ there are no
1153      * outstanding requests.
1154      */
1155     return (xfer->eof || xfer->err) && !xfer->head;
1156 }
1157
1158 void xfer_download_queue(struct fxp_xfer *xfer)
1159 {
1160     while (xfer->req_totalsize < xfer->req_maxsize &&
1161            !xfer->eof && !xfer->err) {
1162         /*
1163          * Queue a new read request.
1164          */
1165         struct req *rr;
1166         struct sftp_request *req;
1167
1168         rr = snew(struct req);
1169         rr->offset = xfer->offset;
1170         rr->complete = 0;
1171         if (xfer->tail) {
1172             xfer->tail->next = rr;
1173             rr->prev = xfer->tail;
1174         } else {
1175             xfer->head = rr;
1176             rr->prev = NULL;
1177         }
1178         xfer->tail = rr;
1179         rr->next = NULL;
1180
1181         rr->len = 32768;
1182         rr->buffer = snewn(rr->len, char);
1183         sftp_register(req = fxp_read_send(xfer->fh, rr->offset, rr->len));
1184         fxp_set_userdata(req, rr);
1185
1186         xfer->offset = uint64_add32(xfer->offset, rr->len);
1187         xfer->req_totalsize += rr->len;
1188
1189 #ifdef DEBUG_DOWNLOAD
1190         { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing read request %p at %s\n", rr, buf); }
1191 #endif
1192     }
1193 }
1194
1195 struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64 offset)
1196 {
1197     struct fxp_xfer *xfer = xfer_init(fh, offset);
1198
1199     xfer->eof = FALSE;
1200     xfer_download_queue(xfer);
1201
1202     return xfer;
1203 }
1204
1205 /*
1206  * Returns INT_MIN to indicate that it didn't even get as far as
1207  * fxp_read_recv and hence has not freed pktin.
1208  */
1209 int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
1210 {
1211     struct sftp_request *rreq;
1212     struct req *rr;
1213
1214     rreq = sftp_find_request(pktin);
1215     if (!rreq)
1216         return INT_MIN;            /* this packet doesn't even make sense */
1217     rr = (struct req *)fxp_get_userdata(rreq);
1218     if (!rr) {
1219         fxp_internal_error("request ID is not part of the current download");
1220         return INT_MIN;                /* this packet isn't ours */
1221     }
1222     rr->retlen = fxp_read_recv(pktin, rreq, rr->buffer, rr->len);
1223 #ifdef DEBUG_DOWNLOAD
1224     printf("read request %p has returned [%d]\n", rr, rr->retlen);
1225 #endif
1226
1227     if ((rr->retlen < 0 && fxp_error_type()==SSH_FX_EOF) || rr->retlen == 0) {
1228         xfer->eof = TRUE;
1229         rr->complete = -1;
1230 #ifdef DEBUG_DOWNLOAD
1231         printf("setting eof\n");
1232 #endif
1233     } else if (rr->retlen < 0) {
1234         /* some error other than EOF; signal it back to caller */
1235         xfer_set_error(xfer);
1236         rr->complete = -1;
1237         return -1;
1238     }
1239
1240     rr->complete = 1;
1241
1242     /*
1243      * Special case: if we have received fewer bytes than we
1244      * actually read, we should do something. For the moment I'll
1245      * just throw an ersatz FXP error to signal this; the SFTP
1246      * draft I've got says that it can't happen except on special
1247      * files, in which case seeking probably has very little
1248      * meaning and so queueing an additional read request to fill
1249      * up the gap sounds like the wrong answer. I'm not sure what I
1250      * should be doing here - if it _was_ a special file, I suspect
1251      * I simply shouldn't have been queueing multiple requests in
1252      * the first place...
1253      */
1254     if (rr->retlen > 0 && uint64_compare(xfer->furthestdata, rr->offset) < 0) {
1255         xfer->furthestdata = rr->offset;
1256 #ifdef DEBUG_DOWNLOAD
1257         { char buf[40];
1258         uint64_decimal(xfer->furthestdata, buf);
1259         printf("setting furthestdata = %s\n", buf); }
1260 #endif
1261     }
1262
1263     if (rr->retlen < rr->len) {
1264         uint64 filesize = uint64_add32(rr->offset,
1265                                        (rr->retlen < 0 ? 0 : rr->retlen));
1266 #ifdef DEBUG_DOWNLOAD
1267         { char buf[40];
1268         uint64_decimal(filesize, buf);
1269         printf("short block! trying filesize = %s\n", buf); }
1270 #endif
1271         if (uint64_compare(xfer->filesize, filesize) > 0) {
1272             xfer->filesize = filesize;
1273 #ifdef DEBUG_DOWNLOAD
1274             printf("actually changing filesize\n");
1275 #endif      
1276         }
1277     }
1278
1279     if (uint64_compare(xfer->furthestdata, xfer->filesize) > 0) {
1280         fxp_error_message = "received a short buffer from FXP_READ, but not"
1281             " at EOF";
1282         fxp_errtype = -1;
1283         xfer_set_error(xfer);
1284         return -1;
1285     }
1286
1287     return 1;
1288 }
1289
1290 void xfer_set_error(struct fxp_xfer *xfer)
1291 {
1292     xfer->err = 1;
1293 }
1294
1295 int xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len)
1296 {
1297     void *retbuf = NULL;
1298     int retlen = 0;
1299
1300     /*
1301      * Discard anything at the head of the rr queue with complete <
1302      * 0; return the first thing with complete > 0.
1303      */
1304     while (xfer->head && xfer->head->complete && !retbuf) {
1305         struct req *rr = xfer->head;
1306
1307         if (rr->complete > 0) {
1308             retbuf = rr->buffer;
1309             retlen = rr->retlen;
1310 #ifdef DEBUG_DOWNLOAD
1311             printf("handing back data from read request %p\n", rr);
1312 #endif
1313         }
1314 #ifdef DEBUG_DOWNLOAD
1315         else
1316             printf("skipping failed read request %p\n", rr);
1317 #endif
1318
1319         xfer->head = xfer->head->next;
1320         if (xfer->head)
1321             xfer->head->prev = NULL;
1322         else
1323             xfer->tail = NULL;
1324         xfer->req_totalsize -= rr->len;
1325         sfree(rr);
1326     }
1327
1328     if (retbuf) {
1329         *buf = retbuf;
1330         *len = retlen;
1331         return 1;
1332     } else
1333         return 0;
1334 }
1335
1336 struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64 offset)
1337 {
1338     struct fxp_xfer *xfer = xfer_init(fh, offset);
1339
1340     /*
1341      * We set `eof' to 1 because this will cause xfer_done() to
1342      * return true iff there are no outstanding requests. During an
1343      * upload, our caller will be responsible for working out
1344      * whether all the data has been sent, so all it needs to know
1345      * from us is whether the outstanding requests have been
1346      * handled once that's done.
1347      */
1348     xfer->eof = 1;
1349
1350     return xfer;
1351 }
1352
1353 int xfer_upload_ready(struct fxp_xfer *xfer)
1354 {
1355     if (sftp_sendbuffer() == 0)
1356         return 1;
1357     else
1358         return 0;
1359 }
1360
1361 void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len)
1362 {
1363     struct req *rr;
1364     struct sftp_request *req;
1365
1366     rr = snew(struct req);
1367     rr->offset = xfer->offset;
1368     rr->complete = 0;
1369     if (xfer->tail) {
1370         xfer->tail->next = rr;
1371         rr->prev = xfer->tail;
1372     } else {
1373         xfer->head = rr;
1374         rr->prev = NULL;
1375     }
1376     xfer->tail = rr;
1377     rr->next = NULL;
1378
1379     rr->len = len;
1380     rr->buffer = NULL;
1381     sftp_register(req = fxp_write_send(xfer->fh, buffer, rr->offset, len));
1382     fxp_set_userdata(req, rr);
1383
1384     xfer->offset = uint64_add32(xfer->offset, rr->len);
1385     xfer->req_totalsize += rr->len;
1386
1387 #ifdef DEBUG_UPLOAD
1388     { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); }
1389 #endif
1390 }
1391
1392 /*
1393  * Returns INT_MIN to indicate that it didn't even get as far as
1394  * fxp_write_recv and hence has not freed pktin.
1395  */
1396 int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
1397 {
1398     struct sftp_request *rreq;
1399     struct req *rr, *prev, *next;
1400     int ret;
1401
1402     rreq = sftp_find_request(pktin);
1403     if (!rreq)
1404         return INT_MIN;            /* this packet doesn't even make sense */
1405     rr = (struct req *)fxp_get_userdata(rreq);
1406     if (!rr) {
1407         fxp_internal_error("request ID is not part of the current upload");
1408         return INT_MIN;                /* this packet isn't ours */
1409     }
1410     ret = fxp_write_recv(pktin, rreq);
1411 #ifdef DEBUG_UPLOAD
1412     printf("write request %p has returned [%d]\n", rr, ret);
1413 #endif
1414
1415     /*
1416      * Remove this one from the queue.
1417      */
1418     prev = rr->prev;
1419     next = rr->next;
1420     if (prev)
1421         prev->next = next;
1422     else
1423         xfer->head = next;
1424     if (next)
1425         next->prev = prev;
1426     else
1427         xfer->tail = prev;
1428     xfer->req_totalsize -= rr->len;
1429     sfree(rr);
1430
1431     if (!ret)
1432         return -1;
1433
1434     return 1;
1435 }
1436
1437 void xfer_cleanup(struct fxp_xfer *xfer)
1438 {
1439     struct req *rr;
1440     while (xfer->head) {
1441         rr = xfer->head;
1442         xfer->head = xfer->head->next;
1443         sfree(rr->buffer);
1444         sfree(rr);
1445     }
1446     sfree(xfer);
1447 }