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