Integer type name change.
[silc.git] / lib / silcsftp / sftp_util.c
1 /*
2
3   sftp_util.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 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 "silcincludes.h"
22 #include "silcsftp.h"
23 #include "sftp_util.h"
24
25 /* Encodes a SFTP packet of type `packet' of length `len'. The variable
26    argument list is encoded as data payload to the buffer. Returns the
27    encoded packet or NULL on error. The caller must free the returned
28    buffer. If `packet_buf' is non-NULL then the new packet data is put
29    to that buffer instead of allocating new one.  If the new data cannot
30    fit to `packet_buf' will be reallocated. */
31
32 SilcBuffer silc_sftp_packet_encode(SilcSFTPPacket packet, 
33                                    SilcBuffer packet_buf, SilcUInt32 len, ...)
34 {
35   SilcBuffer buffer;
36   va_list vp;
37
38   va_start(vp, len);
39   buffer = silc_sftp_packet_encode_vp(packet, packet_buf, len, vp);
40   va_end(vp);
41
42   return buffer;
43 }
44
45 /* Same as silc_sftp_packet_encode but takes the variable argument list
46    pointer as argument. */
47
48 SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet, 
49                                       SilcBuffer packet_buf, SilcUInt32 len, 
50                                       va_list vp)
51 {
52   SilcBuffer buffer;
53   bool dyn;
54   int ret;
55
56   if (packet_buf) {
57     if (packet_buf->truelen < 4 + 1 + len)
58       packet_buf = silc_buffer_realloc(packet_buf, 4 + 1 + len);
59
60     buffer = packet_buf;
61     dyn = FALSE;
62   } else {
63     buffer = silc_buffer_alloc(4 + 1 + len);
64     dyn = TRUE;
65   }
66
67   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
68   silc_buffer_format(buffer, 
69                      SILC_STR_UI_INT(len),
70                      SILC_STR_UI_CHAR(packet),
71                      SILC_STR_END);
72   silc_buffer_pull(buffer, 5);
73
74   ret = silc_buffer_format_vp(buffer, vp);
75   if (ret < 0) {
76     if (dyn)
77       silc_buffer_free(buffer);
78     return NULL;
79   }
80
81   silc_buffer_push(buffer, 5);
82
83   return buffer;
84 }
85
86 /* Decodes the SFTP packet data `packet' and return the SFTP packet type.
87    The payload of the packet is returned to the `payload' pointer. Returns
88    0 if error occurred during decoding. */
89
90 SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
91                                        unsigned char **payload,
92                                        SilcUInt32 *payload_len)
93 {
94   SilcUInt32 len;
95   SilcUInt8 type;
96   int ret;
97
98   ret = silc_buffer_unformat(packet,
99                              SILC_STR_UI_INT(&len),
100                              SILC_STR_UI_CHAR(&type),
101                              SILC_STR_END);
102   if (ret < 0)
103     return 0;
104
105   if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
106     return 0;
107
108   if (len > (packet->len - 5))
109     return 0;
110
111   silc_buffer_pull(packet, 5);
112   ret = silc_buffer_unformat(packet, 
113                              SILC_STR_UI_XNSTRING(payload, len),
114                              SILC_STR_END);
115   if (ret < 0)
116     return 0;
117
118   silc_buffer_push(packet, 5);
119
120   *payload_len = len;
121
122   return (SilcSFTPPacket)type;
123 }
124
125 /* Encodes the SFTP attributes to a buffer and returns the allocated buffer.
126    The caller must free the buffer. */
127
128 SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr)
129 {
130   SilcBuffer buffer;
131   int i, ret, len = 4;
132
133   if (attr->flags & SILC_SFTP_ATTR_SIZE)
134     len += 8;
135   if (attr->flags & SILC_SFTP_ATTR_UIDGID)
136     len += 8;
137   if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
138     len += 4;
139   if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
140     len += 8;
141   if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
142     len += 4;
143     for (i = 0; i < attr->extended_count; i++) {
144       len += 8;
145       len += attr->extended_type[i]->len;
146       len += attr->extended_data[i]->len;
147     }
148   }
149
150   buffer = silc_buffer_alloc(len);
151   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
152
153   silc_buffer_format(buffer, 
154                      SILC_STR_UI_INT(attr->flags), 
155                      SILC_STR_END);
156   silc_buffer_pull(buffer, 4);
157
158   if (attr->flags & SILC_SFTP_ATTR_SIZE) {
159     silc_buffer_format(buffer, 
160                        SILC_STR_UI_INT64(attr->size), 
161                        SILC_STR_END);
162     silc_buffer_pull(buffer, 8);
163   }
164
165   if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
166     silc_buffer_format(buffer, 
167                        SILC_STR_UI_INT(attr->uid), 
168                        SILC_STR_UI_INT(attr->gid), 
169                        SILC_STR_END);
170     silc_buffer_pull(buffer, 8);
171   }
172
173   if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
174     silc_buffer_format(buffer, 
175                        SILC_STR_UI_INT(attr->permissions), 
176                        SILC_STR_END);
177     silc_buffer_pull(buffer, 4);
178   }
179
180   if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
181     silc_buffer_format(buffer, 
182                        SILC_STR_UI_INT(attr->atime), 
183                        SILC_STR_UI_INT(attr->mtime), 
184                        SILC_STR_END);
185     silc_buffer_pull(buffer, 8);
186   }
187
188   if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
189     silc_buffer_format(buffer, 
190                        SILC_STR_UI_INT(attr->extended_count), 
191                        SILC_STR_END);
192     silc_buffer_pull(buffer, 4);
193
194     for (i = 0; i < attr->extended_count; i++) {
195       ret = 
196         silc_buffer_format(buffer, 
197                            SILC_STR_UI_INT(attr->extended_type[i]->len),
198                            SILC_STR_UI_XNSTRING(attr->extended_type[i]->data,
199                                                 attr->extended_type[i]->len),
200                            SILC_STR_UI_INT(attr->extended_data[i]->len),
201                            SILC_STR_UI_XNSTRING(attr->extended_data[i]->data,
202                                                 attr->extended_data[i]->len),
203                            SILC_STR_END);
204       silc_buffer_pull(buffer, ret);
205     }
206   }
207
208   silc_buffer_push(buffer, buffer->data - buffer->head);
209
210   return buffer;
211 }
212
213 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
214    attributes that the caller must free or NULL on error. */
215
216 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
217 {
218   SilcSFTPAttributes attr;
219
220   attr = silc_calloc(1, sizeof(*attr));
221
222   if (silc_buffer_unformat(buffer, 
223                            SILC_STR_UI_INT(&attr->flags), 
224                            SILC_STR_END) < 0)
225     goto out;
226
227   silc_buffer_pull(buffer, 4);
228
229   if (attr->flags & SILC_SFTP_ATTR_SIZE) {
230     if (silc_buffer_unformat(buffer, 
231                              SILC_STR_UI_INT64(&attr->size), 
232                              SILC_STR_END) < 0)
233       goto out;
234
235     silc_buffer_pull(buffer, 8);
236   }
237
238   if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
239     if (silc_buffer_unformat(buffer, 
240                              SILC_STR_UI_INT(&attr->uid), 
241                              SILC_STR_UI_INT(&attr->gid), 
242                              SILC_STR_END) < 0)
243       goto out;
244
245     silc_buffer_pull(buffer, 8);
246   }
247
248   if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
249     if (silc_buffer_unformat(buffer, 
250                              SILC_STR_UI_INT(&attr->permissions), 
251                              SILC_STR_END) < 0)
252       goto out;
253
254     silc_buffer_pull(buffer, 4);
255   }
256
257   if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
258     if (silc_buffer_unformat(buffer, 
259                              SILC_STR_UI_INT(&attr->atime), 
260                              SILC_STR_UI_INT(&attr->mtime), 
261                              SILC_STR_END) < 0)
262       goto out;
263
264     silc_buffer_pull(buffer, 8);
265   }
266
267   if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
268     int i;
269
270     if (silc_buffer_unformat(buffer, 
271                              SILC_STR_UI_INT(&attr->extended_count), 
272                              SILC_STR_END) < 0)
273       goto out;
274
275     silc_buffer_pull(buffer, 4);
276
277     attr->extended_type = silc_calloc(attr->extended_count, 
278                                       sizeof(*attr->extended_type));
279     attr->extended_data = silc_calloc(attr->extended_count, 
280                                       sizeof(*attr->extended_data));
281     for (i = 0; i < attr->extended_count; i++) {
282       unsigned char *tmp, *tmp2;
283       SilcUInt32 tmp_len, tmp2_len;
284
285       if (silc_buffer_unformat(buffer, 
286                                SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
287                                SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
288                                SILC_STR_END) < 0)
289         goto out;
290
291       attr->extended_type[i] = silc_buffer_alloc(tmp_len);
292       attr->extended_data[i] = silc_buffer_alloc(tmp2_len);
293       silc_buffer_put(attr->extended_type[i], tmp, tmp_len);
294       silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len);
295
296       silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
297     }
298   }
299
300   return attr;
301
302  out:
303   silc_sftp_attr_free(attr);
304   return NULL;
305 }
306
307 /* Frees the attributes context and its internals. */
308
309 void silc_sftp_attr_free(SilcSFTPAttributes attr)
310 {
311   int i;
312
313   for (i = 0; i < attr->extended_count; i++) {
314     silc_buffer_free(attr->extended_type[i]);
315     silc_buffer_free(attr->extended_data[i]);
316   }
317   silc_free(attr->extended_type);
318   silc_free(attr->extended_data);
319   silc_free(attr);
320 }
321
322 /* Adds an entry to the `name' context. */
323
324 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
325                         const char *long_name, SilcSFTPAttributes attrs)
326 {
327   name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
328                                 (name->count + 1));
329   name->long_filename = silc_realloc(name->long_filename, 
330                                      sizeof(*name->long_filename) *
331                                      (name->count + 1));
332   name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
333                              (name->count + 1));
334
335   name->filename[name->count] = strdup(short_name);
336   name->long_filename[name->count] = strdup(long_name);
337   name->attrs[name->count] = attrs;
338   name->count++;
339 }
340
341 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer. 
342    The caller must free the buffer. */
343
344 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
345 {
346   SilcBuffer buffer;
347   int i, len = 4;
348   SilcBuffer *attr_buf;
349
350   attr_buf = silc_calloc(name->count, sizeof(*attr_buf));
351   for (i = 0; i < name->count; i++) {
352     len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i]));
353     attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
354     len += attr_buf[i]->len;
355   }
356
357   buffer = silc_buffer_alloc(len);
358   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
359
360   silc_buffer_format(buffer,
361                      SILC_STR_UI_INT(name->count),
362                      SILC_STR_END);
363   silc_buffer_pull(buffer, 4);
364
365   for (i = 0; i < name->count; i++) {
366     len =
367       silc_buffer_format(buffer,
368                          SILC_STR_UI_INT(strlen(name->filename[i])),
369                          SILC_STR_UI32_STRING(name->filename[i]),
370                          SILC_STR_UI_INT(strlen(name->long_filename[i])),
371                          SILC_STR_UI32_STRING(name->long_filename[i]),
372                          SILC_STR_UI_XNSTRING(attr_buf[i]->data,
373                                               attr_buf[i]->len),
374                          SILC_STR_END);
375
376     silc_buffer_pull(buffer, len);
377     silc_free(attr_buf[i]);
378   }
379   silc_free(attr_buf);
380
381   silc_buffer_push(buffer, buffer->data - buffer->head);
382
383   return buffer;
384 }
385
386 /* Decodes a SilcSFTPName structure from the `buffer' that must include
387    `count' many name, longname and attribute values. Returns the allocated
388    structure or NULL on error. */
389
390 SilcSFTPName silc_sftp_name_decode(SilcUInt32 count, SilcBuffer buffer)
391 {
392   SilcSFTPName name;
393   int i;
394   int ret;
395
396   name = silc_calloc(1, sizeof(*name));
397   name->filename = silc_calloc(count, sizeof(*name->filename));
398   name->long_filename = silc_calloc(count, sizeof(*name->filename));
399   name->attrs = silc_calloc(count, sizeof(*name->attrs));
400   name->count = count;
401
402   for (i = 0; i < count; i++) {
403     ret = 
404       silc_buffer_unformat(buffer,
405                            SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
406                            SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
407                            SILC_STR_END);
408     if (ret < 0) {
409       silc_sftp_name_free(name);
410       return NULL;
411     }
412
413     silc_buffer_pull(buffer, ret);
414
415     /* Decode attributes, this will pull the `buffer' to correct place
416        for next round automatically. */
417     name->attrs[i] = silc_sftp_attr_decode(buffer);
418   }
419
420   return name;
421 }
422
423 /* Frees the name context and its internals. */
424
425 void silc_sftp_name_free(SilcSFTPName name)
426 {
427   int i;
428
429   for (i = 0; i < name->count; i++) {
430     silc_free(name->filename[i]);
431     silc_free(name->long_filename[i]);
432     silc_sftp_attr_free(name->attrs[i]);
433   }
434
435   silc_free(name->filename);
436   silc_free(name->long_filename);
437   silc_free(name->attrs);
438   silc_free(name);
439 }
440
441 /* Maps errno to SFTP status message. */
442
443 SilcSFTPStatus silc_sftp_map_errno(int err)
444 {
445   SilcSFTPStatus ret;
446
447   switch (err) {
448   case 0:
449     ret = SILC_SFTP_STATUS_OK;
450     break;
451   case ENOENT:
452   case ENOTDIR:
453   case EBADF:
454     ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
455     break;
456   case EPERM:
457   case EACCES:
458   case EFAULT:
459     ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
460     break;
461   case ENAMETOOLONG:
462   case EINVAL:
463     ret = SILC_SFTP_STATUS_BAD_MESSAGE;
464     break;
465   default:
466     ret = SILC_SFTP_STATUS_FAILURE;
467     break;
468   }
469
470   return ret;
471 }