5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 Pekka Riikonen
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.
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.
21 #include "silcincludes.h"
23 #include "sftp_util.h"
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. */
32 SilcBuffer silc_sftp_packet_encode(SilcSFTPPacket packet,
33 SilcBuffer packet_buf, uint32 len, ...)
39 buffer = silc_sftp_packet_encode_vp(packet, packet_buf, len, vp);
45 /* Same as silc_sftp_packet_encode but takes the variable argument list
46 pointer as argument. */
48 SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet,
49 SilcBuffer packet_buf, uint32 len,
57 if (packet_buf->truelen < 4 + 1 + len)
58 packet_buf = silc_buffer_realloc(packet_buf, 4 + 1 + len);
63 buffer = silc_buffer_alloc(4 + 1 + len);
67 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
68 silc_buffer_format(buffer,
70 SILC_STR_UI_CHAR(packet),
72 silc_buffer_pull(buffer, 5);
74 ret = silc_buffer_format_vp(buffer, vp);
77 silc_buffer_free(buffer);
81 silc_buffer_push(buffer, 5);
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. */
90 SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
91 unsigned char **payload,
98 ret = silc_buffer_unformat(packet,
99 SILC_STR_UI_INT(&len),
100 SILC_STR_UI_CHAR(&type),
105 if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
108 if (len > (packet->len - 5))
111 silc_buffer_pull(packet, 5);
112 ret = silc_buffer_unformat(packet,
113 SILC_STR_UI_XNSTRING(payload, len),
118 silc_buffer_push(packet, 5);
122 return (SilcSFTPPacket)type;
125 /* Encodes the SFTP attributes to a buffer and returns the allocated buffer.
126 The caller must free the buffer. */
128 SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr)
133 if (attr->flags & SILC_SFTP_ATTR_SIZE)
135 if (attr->flags & SILC_SFTP_ATTR_UIDGID)
137 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
139 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
141 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
143 for (i = 0; i < attr->extended_count; i++) {
145 len += attr->extended_type[i]->len;
146 len += attr->extended_data[i]->len;
150 buffer = silc_buffer_alloc(len);
151 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
153 silc_buffer_format(buffer,
154 SILC_STR_UI_INT(attr->flags),
156 silc_buffer_pull(buffer, 4);
158 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
159 silc_buffer_format(buffer,
160 SILC_STR_UI_INT64(attr->size),
162 silc_buffer_pull(buffer, 8);
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),
170 silc_buffer_pull(buffer, 8);
173 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
174 silc_buffer_format(buffer,
175 SILC_STR_UI_INT(attr->permissions),
177 silc_buffer_pull(buffer, 4);
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),
185 silc_buffer_pull(buffer, 8);
188 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
189 silc_buffer_format(buffer,
190 SILC_STR_UI_INT(attr->extended_count),
192 silc_buffer_pull(buffer, 4);
194 for (i = 0; i < attr->extended_count; i++) {
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),
204 silc_buffer_pull(buffer, ret);
208 silc_buffer_push(buffer, buffer->data - buffer->head);
213 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
214 attributes that the caller must free or NULL on error. */
216 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
218 SilcSFTPAttributes attr;
220 attr = silc_calloc(1, sizeof(*attr));
222 if (silc_buffer_unformat(buffer,
223 SILC_STR_UI_INT(&attr->flags),
227 silc_buffer_pull(buffer, 4);
229 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
230 if (silc_buffer_unformat(buffer,
231 SILC_STR_UI_INT64(&attr->size),
235 silc_buffer_pull(buffer, 8);
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),
245 silc_buffer_pull(buffer, 8);
248 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
249 if (silc_buffer_unformat(buffer,
250 SILC_STR_UI_INT(&attr->permissions),
254 silc_buffer_pull(buffer, 4);
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),
264 silc_buffer_pull(buffer, 8);
267 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
270 if (silc_buffer_unformat(buffer,
271 SILC_STR_UI_INT(&attr->extended_count),
275 silc_buffer_pull(buffer, 4);
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 uint32 tmp_len, tmp2_len;
285 if (silc_buffer_unformat(buffer,
286 SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
287 SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
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);
296 silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
303 silc_sftp_attr_free(attr);
307 /* Frees the attributes context and its internals. */
309 void silc_sftp_attr_free(SilcSFTPAttributes attr)
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]);
317 silc_free(attr->extended_type);
318 silc_free(attr->extended_data);
322 /* Adds an entry to the `name' context. */
324 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
325 const char *long_name, SilcSFTPAttributes attrs)
327 name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
329 name->long_filename = silc_realloc(name->long_filename,
330 sizeof(*name->long_filename) *
332 name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
335 name->filename[name->count] = strdup(short_name);
336 name->long_filename[name->count] = strdup(long_name);
337 name->attrs[name->count] = attrs;
341 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
342 The caller must free the buffer. */
344 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
348 SilcBuffer *attr_buf;
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;
357 buffer = silc_buffer_alloc(len);
358 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
360 silc_buffer_format(buffer,
361 SILC_STR_UI_INT(name->count),
363 silc_buffer_pull(buffer, 4);
365 for (i = 0; i < name->count; i++) {
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,
376 silc_buffer_pull(buffer, len);
377 silc_free(attr_buf[i]);
381 silc_buffer_push(buffer, buffer->data - buffer->head);
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. */
390 SilcSFTPName silc_sftp_name_decode(uint32 count, SilcBuffer buffer)
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));
402 for (i = 0; i < count; i++) {
404 silc_buffer_unformat(buffer,
405 SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
406 SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
409 silc_sftp_name_free(name);
413 silc_buffer_pull(buffer, ret);
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);
423 /* Frees the name context and its internals. */
425 void silc_sftp_name_free(SilcSFTPName name)
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]);
435 silc_free(name->filename);
436 silc_free(name->long_filename);
437 silc_free(name->attrs);
441 /* Maps errno to SFTP status message. */
443 SilcSFTPStatus silc_sftp_map_errno(int err)
449 ret = SILC_SFTP_STATUS_OK;
454 ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
459 ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
463 ret = SILC_SFTP_STATUS_BAD_MESSAGE;
466 ret = SILC_SFTP_STATUS_FAILURE;