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