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