Merged silc_1_1_branch to trunk.
[silc.git] / lib / silcsftp / sftp_client.c
1 /*
2
3   sftp_client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcsftp.h"
23 #include "sftp_util.h"
24
25 /* Request context. Every request will allocate this context and set
26    the correct callback function according the `type' field. */
27 typedef struct SilcSFTPRequestStruct {
28   struct SilcSFTPRequestStruct *next;
29   SilcSFTPStatusCallback status;
30   SilcSFTPHandleCallback handle;
31   SilcSFTPDataCallback data;
32   SilcSFTPNameCallback name;
33   SilcSFTPAttrCallback attr;
34   SilcSFTPExtendedCallback extended;
35   void *context;
36   SilcUInt32 id;
37   SilcSFTPPacket type;
38 } *SilcSFTPRequest;
39
40 /* SFTP client context */
41 typedef struct {
42   SilcStream stream;
43   SilcSchedule schedule;
44   SilcSFTPVersionCallback version;
45   SilcSFTPErrorCallback error;
46   void *context;
47   SilcList requests;
48   SilcBuffer packet;
49   SilcUInt32 id;
50 } *SilcSFTPClient;
51
52 /* File handle */
53 struct SilcSFTPHandleStruct {
54   unsigned char *data;
55   SilcUInt32 data_len;
56 };
57
58 static void silc_sftp_client_receive_process(SilcSFTP context,
59                                              SilcBuffer buffer);
60
61 /* Creates SilcSFTPHandle and returns pointer to it. The caller must free
62    the context. */
63
64 static SilcSFTPHandle silc_sftp_handle_create(unsigned char *data,
65                                               SilcUInt32 data_len)
66 {
67   SilcSFTPHandle handle;
68
69   handle = silc_calloc(1, sizeof(*handle));
70   if (!handle)
71     return NULL;
72   handle->data = silc_calloc(data_len, sizeof(*handle->data));
73   if (!handle->data)
74     return NULL;
75   memcpy(handle->data, data, data_len);
76   handle->data_len = data_len;
77
78   return handle;
79 }
80
81 /* Deletes the handle indicated by the `handle'. */
82
83 static void silc_sftp_handle_delete(SilcSFTPHandle handle)
84 {
85   silc_free(handle->data);
86   silc_free(handle);
87 }
88
89 /* Returns the handle data of the `handle' to the `data' pointer. */
90
91 static void silc_sftp_handle_get(SilcSFTPHandle handle,
92                                  const unsigned char **data,
93                                  SilcUInt32 *data_len)
94 {
95   *data = (const unsigned char *)handle->data;
96   *data_len = handle->data_len;
97 }
98
99 /* Generic routine to send SFTP packet to the SFTP server. */
100
101 static void silc_sftp_send_packet(SilcSFTPClient sftp,
102                                   SilcSFTPPacket type,
103                                   SilcUInt32 len, ...)
104 {
105   SilcBuffer tmp;
106   va_list vp;
107   int ret;
108
109   va_start(vp, len);
110   tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
111   va_end(vp);
112   if (!tmp)
113     return;
114   sftp->packet = tmp;
115
116   SILC_LOG_HEXDUMP(("SFTP packet to server"), sftp->packet->data,
117                    silc_buffer_len(sftp->packet));
118
119   /* Send the packet */
120   while (silc_buffer_len(sftp->packet) > 0) {
121     ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet),
122                             silc_buffer_len(sftp->packet));
123     if (ret == -2) {
124       SILC_LOG_ERROR(("Error sending SFTP packet type %d", type));
125       sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION,
126                   sftp->context);
127       silc_buffer_reset(sftp->packet);
128       return;
129     }
130     if (ret == 0) {
131       sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context);
132       silc_buffer_reset(sftp->packet);
133       return;
134     }
135     if (ret == -1)
136       return;
137
138     silc_buffer_pull(sftp->packet, ret);
139   }
140
141   /* Clear packet */
142   silc_buffer_reset(sftp->packet);
143 }
144
145 /* Finds request by request ID. */
146
147 static SilcSFTPRequest silc_sftp_find_request(SilcSFTPClient sftp,
148                                               SilcUInt32 id)
149 {
150   SilcSFTPRequest req;
151
152   SILC_LOG_DEBUG(("Finding request ID: %d", id));
153
154   silc_list_start(sftp->requests);
155   while ((req = silc_list_get(sftp->requests)) != SILC_LIST_END) {
156     if (req->id == id)
157       return req;
158   }
159
160   SILC_LOG_DEBUG(("Unknown request ID %d", id));
161
162   return NULL;
163 }
164
165 /* Function used to call the request callback indicated by the `req'. The
166    `status' will be sent to the callback function as the status of the
167    operation. The variable argument list includes the status and req->type
168    specific data. */
169
170 static void silc_sftp_call_request(SilcSFTPClient sftp,
171                                    SilcSFTPRequest req,
172                                    SilcSFTPPacket type,
173                                    SilcSFTPStatus status, ...)
174 {
175   va_list vp;
176
177   SILC_LOG_DEBUG(("Start"));
178
179   va_start(vp, status);
180
181   switch (req->type) {
182   case SILC_SFTP_READ:
183     {
184       /* Data returned */
185       unsigned char *data;
186       SilcUInt32 data_len;
187
188       if (status != SILC_SFTP_STATUS_OK) {
189         if (req->data)
190           (*req->data)((SilcSFTP)sftp, status, NULL, 0, req->context);
191         break;
192       }
193
194       data = (unsigned char *)va_arg(vp, unsigned char *);
195       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
196
197       if (req->data)
198         (*req->data)((SilcSFTP)sftp, status, (const unsigned char *)data,
199                      data_len, req->context);
200     }
201     break;
202
203   case SILC_SFTP_OPEN:
204   case SILC_SFTP_OPENDIR:
205     {
206       /* Handle returned */
207       SilcSFTPHandle handle;
208       unsigned char *hdata;
209       SilcUInt32 hdata_len;
210
211       if (status != SILC_SFTP_STATUS_OK) {
212         if (req->handle)
213           (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
214         break;
215       }
216
217       hdata = (unsigned char *)va_arg(vp, unsigned char *);
218       hdata_len = (SilcUInt32)va_arg(vp, SilcUInt32);
219       handle = silc_sftp_handle_create(hdata, hdata_len);
220       if (!handle) {
221         if (req->handle)
222           (*req->handle)((SilcSFTP)sftp, status, NULL, req->context);
223         break;
224       }
225
226       if (req->handle)
227         (*req->handle)((SilcSFTP)sftp, status, handle, req->context);
228     }
229     break;
230
231   case SILC_SFTP_CLOSE:
232   case SILC_SFTP_WRITE:
233   case SILC_SFTP_REMOVE:
234   case SILC_SFTP_RENAME:
235   case SILC_SFTP_MKDIR:
236   case SILC_SFTP_RMDIR:
237   case SILC_SFTP_SETSTAT:
238   case SILC_SFTP_FSETSTAT:
239   case SILC_SFTP_SYMLINK:
240     {
241       /* Status returned */
242       char *message, *language_tag;
243
244       message = (char *)va_arg(vp, char *);
245       language_tag = (char *)va_arg(vp, char *);
246
247       if (req->status)
248         (*req->status)((SilcSFTP)sftp, status, (const char *)message,
249                        (const char *)language_tag, req->context);
250     }
251     break;
252
253   case SILC_SFTP_STAT:
254   case SILC_SFTP_LSTAT:
255   case SILC_SFTP_FSTAT:
256     {
257       /* Attributes returned */
258       SilcSFTPAttributes attr;
259
260       if (status != SILC_SFTP_STATUS_OK) {
261         if (req->attr)
262           (*req->attr)((SilcSFTP)sftp, status, NULL, req->context);
263         break;
264       }
265
266       attr = (SilcSFTPAttributes)va_arg(vp, SilcSFTPAttributes);
267
268       if (req->attr)
269         (*req->attr)((SilcSFTP)sftp, status, (const SilcSFTPAttributes)attr,
270                      req->context);
271     }
272     break;
273
274   case SILC_SFTP_READDIR:
275   case SILC_SFTP_REALPATH:
276   case SILC_SFTP_READLINK:
277     {
278       /* Name(s) returned */
279       SilcSFTPName name;
280
281       if (status != SILC_SFTP_STATUS_OK) {
282         if (req->name)
283           (*req->name)((SilcSFTP)sftp, status, NULL, req->context);
284         break;
285       }
286
287       name = (SilcSFTPName)va_arg(vp, SilcSFTPName);
288
289       if (req->name)
290         (*req->name)((SilcSFTP)sftp, status, name, req->context);
291     }
292     break;
293
294   case SILC_SFTP_EXTENDED:
295     {
296       /* Extended reply returned */
297       unsigned char *data;
298       SilcUInt32 data_len;
299
300       if (status != SILC_SFTP_STATUS_OK) {
301         if (req->extended)
302           (*req->extended)((SilcSFTP)sftp, status, NULL, 0, req->context);
303         break;
304       }
305
306       data = (unsigned char *)va_arg(vp, unsigned char *);
307       data_len = (SilcUInt32)va_arg(vp, SilcUInt32);
308
309       if (req->extended)
310         (*req->extended)((SilcSFTP)sftp, status, (const unsigned char *)data,
311                          data_len, req->context);
312     }
313     break;
314
315   default:
316     SILC_LOG_DEBUG(("Unknown request type %d", req->type));
317     break;
318   }
319
320   /* Remove this request */
321   silc_list_del(sftp->requests, req);
322   silc_free(req);
323
324   va_end(vp);
325 }
326
327 /* Handles stream I/O */
328
329 static void silc_sftp_client_io(SilcStream stream, SilcStreamStatus status,
330                                 void *context)
331 {
332   SilcSFTPClient sftp = context;
333   unsigned char inbuf[65536];
334   SilcBufferStruct packet;
335   int ret;
336
337   switch (status) {
338   case SILC_STREAM_CAN_READ:
339     SILC_LOG_DEBUG(("Reading data from stream"));
340
341     /* Read data from stream */
342     ret = silc_stream_read(stream, inbuf, sizeof(inbuf));
343     if (ret <= 0) {
344       if (ret == 0)
345         sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
346       if (ret == -2)
347         sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
348       return;
349     }
350
351     SILC_LOG_DEBUG(("Read %d bytes", ret));
352
353     /* Now process the SFTP packet */
354     silc_buffer_set(&packet, inbuf, ret);
355     silc_sftp_client_receive_process(context, &packet);
356     break;
357
358   case SILC_STREAM_CAN_WRITE:
359     if (!silc_buffer_headlen(sftp->packet))
360       return;
361
362     SILC_LOG_DEBUG(("Writing pending data to stream"));
363
364     /* Write pending data to stream */
365     silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet));
366     while (silc_buffer_len(sftp->packet) > 0) {
367       ret = silc_stream_write(stream, sftp->packet->data,
368                               silc_buffer_len(sftp->packet));
369       if (ret == 0) {
370         sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
371         silc_buffer_reset(sftp->packet);
372         return;
373       }
374
375       if (ret == -2) {
376         sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
377         silc_buffer_reset(sftp->packet);
378         return;
379       }
380
381       if (ret == -1)
382         return;
383
384       /* Wrote data */
385       silc_buffer_pull(sftp->packet, ret);
386     }
387     break;
388
389   default:
390     break;
391   }
392 }
393
394 /* Starts SFTP client and returns context for it. */
395
396 SilcSFTP silc_sftp_client_start(SilcStream stream,
397                                 SilcSchedule schedule,
398                                 SilcSFTPVersionCallback version_cb,
399                                 SilcSFTPErrorCallback error_cb,
400                                 void *context)
401 {
402   SilcSFTPClient sftp;
403
404   SILC_LOG_DEBUG(("Starting SFTP client"));
405
406   if (!stream)
407     return NULL;
408
409   sftp = silc_calloc(1, sizeof(*sftp));
410   if (!sftp)
411     return NULL;
412   sftp->stream = stream;
413   sftp->version = version_cb;
414   sftp->error = error_cb;
415   sftp->context = context;
416   sftp->schedule = schedule;
417   silc_list_init(sftp->requests, struct SilcSFTPRequestStruct, next);
418
419   /* We handle the stream now */
420   silc_stream_set_notifier(stream, schedule, silc_sftp_client_io, sftp);
421
422   /* Send the SFTP session initialization to the server */
423   silc_sftp_send_packet(sftp, SILC_SFTP_INIT, 4,
424                         SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
425                         SILC_STR_END);
426
427   return (SilcSFTP)sftp;
428 }
429
430 /* Shutdown's the SFTP client.  The caller is responsible of closing
431    the associated socket connection.  The SFTP context is freed and is
432    invalid after this function returns. */
433
434 void silc_sftp_client_shutdown(SilcSFTP context)
435 {
436   SilcSFTPClient sftp = (SilcSFTPClient)context;
437
438   silc_stream_set_notifier(sftp->stream, sftp->schedule, NULL, NULL);
439   if (sftp->packet)
440     silc_buffer_free(sftp->packet);
441   silc_free(sftp);
442 }
443
444 /* Function that is called to process the incmoing SFTP packet. */
445
446 void silc_sftp_client_receive_process(SilcSFTP context, SilcBuffer buffer)
447 {
448   SilcSFTPClient sftp = (SilcSFTPClient)context;
449   SilcSFTPRequest req;
450   SilcSFTPPacket type;
451   unsigned char *payload = NULL;
452   SilcUInt32 payload_len;
453   int ret;
454   SilcBufferStruct buf;
455   SilcUInt32 id;
456
457   SILC_LOG_DEBUG(("Process SFTP packet"));
458
459   /* Parse the packet */
460   type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
461   if (type <= 0)
462     return;
463
464   silc_buffer_set(&buf, payload, payload_len);
465
466   switch (type) {
467   case SILC_SFTP_DATA:
468     {
469       unsigned char *data = NULL;
470       SilcUInt32 data_len = 0;
471
472       SILC_LOG_DEBUG(("Data packet"));
473
474       ret = silc_buffer_unformat(&buf,
475                                  SILC_STR_UI_INT(&id),
476                                  SILC_STR_UI32_NSTRING(&data, &data_len),
477                                  SILC_STR_END);
478       if (ret < 0)
479         break;
480
481       /* Get request */
482       req = silc_sftp_find_request(sftp, id);
483       if (!req)
484         break;
485
486       /* Call the callback */
487       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
488                              data, data_len);
489     }
490     break;
491
492   case SILC_SFTP_VERSION:
493     {
494       SilcSFTPVersion version;
495
496       SILC_LOG_DEBUG(("Version packet"));
497
498       ret = silc_buffer_unformat(&buf,
499                                  SILC_STR_UI_INT(&version),
500                                  SILC_STR_END);
501       if (ret < 0) {
502         (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0,
503                          sftp->context);
504         break;
505       }
506
507       /* Call the callback */
508       (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version,
509                        sftp->context);
510     }
511     break;
512
513   case SILC_SFTP_STATUS:
514     {
515       SilcUInt32 status;
516       char *message = NULL, *language_tag = NULL;
517
518       SILC_LOG_DEBUG(("Status packet"));
519
520       ret = silc_buffer_unformat(&buf,
521                                  SILC_STR_UI_INT(&id),
522                                  SILC_STR_UI_INT(&status),
523                                  SILC_STR_END);
524       if (ret < 0)
525         break;
526
527       if (status != SILC_SFTP_STATUS_OK) {
528         silc_buffer_pull(&buf, 8);
529         ret = silc_buffer_unformat(&buf,
530                                    SILC_STR_UI32_STRING_ALLOC(&message),
531                                    SILC_STR_UI32_STRING_ALLOC(&language_tag),
532                                    SILC_STR_END);
533         if (ret < 0)
534           break;
535
536         silc_buffer_push(&buf, 8);
537       }
538
539       /* Get request */
540       req = silc_sftp_find_request(sftp, id);
541       if (!req) {
542         silc_free(message);
543         silc_free(language_tag);
544         break;
545       }
546
547       /* Call the callback */
548       silc_sftp_call_request(sftp, req, type, status, message, language_tag);
549
550       silc_free(message);
551       silc_free(language_tag);
552     }
553     break;
554
555   case SILC_SFTP_HANDLE:
556     {
557       unsigned char *handle = NULL;
558       SilcUInt32 handle_len;
559
560       SILC_LOG_DEBUG(("Handle packet"));
561
562       ret = silc_buffer_unformat(&buf,
563                                  SILC_STR_UI_INT(&id),
564                                  SILC_STR_UI32_NSTRING(&handle,
565                                                        &handle_len),
566                                  SILC_STR_END);
567       if (ret < 0)
568         break;
569
570       /* Get request */
571       req = silc_sftp_find_request(sftp, id);
572       if (!req)
573         break;
574
575       /* Call the callback */
576       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
577                              handle, handle_len);
578     }
579     break;
580
581   case SILC_SFTP_NAME:
582     {
583       SilcUInt32 count;
584       SilcSFTPName name = NULL;
585
586       SILC_LOG_DEBUG(("Name packet"));
587
588       ret = silc_buffer_unformat(&buf,
589                                  SILC_STR_UI_INT(&id),
590                                  SILC_STR_UI_INT(&count),
591                                  SILC_STR_END);
592       if (ret < 0)
593         break;
594
595       /* Get request */
596       req = silc_sftp_find_request(sftp, id);
597       if (!req)
598         break;
599
600       silc_buffer_pull(&buf, 8);
601       name = silc_sftp_name_decode(count, &buf);
602       if (!name)
603         break;
604       silc_buffer_push(&buf, 8);
605
606       /* Call the callback */
607       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, name);
608       silc_sftp_name_free(name);
609     }
610     break;
611
612   case SILC_SFTP_ATTRS:
613     {
614       SilcSFTPAttributes attr = NULL;
615       unsigned char *data;
616       SilcBufferStruct tmpbuf;
617
618       SILC_LOG_DEBUG(("Attributes packet"));
619
620       ret =
621         silc_buffer_unformat(&buf,
622                              SILC_STR_UI_INT(&id),
623                              SILC_STR_DATA(&data, silc_buffer_len(&buf) - 4),
624                              SILC_STR_END);
625       if (ret < 0)
626         break;
627
628       /* Get request */
629       req = silc_sftp_find_request(sftp, id);
630       if (!req)
631         break;
632
633       silc_buffer_set(&tmpbuf, data, silc_buffer_len(&buf) - 4);
634       attr = silc_sftp_attr_decode(&tmpbuf);
635       if (!attr)
636         break;
637
638       /* Call the callback */
639       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, attr);
640     }
641     break;
642
643   case SILC_SFTP_EXTENDED_REPLY:
644     {
645       unsigned char *data = NULL;
646
647       SILC_LOG_DEBUG(("Extended reply packet"));
648
649       ret = silc_buffer_unformat(&buf,
650                                  SILC_STR_UI_INT(&id),
651                                  SILC_STR_DATA(&data,
652                                                silc_buffer_len(&buf) - 4),
653                                  SILC_STR_END);
654       if (ret < 0)
655         break;
656
657       /* Get request */
658       req = silc_sftp_find_request(sftp, id);
659       if (!req)
660         break;
661
662       /* Call the callback */
663       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
664                              data, silc_buffer_len(&buf) - 4);
665     }
666     break;
667
668   default:
669     break;
670   }
671 }
672
673 void silc_sftp_open(SilcSFTP sftp,
674                     const char *filename,
675                     SilcSFTPFileOperation pflags,
676                     SilcSFTPAttributes attrs,
677                     SilcSFTPHandleCallback callback,
678                     void *context)
679 {
680   SilcSFTPClient client = (SilcSFTPClient)sftp;
681   SilcSFTPRequest req;
682   SilcBuffer attrs_buf;
683   SilcUInt32 len = 0;
684
685   SILC_LOG_DEBUG(("Open request"));
686
687   req = silc_calloc(1, sizeof(*req));
688   if (!req)
689     return;
690   req->id = client->id++;
691   req->type = SILC_SFTP_OPEN;
692   req->handle = callback;
693   req->context = context;
694   silc_list_add(client->requests, req);
695
696   attrs_buf = silc_sftp_attr_encode(attrs);
697   if (!attrs_buf)
698     return;
699   len = 4 + 4 + strlen(filename) + 4 + silc_buffer_len(attrs_buf);
700
701   silc_sftp_send_packet(client, req->type, len,
702                         SILC_STR_UI_INT(req->id),
703                         SILC_STR_UI_INT(strlen(filename)),
704                         SILC_STR_UI32_STRING(filename),
705                         SILC_STR_UI_INT(pflags),
706                         SILC_STR_UI_XNSTRING(attrs_buf->data,
707                                              silc_buffer_len(attrs_buf)),
708                         SILC_STR_END);
709
710   silc_buffer_free(attrs_buf);
711 }
712
713 void silc_sftp_close(SilcSFTP sftp,
714                      SilcSFTPHandle handle,
715                      SilcSFTPStatusCallback callback,
716                      void *context)
717 {
718   SilcSFTPClient client = (SilcSFTPClient)sftp;
719   SilcSFTPRequest req;
720   SilcUInt32 len = 0;
721   const unsigned char *hdata;
722   SilcUInt32 hdata_len;
723
724   SILC_LOG_DEBUG(("Close request"));
725
726   req = silc_calloc(1, sizeof(*req));
727   if (!req)
728     return;
729   req->id = client->id++;
730   req->type = SILC_SFTP_CLOSE;
731   req->status = callback;
732   req->context = context;
733   silc_list_add(client->requests, req);
734
735   silc_sftp_handle_get(handle, &hdata, &hdata_len);
736   len = 4 + 4 + hdata_len;
737
738   silc_sftp_send_packet(client, req->type, len,
739                         SILC_STR_UI_INT(req->id),
740                         SILC_STR_UI_INT(hdata_len),
741                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
742                         SILC_STR_END);
743   silc_sftp_handle_delete(handle);
744 }
745
746 void silc_sftp_read(SilcSFTP sftp,
747                     SilcSFTPHandle handle,
748                     SilcUInt64 offset,
749                     SilcUInt32 len,
750                     SilcSFTPDataCallback callback,
751                     void *context)
752 {
753   SilcSFTPClient client = (SilcSFTPClient)sftp;
754   SilcSFTPRequest req;
755   SilcUInt32 len2 = 0;
756   const unsigned char *hdata;
757   SilcUInt32 hdata_len;
758
759   SILC_LOG_DEBUG(("Read request"));
760
761   req = silc_calloc(1, sizeof(*req));
762   if (!req)
763     return;
764   req->id = client->id++;
765   req->type = SILC_SFTP_READ;
766   req->data = callback;
767   req->context = context;
768   silc_list_add(client->requests, req);
769
770   silc_sftp_handle_get(handle, &hdata, &hdata_len);
771   len2 = 4 + 4 + hdata_len + 8 + 4;
772
773   silc_sftp_send_packet(client, req->type, len2,
774                         SILC_STR_UI_INT(req->id),
775                         SILC_STR_UI_INT(hdata_len),
776                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
777                         SILC_STR_UI_INT64(offset),
778                         SILC_STR_UI_INT(len),
779                         SILC_STR_END);
780 }
781
782 void silc_sftp_write(SilcSFTP sftp,
783                      SilcSFTPHandle handle,
784                      SilcUInt64 offset,
785                      const unsigned char *data,
786                      SilcUInt32 data_len,
787                      SilcSFTPStatusCallback callback,
788                      void *context)
789 {
790   SilcSFTPClient client = (SilcSFTPClient)sftp;
791   SilcSFTPRequest req;
792   SilcUInt32 len = 0;
793   const unsigned char *hdata;
794   SilcUInt32 hdata_len;
795
796   SILC_LOG_DEBUG(("Write request"));
797
798   req = silc_calloc(1, sizeof(*req));
799   if (!req)
800     return;
801   req->id = client->id++;
802   req->type = SILC_SFTP_WRITE;
803   req->status = callback;
804   req->context = context;
805   silc_list_add(client->requests, req);
806
807   silc_sftp_handle_get(handle, &hdata, &hdata_len);
808   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
809
810   silc_sftp_send_packet(client, req->type, len,
811                         SILC_STR_UI_INT(req->id),
812                         SILC_STR_UI_INT(hdata_len),
813                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
814                         SILC_STR_UI_INT64(offset),
815                         SILC_STR_UI_INT(data_len),
816                         SILC_STR_UI_XNSTRING(data, data_len),
817                         SILC_STR_END);
818 }
819
820 void silc_sftp_remove(SilcSFTP sftp,
821                       const char *filename,
822                       SilcSFTPStatusCallback callback,
823                       void *context)
824 {
825   SilcSFTPClient client = (SilcSFTPClient)sftp;
826   SilcSFTPRequest req;
827   SilcUInt32 len = 0;
828
829   SILC_LOG_DEBUG(("Remove request"));
830
831   req = silc_calloc(1, sizeof(*req));
832   if (!req)
833     return;
834   req->id = client->id++;
835   req->type = SILC_SFTP_REMOVE;
836   req->status = callback;
837   req->context = context;
838   silc_list_add(client->requests, req);
839
840   len = 4 + 4 + strlen(filename);
841
842   silc_sftp_send_packet(client, req->type, len,
843                         SILC_STR_UI_INT(req->id),
844                         SILC_STR_UI_INT(strlen(filename)),
845                         SILC_STR_UI32_STRING(filename),
846                         SILC_STR_END);
847 }
848
849 void silc_sftp_rename(SilcSFTP sftp,
850                       const char *oldname,
851                       const char *newname,
852                       SilcSFTPStatusCallback callback,
853                       void *context)
854 {
855   SilcSFTPClient client = (SilcSFTPClient)sftp;
856   SilcSFTPRequest req;
857   SilcUInt32 len = 0;
858
859   SILC_LOG_DEBUG(("Rename request"));
860
861   req = silc_calloc(1, sizeof(*req));
862   if (!req)
863     return;
864   req->id = client->id++;
865   req->type = SILC_SFTP_RENAME;
866   req->status = callback;
867   req->context = context;
868   silc_list_add(client->requests, req);
869
870   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
871
872   silc_sftp_send_packet(client, req->type, len,
873                         SILC_STR_UI_INT(req->id),
874                         SILC_STR_UI_INT(strlen(oldname)),
875                         SILC_STR_UI32_STRING(oldname),
876                         SILC_STR_UI_INT(strlen(newname)),
877                         SILC_STR_UI32_STRING(newname),
878                         SILC_STR_END);
879 }
880
881 void silc_sftp_mkdir(SilcSFTP sftp,
882                      const char *path,
883                      SilcSFTPAttributes attrs,
884                      SilcSFTPStatusCallback callback,
885                      void *context)
886 {
887   SilcSFTPClient client = (SilcSFTPClient)sftp;
888   SilcSFTPRequest req;
889   SilcUInt32 len = 0;
890   SilcBuffer attrs_buf;
891
892   SILC_LOG_DEBUG(("Mkdir request"));
893
894   req = silc_calloc(1, sizeof(*req));
895   if (!req)
896     return;
897   req->id = client->id++;
898   req->type = SILC_SFTP_MKDIR;
899   req->status = callback;
900   req->context = context;
901   silc_list_add(client->requests, req);
902
903   attrs_buf = silc_sftp_attr_encode(attrs);
904   if (!attrs_buf)
905     return;
906   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
907
908   silc_sftp_send_packet(client, req->type, len,
909                         SILC_STR_UI_INT(req->id),
910                         SILC_STR_UI_INT(strlen(path)),
911                         SILC_STR_UI32_STRING(path),
912                         SILC_STR_UI_XNSTRING(attrs_buf->data,
913                                              silc_buffer_len(attrs_buf)),
914                         SILC_STR_END);
915
916   silc_buffer_free(attrs_buf);
917 }
918
919 void silc_sftp_rmdir(SilcSFTP sftp,
920                      const char *path,
921                      SilcSFTPStatusCallback callback,
922                      void *context)
923 {
924   SilcSFTPClient client = (SilcSFTPClient)sftp;
925   SilcSFTPRequest req;
926   SilcUInt32 len = 0;
927
928   SILC_LOG_DEBUG(("Rmdir request"));
929
930   req = silc_calloc(1, sizeof(*req));
931   if (!req)
932     return;
933   req->id = client->id++;
934   req->type = SILC_SFTP_RMDIR;
935   req->status = callback;
936   req->context = context;
937   silc_list_add(client->requests, req);
938
939   len = 4 + 4 + strlen(path);
940
941   silc_sftp_send_packet(client, req->type, len,
942                         SILC_STR_UI_INT(req->id),
943                         SILC_STR_UI_INT(strlen(path)),
944                         SILC_STR_UI32_STRING(path),
945                         SILC_STR_END);
946 }
947
948 void silc_sftp_opendir(SilcSFTP sftp,
949                        const char *path,
950                        SilcSFTPHandleCallback callback,
951                        void *context)
952 {
953   SilcSFTPClient client = (SilcSFTPClient)sftp;
954   SilcSFTPRequest req;
955   SilcUInt32 len = 0;
956
957   SILC_LOG_DEBUG(("Opendir request"));
958
959   req = silc_calloc(1, sizeof(*req));
960   if (!req)
961     return;
962   req->id = client->id++;
963   req->type = SILC_SFTP_OPENDIR;
964   req->handle = callback;
965   req->context = context;
966   silc_list_add(client->requests, req);
967
968   len = 4 + 4 + strlen(path);
969
970   silc_sftp_send_packet(client, req->type, len,
971                         SILC_STR_UI_INT(req->id),
972                         SILC_STR_UI_INT(strlen(path)),
973                         SILC_STR_UI32_STRING(path),
974                         SILC_STR_END);
975 }
976
977 void silc_sftp_readdir(SilcSFTP sftp,
978                        SilcSFTPHandle handle,
979                        SilcSFTPNameCallback callback,
980                        void *context)
981 {
982   SilcSFTPClient client = (SilcSFTPClient)sftp;
983   SilcSFTPRequest req;
984   SilcUInt32 len = 0;
985   const unsigned char *hdata;
986   SilcUInt32 hdata_len;
987
988   SILC_LOG_DEBUG(("Readdir request"));
989
990   req = silc_calloc(1, sizeof(*req));
991   if (!req)
992     return;
993   req->id = client->id++;
994   req->type = SILC_SFTP_READDIR;
995   req->name = callback;
996   req->context = context;
997   silc_list_add(client->requests, req);
998
999   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1000   len = 4 + 4 + hdata_len;
1001
1002   silc_sftp_send_packet(client, req->type, len,
1003                         SILC_STR_UI_INT(req->id),
1004                         SILC_STR_UI_INT(hdata_len),
1005                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1006                         SILC_STR_END);
1007 }
1008
1009 void silc_sftp_stat(SilcSFTP sftp,
1010                     const char *path,
1011                     SilcSFTPAttrCallback callback,
1012                     void *context)
1013 {
1014   SilcSFTPClient client = (SilcSFTPClient)sftp;
1015   SilcSFTPRequest req;
1016   SilcUInt32 len = 0;
1017
1018   SILC_LOG_DEBUG(("Stat request"));
1019
1020   req = silc_calloc(1, sizeof(*req));
1021   if (!req)
1022     return;
1023   req->id = client->id++;
1024   req->type = SILC_SFTP_STAT;
1025   req->attr = callback;
1026   req->context = context;
1027   silc_list_add(client->requests, req);
1028
1029   len = 4 + 4 + strlen(path);
1030
1031   silc_sftp_send_packet(client, req->type, len,
1032                         SILC_STR_UI_INT(req->id),
1033                         SILC_STR_UI_INT(strlen(path)),
1034                         SILC_STR_UI32_STRING(path),
1035                         SILC_STR_END);
1036 }
1037
1038 void silc_sftp_lstat(SilcSFTP sftp,
1039                      const char *path,
1040                      SilcSFTPAttrCallback callback,
1041                      void *context)
1042 {
1043   SilcSFTPClient client = (SilcSFTPClient)sftp;
1044   SilcSFTPRequest req;
1045   SilcUInt32 len = 0;
1046
1047   SILC_LOG_DEBUG(("Lstat request"));
1048
1049   req = silc_calloc(1, sizeof(*req));
1050   if (!req)
1051     return;
1052   req->id = client->id++;
1053   req->type = SILC_SFTP_LSTAT;
1054   req->attr = callback;
1055   req->context = context;
1056   silc_list_add(client->requests, req);
1057
1058   len = 4 + 4 + strlen(path);
1059
1060   silc_sftp_send_packet(client, req->type, len,
1061                         SILC_STR_UI_INT(req->id),
1062                         SILC_STR_UI_INT(strlen(path)),
1063                         SILC_STR_UI32_STRING(path),
1064                         SILC_STR_END);
1065 }
1066
1067 void silc_sftp_fstat(SilcSFTP sftp,
1068                      SilcSFTPHandle handle,
1069                      SilcSFTPAttrCallback callback,
1070                      void *context)
1071 {
1072   SilcSFTPClient client = (SilcSFTPClient)sftp;
1073   SilcSFTPRequest req;
1074   SilcUInt32 len = 0;
1075   const unsigned char *hdata;
1076   SilcUInt32 hdata_len;
1077
1078   SILC_LOG_DEBUG(("Fstat request"));
1079
1080   req = silc_calloc(1, sizeof(*req));
1081   if (!req)
1082     return;
1083   req->id = client->id++;
1084   req->type = SILC_SFTP_FSTAT;
1085   req->attr = callback;
1086   req->context = context;
1087   silc_list_add(client->requests, req);
1088
1089   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1090   len = 4 + 4 + hdata_len;
1091
1092   silc_sftp_send_packet(client, req->type, len,
1093                         SILC_STR_UI_INT(req->id),
1094                         SILC_STR_UI_INT(hdata_len),
1095                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1096                         SILC_STR_END);
1097 }
1098
1099 void silc_sftp_setstat(SilcSFTP sftp,
1100                        const char *path,
1101                        SilcSFTPAttributes attrs,
1102                        SilcSFTPStatusCallback callback,
1103                        void *context)
1104 {
1105   SilcSFTPClient client = (SilcSFTPClient)sftp;
1106   SilcSFTPRequest req;
1107   SilcUInt32 len = 0;
1108   SilcBuffer attrs_buf;
1109
1110   SILC_LOG_DEBUG(("Setstat request"));
1111
1112   req = silc_calloc(1, sizeof(*req));
1113   if (!req)
1114     return;
1115   req->id = client->id++;
1116   req->type = SILC_SFTP_SETSTAT;
1117   req->status = callback;
1118   req->context = context;
1119   silc_list_add(client->requests, req);
1120
1121   attrs_buf = silc_sftp_attr_encode(attrs);
1122   if (!attrs_buf)
1123     return;
1124   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
1125
1126   silc_sftp_send_packet(client, req->type, len,
1127                         SILC_STR_UI_INT(req->id),
1128                         SILC_STR_UI_INT(strlen(path)),
1129                         SILC_STR_UI32_STRING(path),
1130                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1131                                              silc_buffer_len(attrs_buf)),
1132                         SILC_STR_END);
1133
1134   silc_buffer_free(attrs_buf);
1135 }
1136
1137 void silc_sftp_fsetstat(SilcSFTP sftp,
1138                         SilcSFTPHandle handle,
1139                         SilcSFTPAttributes attrs,
1140                         SilcSFTPStatusCallback callback,
1141                         void *context)
1142 {
1143   SilcSFTPClient client = (SilcSFTPClient)sftp;
1144   SilcSFTPRequest req;
1145   SilcUInt32 len = 0;
1146   SilcBuffer attrs_buf;
1147   const unsigned char *hdata;
1148   SilcUInt32 hdata_len;
1149
1150   SILC_LOG_DEBUG(("Fsetstat request"));
1151
1152   req = silc_calloc(1, sizeof(*req));
1153   if (!req)
1154     return;
1155   req->id = client->id++;
1156   req->type = SILC_SFTP_FSETSTAT;
1157   req->status = callback;
1158   req->context = context;
1159   silc_list_add(client->requests, req);
1160
1161   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1162   attrs_buf = silc_sftp_attr_encode(attrs);
1163   if (!attrs_buf)
1164     return;
1165   len = 4 + 4 + hdata_len + silc_buffer_len(attrs_buf);
1166
1167   silc_sftp_send_packet(client, req->type, len,
1168                         SILC_STR_UI_INT(req->id),
1169                         SILC_STR_UI_INT(hdata_len),
1170                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1171                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1172                                              silc_buffer_len(attrs_buf)),
1173                         SILC_STR_END);
1174
1175   silc_buffer_free(attrs_buf);
1176 }
1177
1178 void silc_sftp_readlink(SilcSFTP sftp,
1179                         const char *path,
1180                         SilcSFTPNameCallback callback,
1181                         void *context)
1182 {
1183   SilcSFTPClient client = (SilcSFTPClient)sftp;
1184   SilcSFTPRequest req;
1185   SilcUInt32 len = 0;
1186
1187   SILC_LOG_DEBUG(("Readlink request"));
1188
1189   req = silc_calloc(1, sizeof(*req));
1190   if (!req)
1191     return;
1192   req->id = client->id++;
1193   req->type = SILC_SFTP_READLINK;
1194   req->name = callback;
1195   req->context = context;
1196   silc_list_add(client->requests, req);
1197
1198   len = 4 + 4 + strlen(path);
1199
1200   silc_sftp_send_packet(client, req->type, len,
1201                         SILC_STR_UI_INT(req->id),
1202                         SILC_STR_UI_INT(strlen(path)),
1203                         SILC_STR_UI32_STRING(path),
1204                         SILC_STR_END);
1205 }
1206
1207 void silc_sftp_symlink(SilcSFTP sftp,
1208                        const char *linkpath,
1209                        const char *targetpath,
1210                        SilcSFTPStatusCallback callback,
1211                        void *context)
1212 {
1213   SilcSFTPClient client = (SilcSFTPClient)sftp;
1214   SilcSFTPRequest req;
1215   SilcUInt32 len = 0;
1216
1217   SILC_LOG_DEBUG(("Symlink request"));
1218
1219   req = silc_calloc(1, sizeof(*req));
1220   if (!req)
1221     return;
1222   req->id = client->id++;
1223   req->type = SILC_SFTP_SYMLINK;
1224   req->status = callback;
1225   req->context = context;
1226   silc_list_add(client->requests, req);
1227
1228   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1229
1230   silc_sftp_send_packet(client, req->type, len,
1231                         SILC_STR_UI_INT(req->id),
1232                         SILC_STR_UI_INT(strlen(linkpath)),
1233                         SILC_STR_UI32_STRING(linkpath),
1234                         SILC_STR_UI_INT(strlen(targetpath)),
1235                         SILC_STR_UI32_STRING(targetpath),
1236                         SILC_STR_END);
1237 }
1238
1239 void silc_sftp_realpath(SilcSFTP sftp,
1240                         const char *path,
1241                         SilcSFTPNameCallback callback,
1242                         void *context)
1243 {
1244   SilcSFTPClient client = (SilcSFTPClient)sftp;
1245   SilcSFTPRequest req;
1246   SilcUInt32 len = 0;
1247
1248   SILC_LOG_DEBUG(("Realpath request"));
1249
1250   req = silc_calloc(1, sizeof(*req));
1251   if (!req)
1252     return;
1253   req->id = client->id++;
1254   req->type = SILC_SFTP_REALPATH;
1255   req->name = callback;
1256   req->context = context;
1257   silc_list_add(client->requests, req);
1258
1259   len = 4 + 4 + strlen(path);
1260
1261   silc_sftp_send_packet(client, req->type, len,
1262                         SILC_STR_UI_INT(req->id),
1263                         SILC_STR_UI_INT(strlen(path)),
1264                         SILC_STR_UI32_STRING(path),
1265                         SILC_STR_END);
1266 }
1267
1268 void silc_sftp_extended(SilcSFTP sftp,
1269                         const char *request,
1270                         const unsigned char *data,
1271                         SilcUInt32 data_len,
1272                         SilcSFTPExtendedCallback callback,
1273                         void *context)
1274 {
1275   SilcSFTPClient client = (SilcSFTPClient)sftp;
1276   SilcSFTPRequest req;
1277   SilcUInt32 len = 0;
1278
1279   SILC_LOG_DEBUG(("Extended request"));
1280
1281   req = silc_calloc(1, sizeof(*req));
1282   if (!req)
1283     return;
1284   req->id = client->id++;
1285   req->type = SILC_SFTP_WRITE;
1286   req->extended = callback;
1287   req->context = context;
1288   silc_list_add(client->requests, req);
1289
1290   len = 4 + 4 + strlen(request) + data_len;
1291
1292   silc_sftp_send_packet(client, req->type, len,
1293                         SILC_STR_UI_INT(req->id),
1294                         SILC_STR_UI_INT(strlen(request)),
1295                         SILC_STR_UI32_STRING(request),
1296                         SILC_STR_UI_XNSTRING(data, data_len),
1297                         SILC_STR_END);
1298 }