3fb2ee024f01332594c16d1347f09be661254989
[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     break;
317   }
318
319   /* Remove this request */
320   silc_list_del(sftp->requests, req);
321   silc_free(req);
322
323   va_end(vp);
324 }
325
326 /* Handles stream I/O */
327
328 static void silc_sftp_client_io(SilcStream stream, SilcStreamStatus status,
329                                 void *context)
330 {
331   SilcSFTPClient sftp = context;
332   unsigned char inbuf[30720];
333   SilcBufferStruct packet;
334   int ret;
335
336   switch (status) {
337   case SILC_STREAM_CAN_READ:
338     SILC_LOG_DEBUG(("Reading data from stream"));
339
340     /* Read data from stream */
341     ret = silc_stream_read(stream, inbuf, sizeof(inbuf));
342     if (ret <= 0) {
343       if (ret == 0)
344         sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
345       if (ret == -2)
346         sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
347       return;
348     }
349
350     /* Now process the SFTP packet */
351     silc_buffer_set(&packet, inbuf, ret);
352     silc_sftp_client_receive_process(context, &packet);
353     break;
354
355   case SILC_STREAM_CAN_WRITE:
356     if (!silc_buffer_headlen(sftp->packet))
357       return;
358
359     SILC_LOG_DEBUG(("Writing pending data to stream"));
360
361     /* Write pending data to stream */
362     silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet));
363     while (silc_buffer_len(sftp->packet) > 0) {
364       ret = silc_stream_write(stream, sftp->packet->data,
365                               silc_buffer_len(sftp->packet));
366       if (ret == 0) {
367         sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
368         silc_buffer_reset(sftp->packet);
369         return;
370       }
371
372       if (ret == -2) {
373         sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
374         silc_buffer_reset(sftp->packet);
375         return;
376       }
377
378       if (ret == -1)
379         return;
380
381       /* Wrote data */
382       silc_buffer_pull(sftp->packet, ret);
383     }
384     break;
385
386   default:
387     break;
388   }
389 }
390
391 /* Starts SFTP client and returns context for it. */
392
393 SilcSFTP silc_sftp_client_start(SilcStream stream,
394                                 SilcSchedule schedule,
395                                 SilcSFTPVersionCallback version_cb,
396                                 SilcSFTPErrorCallback error_cb,
397                                 void *context)
398 {
399   SilcSFTPClient sftp;
400
401   SILC_LOG_DEBUG(("Starting SFTP client"));
402
403   if (!stream)
404     return NULL;
405
406   sftp = silc_calloc(1, sizeof(*sftp));
407   if (!sftp)
408     return NULL;
409   sftp->stream = stream;
410   sftp->version = version_cb;
411   sftp->error = error_cb;
412   sftp->context = context;
413   sftp->schedule = schedule;
414   silc_list_init(sftp->requests, struct SilcSFTPRequestStruct, next);
415
416   /* We handle the stream now */
417   silc_stream_set_notifier(stream, schedule, silc_sftp_client_io, sftp);
418
419   /* Send the SFTP session initialization to the server */
420   silc_sftp_send_packet(sftp, SILC_SFTP_INIT, 4,
421                         SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
422                         SILC_STR_END);
423
424   return (SilcSFTP)sftp;
425 }
426
427 /* Shutdown's the SFTP client.  The caller is responsible of closing
428    the associated socket connection.  The SFTP context is freed and is
429    invalid after this function returns. */
430
431 void silc_sftp_client_shutdown(SilcSFTP context)
432 {
433   SilcSFTPClient sftp = (SilcSFTPClient)context;
434
435   silc_stream_set_notifier(sftp->stream, sftp->schedule, NULL, NULL);
436   if (sftp->packet)
437     silc_buffer_free(sftp->packet);
438   silc_free(sftp);
439 }
440
441 /* Function that is called to process the incmoing SFTP packet. */
442
443 void silc_sftp_client_receive_process(SilcSFTP context, SilcBuffer buffer)
444 {
445   SilcSFTPClient sftp = (SilcSFTPClient)context;
446   SilcSFTPRequest req;
447   SilcSFTPPacket type;
448   unsigned char *payload = NULL;
449   SilcUInt32 payload_len;
450   int ret;
451   SilcBufferStruct buf;
452   SilcUInt32 id;
453
454   SILC_LOG_DEBUG(("Process SFTP packet"));
455
456   /* Parse the packet */
457   type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
458   if (!type)
459     return;
460
461   silc_buffer_set(&buf, payload, payload_len);
462
463   switch (type) {
464   case SILC_SFTP_DATA:
465     {
466       unsigned char *data = NULL;
467       SilcUInt32 data_len = 0;
468
469       SILC_LOG_DEBUG(("Data packet"));
470
471       ret = silc_buffer_unformat(&buf,
472                                  SILC_STR_UI_INT(&id),
473                                  SILC_STR_UI32_NSTRING(&data, &data_len),
474                                  SILC_STR_END);
475       if (ret < 0)
476         break;
477
478       /* Get request */
479       req = silc_sftp_find_request(sftp, id);
480       if (!req)
481         break;
482
483       /* Call the callback */
484       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
485                              data, data_len);
486     }
487     break;
488
489   case SILC_SFTP_VERSION:
490     {
491       SilcSFTPVersion version;
492
493       SILC_LOG_DEBUG(("Version packet"));
494
495       ret = silc_buffer_unformat(&buf,
496                                  SILC_STR_UI_INT(&version),
497                                  SILC_STR_END);
498       if (ret < 0) {
499         (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0,
500                          sftp->context);
501         break;
502       }
503
504       /* Call the callback */
505       (*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version,
506                        sftp->context);
507     }
508     break;
509
510   case SILC_SFTP_STATUS:
511     {
512       SilcUInt32 status;
513       char *message = NULL, *language_tag = NULL;
514
515       SILC_LOG_DEBUG(("Status packet"));
516
517       ret = silc_buffer_unformat(&buf,
518                                  SILC_STR_UI_INT(&id),
519                                  SILC_STR_UI_INT(&status),
520                                  SILC_STR_END);
521       if (ret < 0)
522         break;
523
524       if (status != SILC_SFTP_STATUS_OK) {
525         silc_buffer_pull(&buf, 8);
526         ret = silc_buffer_unformat(&buf,
527                                    SILC_STR_UI32_STRING_ALLOC(&message),
528                                    SILC_STR_UI32_STRING_ALLOC(&language_tag),
529                                    SILC_STR_END);
530         if (ret < 0)
531           break;
532
533         silc_buffer_push(&buf, 8);
534       }
535
536       /* Get request */
537       req = silc_sftp_find_request(sftp, id);
538       if (!req) {
539         silc_free(message);
540         silc_free(language_tag);
541         break;
542       }
543
544       /* Call the callback */
545       silc_sftp_call_request(sftp, req, type, status, message, language_tag);
546
547       silc_free(message);
548       silc_free(language_tag);
549     }
550     break;
551
552   case SILC_SFTP_HANDLE:
553     {
554       unsigned char *handle = NULL;
555       SilcUInt32 handle_len;
556
557       SILC_LOG_DEBUG(("Handle packet"));
558
559       ret = silc_buffer_unformat(&buf,
560                                  SILC_STR_UI_INT(&id),
561                                  SILC_STR_UI32_NSTRING(&handle,
562                                                        &handle_len),
563                                  SILC_STR_END);
564       if (ret < 0)
565         break;
566
567       /* Get request */
568       req = silc_sftp_find_request(sftp, id);
569       if (!req)
570         break;
571
572       /* Call the callback */
573       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
574                              handle, handle_len);
575     }
576     break;
577
578   case SILC_SFTP_NAME:
579     {
580       SilcUInt32 count;
581       SilcSFTPName name = NULL;
582
583       SILC_LOG_DEBUG(("Name packet"));
584
585       ret = silc_buffer_unformat(&buf,
586                                  SILC_STR_UI_INT(&id),
587                                  SILC_STR_UI_INT(&count),
588                                  SILC_STR_END);
589       if (ret < 0)
590         break;
591
592       /* Get request */
593       req = silc_sftp_find_request(sftp, id);
594       if (!req)
595         break;
596
597       silc_buffer_pull(&buf, 8);
598       name = silc_sftp_name_decode(count, &buf);
599       if (!name)
600         break;
601       silc_buffer_push(&buf, 8);
602
603       /* Call the callback */
604       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, name);
605       silc_sftp_name_free(name);
606     }
607     break;
608
609   case SILC_SFTP_ATTRS:
610     {
611       SilcSFTPAttributes attr = NULL;
612       unsigned char *data;
613       SilcBufferStruct tmpbuf;
614
615       SILC_LOG_DEBUG(("Attributes packet"));
616
617       ret =
618         silc_buffer_unformat(&buf,
619                              SILC_STR_UI_INT(&id),
620                              SILC_STR_DATA(&data, silc_buffer_len(&buf) - 4),
621                              SILC_STR_END);
622       if (ret < 0)
623         break;
624
625       /* Get request */
626       req = silc_sftp_find_request(sftp, id);
627       if (!req)
628         break;
629
630       silc_buffer_set(&tmpbuf, data, silc_buffer_len(&buf) - 4);
631       attr = silc_sftp_attr_decode(&tmpbuf);
632       if (!attr)
633         break;
634
635       /* Call the callback */
636       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK, attr);
637     }
638     break;
639
640   case SILC_SFTP_EXTENDED_REPLY:
641     {
642       unsigned char *data = NULL;
643
644       SILC_LOG_DEBUG(("Extended reply packet"));
645
646       ret = silc_buffer_unformat(&buf,
647                                  SILC_STR_UI_INT(&id),
648                                  SILC_STR_DATA(&data,
649                                                silc_buffer_len(&buf) - 4),
650                                  SILC_STR_END);
651       if (ret < 0)
652         break;
653
654       /* Get request */
655       req = silc_sftp_find_request(sftp, id);
656       if (!req)
657         break;
658
659       /* Call the callback */
660       silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
661                              data, silc_buffer_len(&buf) - 4);
662     }
663     break;
664
665   default:
666     break;
667   }
668 }
669
670 void silc_sftp_open(SilcSFTP sftp,
671                     const char *filename,
672                     SilcSFTPFileOperation pflags,
673                     SilcSFTPAttributes attrs,
674                     SilcSFTPHandleCallback callback,
675                     void *context)
676 {
677   SilcSFTPClient client = (SilcSFTPClient)sftp;
678   SilcSFTPRequest req;
679   SilcBuffer attrs_buf;
680   SilcUInt32 len = 0;
681
682   SILC_LOG_DEBUG(("Open request"));
683
684   req = silc_calloc(1, sizeof(*req));
685   if (!req)
686     return;
687   req->id = client->id++;
688   req->type = SILC_SFTP_OPEN;
689   req->handle = callback;
690   req->context = context;
691   silc_list_add(client->requests, req);
692
693   attrs_buf = silc_sftp_attr_encode(attrs);
694   if (!attrs_buf)
695     return;
696   len = 4 + 4 + strlen(filename) + 4 + silc_buffer_len(attrs_buf);
697
698   silc_sftp_send_packet(client, req->type, len,
699                         SILC_STR_UI_INT(req->id),
700                         SILC_STR_UI_INT(strlen(filename)),
701                         SILC_STR_UI32_STRING(filename),
702                         SILC_STR_UI_INT(pflags),
703                         SILC_STR_UI_XNSTRING(attrs_buf->data,
704                                              silc_buffer_len(attrs_buf)),
705                         SILC_STR_END);
706
707   silc_buffer_free(attrs_buf);
708 }
709
710 void silc_sftp_close(SilcSFTP sftp,
711                      SilcSFTPHandle handle,
712                      SilcSFTPStatusCallback callback,
713                      void *context)
714 {
715   SilcSFTPClient client = (SilcSFTPClient)sftp;
716   SilcSFTPRequest req;
717   SilcUInt32 len = 0;
718   const unsigned char *hdata;
719   SilcUInt32 hdata_len;
720
721   SILC_LOG_DEBUG(("Close request"));
722
723   req = silc_calloc(1, sizeof(*req));
724   if (!req)
725     return;
726   req->id = client->id++;
727   req->type = SILC_SFTP_CLOSE;
728   req->status = callback;
729   req->context = context;
730   silc_list_add(client->requests, req);
731
732   silc_sftp_handle_get(handle, &hdata, &hdata_len);
733   len = 4 + 4 + hdata_len;
734
735   silc_sftp_send_packet(client, req->type, len,
736                         SILC_STR_UI_INT(req->id),
737                         SILC_STR_UI_INT(hdata_len),
738                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
739                         SILC_STR_END);
740   silc_sftp_handle_delete(handle);
741 }
742
743 void silc_sftp_read(SilcSFTP sftp,
744                     SilcSFTPHandle handle,
745                     SilcUInt64 offset,
746                     SilcUInt32 len,
747                     SilcSFTPDataCallback callback,
748                     void *context)
749 {
750   SilcSFTPClient client = (SilcSFTPClient)sftp;
751   SilcSFTPRequest req;
752   SilcUInt32 len2 = 0;
753   const unsigned char *hdata;
754   SilcUInt32 hdata_len;
755
756   SILC_LOG_DEBUG(("Read request"));
757
758   req = silc_calloc(1, sizeof(*req));
759   if (!req)
760     return;
761   req->id = client->id++;
762   req->type = SILC_SFTP_READ;
763   req->data = callback;
764   req->context = context;
765   silc_list_add(client->requests, req);
766
767   silc_sftp_handle_get(handle, &hdata, &hdata_len);
768   len2 = 4 + 4 + hdata_len + 8 + 4;
769
770   silc_sftp_send_packet(client, req->type, len2,
771                         SILC_STR_UI_INT(req->id),
772                         SILC_STR_UI_INT(hdata_len),
773                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
774                         SILC_STR_UI_INT64(offset),
775                         SILC_STR_UI_INT(len),
776                         SILC_STR_END);
777 }
778
779 void silc_sftp_write(SilcSFTP sftp,
780                      SilcSFTPHandle handle,
781                      SilcUInt64 offset,
782                      const unsigned char *data,
783                      SilcUInt32 data_len,
784                      SilcSFTPStatusCallback callback,
785                      void *context)
786 {
787   SilcSFTPClient client = (SilcSFTPClient)sftp;
788   SilcSFTPRequest req;
789   SilcUInt32 len = 0;
790   const unsigned char *hdata;
791   SilcUInt32 hdata_len;
792
793   SILC_LOG_DEBUG(("Write request"));
794
795   req = silc_calloc(1, sizeof(*req));
796   if (!req)
797     return;
798   req->id = client->id++;
799   req->type = SILC_SFTP_WRITE;
800   req->status = callback;
801   req->context = context;
802   silc_list_add(client->requests, req);
803
804   silc_sftp_handle_get(handle, &hdata, &hdata_len);
805   len = 4 + 4 + hdata_len + 8 + 4 + data_len;
806
807   silc_sftp_send_packet(client, req->type, len,
808                         SILC_STR_UI_INT(req->id),
809                         SILC_STR_UI_INT(hdata_len),
810                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
811                         SILC_STR_UI_INT64(offset),
812                         SILC_STR_UI_INT(data_len),
813                         SILC_STR_UI_XNSTRING(data, data_len),
814                         SILC_STR_END);
815 }
816
817 void silc_sftp_remove(SilcSFTP sftp,
818                       const char *filename,
819                       SilcSFTPStatusCallback callback,
820                       void *context)
821 {
822   SilcSFTPClient client = (SilcSFTPClient)sftp;
823   SilcSFTPRequest req;
824   SilcUInt32 len = 0;
825
826   SILC_LOG_DEBUG(("Remove request"));
827
828   req = silc_calloc(1, sizeof(*req));
829   if (!req)
830     return;
831   req->id = client->id++;
832   req->type = SILC_SFTP_REMOVE;
833   req->status = callback;
834   req->context = context;
835   silc_list_add(client->requests, req);
836
837   len = 4 + 4 + strlen(filename);
838
839   silc_sftp_send_packet(client, req->type, len,
840                         SILC_STR_UI_INT(req->id),
841                         SILC_STR_UI_INT(strlen(filename)),
842                         SILC_STR_UI32_STRING(filename),
843                         SILC_STR_END);
844 }
845
846 void silc_sftp_rename(SilcSFTP sftp,
847                       const char *oldname,
848                       const char *newname,
849                       SilcSFTPStatusCallback callback,
850                       void *context)
851 {
852   SilcSFTPClient client = (SilcSFTPClient)sftp;
853   SilcSFTPRequest req;
854   SilcUInt32 len = 0;
855
856   SILC_LOG_DEBUG(("Rename request"));
857
858   req = silc_calloc(1, sizeof(*req));
859   if (!req)
860     return;
861   req->id = client->id++;
862   req->type = SILC_SFTP_RENAME;
863   req->status = callback;
864   req->context = context;
865   silc_list_add(client->requests, req);
866
867   len = 4 + 4 + strlen(oldname) + 4 + strlen(newname);
868
869   silc_sftp_send_packet(client, req->type, len,
870                         SILC_STR_UI_INT(req->id),
871                         SILC_STR_UI_INT(strlen(oldname)),
872                         SILC_STR_UI32_STRING(oldname),
873                         SILC_STR_UI_INT(strlen(newname)),
874                         SILC_STR_UI32_STRING(newname),
875                         SILC_STR_END);
876 }
877
878 void silc_sftp_mkdir(SilcSFTP sftp,
879                      const char *path,
880                      SilcSFTPAttributes attrs,
881                      SilcSFTPStatusCallback callback,
882                      void *context)
883 {
884   SilcSFTPClient client = (SilcSFTPClient)sftp;
885   SilcSFTPRequest req;
886   SilcUInt32 len = 0;
887   SilcBuffer attrs_buf;
888
889   SILC_LOG_DEBUG(("Mkdir request"));
890
891   req = silc_calloc(1, sizeof(*req));
892   if (!req)
893     return;
894   req->id = client->id++;
895   req->type = SILC_SFTP_MKDIR;
896   req->status = callback;
897   req->context = context;
898   silc_list_add(client->requests, req);
899
900   attrs_buf = silc_sftp_attr_encode(attrs);
901   if (!attrs_buf)
902     return;
903   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
904
905   silc_sftp_send_packet(client, req->type, len,
906                         SILC_STR_UI_INT(req->id),
907                         SILC_STR_UI_INT(strlen(path)),
908                         SILC_STR_UI32_STRING(path),
909                         SILC_STR_UI_XNSTRING(attrs_buf->data,
910                                              silc_buffer_len(attrs_buf)),
911                         SILC_STR_END);
912
913   silc_buffer_free(attrs_buf);
914 }
915
916 void silc_sftp_rmdir(SilcSFTP sftp,
917                      const char *path,
918                      SilcSFTPStatusCallback callback,
919                      void *context)
920 {
921   SilcSFTPClient client = (SilcSFTPClient)sftp;
922   SilcSFTPRequest req;
923   SilcUInt32 len = 0;
924
925   SILC_LOG_DEBUG(("Rmdir request"));
926
927   req = silc_calloc(1, sizeof(*req));
928   if (!req)
929     return;
930   req->id = client->id++;
931   req->type = SILC_SFTP_RMDIR;
932   req->status = callback;
933   req->context = context;
934   silc_list_add(client->requests, req);
935
936   len = 4 + 4 + strlen(path);
937
938   silc_sftp_send_packet(client, req->type, len,
939                         SILC_STR_UI_INT(req->id),
940                         SILC_STR_UI_INT(strlen(path)),
941                         SILC_STR_UI32_STRING(path),
942                         SILC_STR_END);
943 }
944
945 void silc_sftp_opendir(SilcSFTP sftp,
946                        const char *path,
947                        SilcSFTPHandleCallback callback,
948                        void *context)
949 {
950   SilcSFTPClient client = (SilcSFTPClient)sftp;
951   SilcSFTPRequest req;
952   SilcUInt32 len = 0;
953
954   SILC_LOG_DEBUG(("Opendir request"));
955
956   req = silc_calloc(1, sizeof(*req));
957   if (!req)
958     return;
959   req->id = client->id++;
960   req->type = SILC_SFTP_OPENDIR;
961   req->handle = callback;
962   req->context = context;
963   silc_list_add(client->requests, req);
964
965   len = 4 + 4 + strlen(path);
966
967   silc_sftp_send_packet(client, req->type, len,
968                         SILC_STR_UI_INT(req->id),
969                         SILC_STR_UI_INT(strlen(path)),
970                         SILC_STR_UI32_STRING(path),
971                         SILC_STR_END);
972 }
973
974 void silc_sftp_readdir(SilcSFTP sftp,
975                        SilcSFTPHandle handle,
976                        SilcSFTPNameCallback callback,
977                        void *context)
978 {
979   SilcSFTPClient client = (SilcSFTPClient)sftp;
980   SilcSFTPRequest req;
981   SilcUInt32 len = 0;
982   const unsigned char *hdata;
983   SilcUInt32 hdata_len;
984
985   SILC_LOG_DEBUG(("Readdir request"));
986
987   req = silc_calloc(1, sizeof(*req));
988   if (!req)
989     return;
990   req->id = client->id++;
991   req->type = SILC_SFTP_READDIR;
992   req->name = callback;
993   req->context = context;
994   silc_list_add(client->requests, req);
995
996   silc_sftp_handle_get(handle, &hdata, &hdata_len);
997   len = 4 + 4 + hdata_len;
998
999   silc_sftp_send_packet(client, req->type, len,
1000                         SILC_STR_UI_INT(req->id),
1001                         SILC_STR_UI_INT(hdata_len),
1002                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1003                         SILC_STR_END);
1004 }
1005
1006 void silc_sftp_stat(SilcSFTP sftp,
1007                     const char *path,
1008                     SilcSFTPAttrCallback callback,
1009                     void *context)
1010 {
1011   SilcSFTPClient client = (SilcSFTPClient)sftp;
1012   SilcSFTPRequest req;
1013   SilcUInt32 len = 0;
1014
1015   SILC_LOG_DEBUG(("Stat request"));
1016
1017   req = silc_calloc(1, sizeof(*req));
1018   if (!req)
1019     return;
1020   req->id = client->id++;
1021   req->type = SILC_SFTP_STAT;
1022   req->attr = callback;
1023   req->context = context;
1024   silc_list_add(client->requests, req);
1025
1026   len = 4 + 4 + strlen(path);
1027
1028   silc_sftp_send_packet(client, req->type, len,
1029                         SILC_STR_UI_INT(req->id),
1030                         SILC_STR_UI_INT(strlen(path)),
1031                         SILC_STR_UI32_STRING(path),
1032                         SILC_STR_END);
1033 }
1034
1035 void silc_sftp_lstat(SilcSFTP sftp,
1036                      const char *path,
1037                      SilcSFTPAttrCallback callback,
1038                      void *context)
1039 {
1040   SilcSFTPClient client = (SilcSFTPClient)sftp;
1041   SilcSFTPRequest req;
1042   SilcUInt32 len = 0;
1043
1044   SILC_LOG_DEBUG(("Lstat request"));
1045
1046   req = silc_calloc(1, sizeof(*req));
1047   if (!req)
1048     return;
1049   req->id = client->id++;
1050   req->type = SILC_SFTP_LSTAT;
1051   req->attr = callback;
1052   req->context = context;
1053   silc_list_add(client->requests, req);
1054
1055   len = 4 + 4 + strlen(path);
1056
1057   silc_sftp_send_packet(client, req->type, len,
1058                         SILC_STR_UI_INT(req->id),
1059                         SILC_STR_UI_INT(strlen(path)),
1060                         SILC_STR_UI32_STRING(path),
1061                         SILC_STR_END);
1062 }
1063
1064 void silc_sftp_fstat(SilcSFTP sftp,
1065                      SilcSFTPHandle handle,
1066                      SilcSFTPAttrCallback callback,
1067                      void *context)
1068 {
1069   SilcSFTPClient client = (SilcSFTPClient)sftp;
1070   SilcSFTPRequest req;
1071   SilcUInt32 len = 0;
1072   const unsigned char *hdata;
1073   SilcUInt32 hdata_len;
1074
1075   SILC_LOG_DEBUG(("Fstat request"));
1076
1077   req = silc_calloc(1, sizeof(*req));
1078   if (!req)
1079     return;
1080   req->id = client->id++;
1081   req->type = SILC_SFTP_FSTAT;
1082   req->attr = callback;
1083   req->context = context;
1084   silc_list_add(client->requests, req);
1085
1086   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1087   len = 4 + 4 + hdata_len;
1088
1089   silc_sftp_send_packet(client, req->type, len,
1090                         SILC_STR_UI_INT(req->id),
1091                         SILC_STR_UI_INT(hdata_len),
1092                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1093                         SILC_STR_END);
1094 }
1095
1096 void silc_sftp_setstat(SilcSFTP sftp,
1097                        const char *path,
1098                        SilcSFTPAttributes attrs,
1099                        SilcSFTPStatusCallback callback,
1100                        void *context)
1101 {
1102   SilcSFTPClient client = (SilcSFTPClient)sftp;
1103   SilcSFTPRequest req;
1104   SilcUInt32 len = 0;
1105   SilcBuffer attrs_buf;
1106
1107   SILC_LOG_DEBUG(("Setstat request"));
1108
1109   req = silc_calloc(1, sizeof(*req));
1110   if (!req)
1111     return;
1112   req->id = client->id++;
1113   req->type = SILC_SFTP_SETSTAT;
1114   req->status = callback;
1115   req->context = context;
1116   silc_list_add(client->requests, req);
1117
1118   attrs_buf = silc_sftp_attr_encode(attrs);
1119   if (!attrs_buf)
1120     return;
1121   len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
1122
1123   silc_sftp_send_packet(client, req->type, len,
1124                         SILC_STR_UI_INT(req->id),
1125                         SILC_STR_UI_INT(strlen(path)),
1126                         SILC_STR_UI32_STRING(path),
1127                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1128                                              silc_buffer_len(attrs_buf)),
1129                         SILC_STR_END);
1130
1131   silc_buffer_free(attrs_buf);
1132 }
1133
1134 void silc_sftp_fsetstat(SilcSFTP sftp,
1135                         SilcSFTPHandle handle,
1136                         SilcSFTPAttributes attrs,
1137                         SilcSFTPStatusCallback callback,
1138                         void *context)
1139 {
1140   SilcSFTPClient client = (SilcSFTPClient)sftp;
1141   SilcSFTPRequest req;
1142   SilcUInt32 len = 0;
1143   SilcBuffer attrs_buf;
1144   const unsigned char *hdata;
1145   SilcUInt32 hdata_len;
1146
1147   SILC_LOG_DEBUG(("Fsetstat request"));
1148
1149   req = silc_calloc(1, sizeof(*req));
1150   if (!req)
1151     return;
1152   req->id = client->id++;
1153   req->type = SILC_SFTP_FSETSTAT;
1154   req->status = callback;
1155   req->context = context;
1156   silc_list_add(client->requests, req);
1157
1158   silc_sftp_handle_get(handle, &hdata, &hdata_len);
1159   attrs_buf = silc_sftp_attr_encode(attrs);
1160   if (!attrs_buf)
1161     return;
1162   len = 4 + 4 + hdata_len + silc_buffer_len(attrs_buf);
1163
1164   silc_sftp_send_packet(client, req->type, len,
1165                         SILC_STR_UI_INT(req->id),
1166                         SILC_STR_UI_INT(hdata_len),
1167                         SILC_STR_UI_XNSTRING(hdata, hdata_len),
1168                         SILC_STR_UI_XNSTRING(attrs_buf->data,
1169                                              silc_buffer_len(attrs_buf)),
1170                         SILC_STR_END);
1171
1172   silc_buffer_free(attrs_buf);
1173 }
1174
1175 void silc_sftp_readlink(SilcSFTP sftp,
1176                         const char *path,
1177                         SilcSFTPNameCallback callback,
1178                         void *context)
1179 {
1180   SilcSFTPClient client = (SilcSFTPClient)sftp;
1181   SilcSFTPRequest req;
1182   SilcUInt32 len = 0;
1183
1184   SILC_LOG_DEBUG(("Readlink request"));
1185
1186   req = silc_calloc(1, sizeof(*req));
1187   if (!req)
1188     return;
1189   req->id = client->id++;
1190   req->type = SILC_SFTP_READLINK;
1191   req->name = callback;
1192   req->context = context;
1193   silc_list_add(client->requests, req);
1194
1195   len = 4 + 4 + strlen(path);
1196
1197   silc_sftp_send_packet(client, req->type, len,
1198                         SILC_STR_UI_INT(req->id),
1199                         SILC_STR_UI_INT(strlen(path)),
1200                         SILC_STR_UI32_STRING(path),
1201                         SILC_STR_END);
1202 }
1203
1204 void silc_sftp_symlink(SilcSFTP sftp,
1205                        const char *linkpath,
1206                        const char *targetpath,
1207                        SilcSFTPStatusCallback callback,
1208                        void *context)
1209 {
1210   SilcSFTPClient client = (SilcSFTPClient)sftp;
1211   SilcSFTPRequest req;
1212   SilcUInt32 len = 0;
1213
1214   SILC_LOG_DEBUG(("Symlink request"));
1215
1216   req = silc_calloc(1, sizeof(*req));
1217   if (!req)
1218     return;
1219   req->id = client->id++;
1220   req->type = SILC_SFTP_SYMLINK;
1221   req->status = callback;
1222   req->context = context;
1223   silc_list_add(client->requests, req);
1224
1225   len = 4 + 4 + strlen(linkpath) + 4 + strlen(targetpath);
1226
1227   silc_sftp_send_packet(client, req->type, len,
1228                         SILC_STR_UI_INT(req->id),
1229                         SILC_STR_UI_INT(strlen(linkpath)),
1230                         SILC_STR_UI32_STRING(linkpath),
1231                         SILC_STR_UI_INT(strlen(targetpath)),
1232                         SILC_STR_UI32_STRING(targetpath),
1233                         SILC_STR_END);
1234 }
1235
1236 void silc_sftp_realpath(SilcSFTP sftp,
1237                         const char *path,
1238                         SilcSFTPNameCallback callback,
1239                         void *context)
1240 {
1241   SilcSFTPClient client = (SilcSFTPClient)sftp;
1242   SilcSFTPRequest req;
1243   SilcUInt32 len = 0;
1244
1245   SILC_LOG_DEBUG(("Realpath request"));
1246
1247   req = silc_calloc(1, sizeof(*req));
1248   if (!req)
1249     return;
1250   req->id = client->id++;
1251   req->type = SILC_SFTP_REALPATH;
1252   req->name = callback;
1253   req->context = context;
1254   silc_list_add(client->requests, req);
1255
1256   len = 4 + 4 + strlen(path);
1257
1258   silc_sftp_send_packet(client, req->type, len,
1259                         SILC_STR_UI_INT(req->id),
1260                         SILC_STR_UI_INT(strlen(path)),
1261                         SILC_STR_UI32_STRING(path),
1262                         SILC_STR_END);
1263 }
1264
1265 void silc_sftp_extended(SilcSFTP sftp,
1266                         const char *request,
1267                         const unsigned char *data,
1268                         SilcUInt32 data_len,
1269                         SilcSFTPExtendedCallback callback,
1270                         void *context)
1271 {
1272   SilcSFTPClient client = (SilcSFTPClient)sftp;
1273   SilcSFTPRequest req;
1274   SilcUInt32 len = 0;
1275
1276   SILC_LOG_DEBUG(("Extended request"));
1277
1278   req = silc_calloc(1, sizeof(*req));
1279   if (!req)
1280     return;
1281   req->id = client->id++;
1282   req->type = SILC_SFTP_WRITE;
1283   req->extended = callback;
1284   req->context = context;
1285   silc_list_add(client->requests, req);
1286
1287   len = 4 + 4 + strlen(request) + data_len;
1288
1289   silc_sftp_send_packet(client, req->type, len,
1290                         SILC_STR_UI_INT(req->id),
1291                         SILC_STR_UI_INT(strlen(request)),
1292                         SILC_STR_UI32_STRING(request),
1293                         SILC_STR_UI_XNSTRING(data, data_len),
1294                         SILC_STR_END);
1295 }