5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 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.
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, SilcUInt32 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, SilcUInt32 len,
57 if (silc_buffer_truelen(packet_buf) < 4 + 1 + len) {
58 packet_buf = silc_buffer_realloc(packet_buf, 4 + 1 + len);
66 buffer = silc_buffer_alloc(4 + 1 + len);
72 silc_buffer_pull_tail(buffer, 4 + 1 + len);
73 silc_buffer_format(buffer,
75 SILC_STR_UI_CHAR(packet),
77 silc_buffer_pull(buffer, 5);
79 ret = silc_buffer_format_vp(buffer, vp);
82 silc_buffer_free(buffer);
86 silc_buffer_push(buffer, 5);
91 /* Decodes the SFTP packet data `packet' and return the SFTP packet type.
92 The payload of the packet is returned to the `payload' pointer. Returns
93 0 if error occurred during decoding. */
95 SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
96 unsigned char **payload,
97 SilcUInt32 *payload_len)
103 ret = silc_buffer_unformat(packet,
104 SILC_STR_UI_INT(&len),
105 SILC_STR_UI_CHAR(&type),
110 if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
113 if (len > (silc_buffer_len(packet) - 5))
116 silc_buffer_pull(packet, 5);
117 ret = silc_buffer_unformat(packet,
118 SILC_STR_UI_XNSTRING(payload, len),
123 silc_buffer_push(packet, 5);
127 return (SilcSFTPPacket)type;
130 /* Encodes the SFTP attributes to a buffer and returns the allocated buffer.
131 The caller must free the buffer. */
133 SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr)
139 if (attr->flags & SILC_SFTP_ATTR_SIZE)
141 if (attr->flags & SILC_SFTP_ATTR_UIDGID)
143 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
145 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
147 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
149 for (i = 0; i < attr->extended_count; i++) {
151 len += silc_buffer_len(attr->extended_type[i]);
152 len += silc_buffer_len(attr->extended_data[i]);
156 buffer = silc_buffer_alloc_size(len);
160 silc_buffer_format(buffer,
161 SILC_STR_UI_INT(attr->flags),
163 silc_buffer_pull(buffer, 4);
165 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
166 silc_buffer_format(buffer,
167 SILC_STR_UI_INT64(attr->size),
169 silc_buffer_pull(buffer, 8);
172 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
173 silc_buffer_format(buffer,
174 SILC_STR_UI_INT(attr->uid),
175 SILC_STR_UI_INT(attr->gid),
177 silc_buffer_pull(buffer, 8);
180 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
181 silc_buffer_format(buffer,
182 SILC_STR_UI_INT(attr->permissions),
184 silc_buffer_pull(buffer, 4);
187 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
188 silc_buffer_format(buffer,
189 SILC_STR_UI_INT(attr->atime),
190 SILC_STR_UI_INT(attr->mtime),
192 silc_buffer_pull(buffer, 8);
195 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
196 silc_buffer_format(buffer,
197 SILC_STR_UI_INT(attr->extended_count),
199 silc_buffer_pull(buffer, 4);
201 for (i = 0; i < attr->extended_count; i++) {
205 SILC_STR_UI_INT(silc_buffer_len(attr->extended_type[i])),
206 SILC_STR_DATA(silc_buffer_data(attr->extended_type[i]),
207 silc_buffer_len(attr->extended_type[i])),
208 SILC_STR_UI_INT(silc_buffer_len(attr->extended_data[i])),
209 SILC_STR_DATA(silc_buffer_data(attr->extended_data[i]),
210 silc_buffer_len(attr->extended_data[i])),
212 silc_buffer_pull(buffer, ret);
216 silc_buffer_push(buffer, buffer->data - buffer->head);
221 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
222 attributes that the caller must free or NULL on error. */
224 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
226 SilcSFTPAttributes attr;
228 attr = silc_calloc(1, sizeof(*attr));
232 if (silc_buffer_unformat(buffer,
233 SILC_STR_UI_INT(&attr->flags),
237 silc_buffer_pull(buffer, 4);
239 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
240 if (silc_buffer_unformat(buffer,
241 SILC_STR_UI_INT64(&attr->size),
245 silc_buffer_pull(buffer, 8);
248 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
249 if (silc_buffer_unformat(buffer,
250 SILC_STR_UI_INT(&attr->uid),
251 SILC_STR_UI_INT(&attr->gid),
255 silc_buffer_pull(buffer, 8);
258 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
259 if (silc_buffer_unformat(buffer,
260 SILC_STR_UI_INT(&attr->permissions),
264 silc_buffer_pull(buffer, 4);
267 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
268 if (silc_buffer_unformat(buffer,
269 SILC_STR_UI_INT(&attr->atime),
270 SILC_STR_UI_INT(&attr->mtime),
274 silc_buffer_pull(buffer, 8);
277 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
280 if (silc_buffer_unformat(buffer,
281 SILC_STR_UI_INT(&attr->extended_count),
285 silc_buffer_pull(buffer, 4);
287 attr->extended_type = silc_calloc(attr->extended_count,
288 sizeof(*attr->extended_type));
289 attr->extended_data = silc_calloc(attr->extended_count,
290 sizeof(*attr->extended_data));
291 if (!attr->extended_type || !attr->extended_data)
294 for (i = 0; i < attr->extended_count; i++) {
295 unsigned char *tmp, *tmp2;
296 SilcUInt32 tmp_len, tmp2_len;
298 if (silc_buffer_unformat(buffer,
299 SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
300 SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
304 attr->extended_type[i] = silc_buffer_alloc(tmp_len);
305 attr->extended_data[i] = silc_buffer_alloc(tmp2_len);
306 if (!attr->extended_type[i] || !attr->extended_data[i])
308 silc_buffer_put(attr->extended_type[i], tmp, tmp_len);
309 silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len);
311 silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
318 silc_sftp_attr_free(attr);
322 /* Frees the attributes context and its internals. */
324 void silc_sftp_attr_free(SilcSFTPAttributes attr)
328 for (i = 0; i < attr->extended_count; i++) {
329 silc_buffer_free(attr->extended_type[i]);
330 silc_buffer_free(attr->extended_data[i]);
332 silc_free(attr->extended_type);
333 silc_free(attr->extended_data);
337 /* Adds an entry to the `name' context. */
339 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
340 const char *long_name, SilcSFTPAttributes attrs)
342 name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
344 name->long_filename = silc_realloc(name->long_filename,
345 sizeof(*name->long_filename) *
347 name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
349 if (!name->filename || !name->long_filename || !name->attrs)
352 name->filename[name->count] = strdup(short_name);
353 name->long_filename[name->count] = strdup(long_name);
354 name->attrs[name->count] = attrs;
358 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
359 The caller must free the buffer. */
361 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
365 SilcBuffer *attr_buf;
367 attr_buf = silc_calloc(name->count, sizeof(*attr_buf));
371 for (i = 0; i < name->count; i++) {
372 len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i]));
373 attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
376 len += silc_buffer_len(attr_buf[i]);
379 buffer = silc_buffer_alloc(len);
382 silc_buffer_end(buffer);
384 silc_buffer_format(buffer,
385 SILC_STR_UI_INT(name->count),
387 silc_buffer_pull(buffer, 4);
389 for (i = 0; i < name->count; i++) {
391 silc_buffer_format(buffer,
392 SILC_STR_UI_INT(strlen(name->filename[i])),
393 SILC_STR_UI32_STRING(name->filename[i]),
394 SILC_STR_UI_INT(strlen(name->long_filename[i])),
395 SILC_STR_UI32_STRING(name->long_filename[i]),
396 SILC_STR_DATA(silc_buffer_data(attr_buf[i]),
397 silc_buffer_len(attr_buf[i])),
400 silc_buffer_pull(buffer, len);
401 silc_free(attr_buf[i]);
405 silc_buffer_push(buffer, buffer->data - buffer->head);
410 /* Decodes a SilcSFTPName structure from the `buffer' that must include
411 `count' many name, longname and attribute values. Returns the allocated
412 structure or NULL on error. */
414 SilcSFTPName silc_sftp_name_decode(SilcUInt32 count, SilcBuffer buffer)
420 name = silc_calloc(1, sizeof(*name));
423 name->filename = silc_calloc(count, sizeof(*name->filename));
424 name->long_filename = silc_calloc(count, sizeof(*name->filename));
425 name->attrs = silc_calloc(count, sizeof(*name->attrs));
426 if (!name->filename || !name->long_filename || !name->attrs) {
427 silc_sftp_name_free(name);
432 for (i = 0; i < count; i++) {
434 silc_buffer_unformat(buffer,
435 SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
436 SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
439 silc_sftp_name_free(name);
443 silc_buffer_pull(buffer, ret);
445 /* Decode attributes, this will pull the `buffer' to correct place
446 for next round automatically. */
447 name->attrs[i] = silc_sftp_attr_decode(buffer);
448 if (!name->attrs[i]) {
449 silc_sftp_name_free(name);
457 /* Frees the name context and its internals. */
459 void silc_sftp_name_free(SilcSFTPName name)
463 for (i = 0; i < name->count; i++) {
464 silc_free(name->filename[i]);
465 silc_free(name->long_filename[i]);
466 silc_sftp_attr_free(name->attrs[i]);
469 silc_free(name->filename);
470 silc_free(name->long_filename);
471 silc_free(name->attrs);
475 /* Maps errno to SFTP status message. */
477 SilcSFTPStatus silc_sftp_map_errno(int err)
483 ret = SILC_SFTP_STATUS_OK;
488 ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
493 ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
497 ret = SILC_SFTP_STATUS_BAD_MESSAGE;
500 ret = SILC_SFTP_STATUS_FAILURE;