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 and -1 if partial packet was
96 SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
97 unsigned char **payload,
98 SilcUInt32 *payload_len)
104 ret = silc_buffer_unformat(packet,
105 SILC_STR_UI_INT(&len),
106 SILC_STR_UI_CHAR(&type),
111 if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
114 if (len > (silc_buffer_len(packet) - 5))
117 silc_buffer_pull(packet, 5);
118 ret = silc_buffer_unformat(packet,
119 SILC_STR_UI_XNSTRING(payload, len),
124 silc_buffer_push(packet, 5);
128 return (SilcSFTPPacket)type;
131 /* Encodes the SFTP attributes to a buffer and returns the allocated buffer.
132 The caller must free the buffer. */
134 SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr)
140 if (attr->flags & SILC_SFTP_ATTR_SIZE)
142 if (attr->flags & SILC_SFTP_ATTR_UIDGID)
144 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
146 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
148 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
150 for (i = 0; i < attr->extended_count; i++) {
152 len += silc_buffer_len(attr->extended_type[i]);
153 len += silc_buffer_len(attr->extended_data[i]);
157 buffer = silc_buffer_alloc_size(len);
161 silc_buffer_format(buffer,
162 SILC_STR_UI_INT(attr->flags),
164 silc_buffer_pull(buffer, 4);
166 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
167 silc_buffer_format(buffer,
168 SILC_STR_UI_INT64(attr->size),
170 silc_buffer_pull(buffer, 8);
173 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
174 silc_buffer_format(buffer,
175 SILC_STR_UI_INT(attr->uid),
176 SILC_STR_UI_INT(attr->gid),
178 silc_buffer_pull(buffer, 8);
181 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
182 silc_buffer_format(buffer,
183 SILC_STR_UI_INT(attr->permissions),
185 silc_buffer_pull(buffer, 4);
188 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
189 silc_buffer_format(buffer,
190 SILC_STR_UI_INT(attr->atime),
191 SILC_STR_UI_INT(attr->mtime),
193 silc_buffer_pull(buffer, 8);
196 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
197 silc_buffer_format(buffer,
198 SILC_STR_UI_INT(attr->extended_count),
200 silc_buffer_pull(buffer, 4);
202 for (i = 0; i < attr->extended_count; i++) {
206 SILC_STR_UI_INT(silc_buffer_len(attr->extended_type[i])),
207 SILC_STR_DATA(silc_buffer_data(attr->extended_type[i]),
208 silc_buffer_len(attr->extended_type[i])),
209 SILC_STR_UI_INT(silc_buffer_len(attr->extended_data[i])),
210 SILC_STR_DATA(silc_buffer_data(attr->extended_data[i]),
211 silc_buffer_len(attr->extended_data[i])),
213 silc_buffer_pull(buffer, ret);
217 silc_buffer_push(buffer, buffer->data - buffer->head);
222 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
223 attributes that the caller must free or NULL on error. */
225 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
227 SilcSFTPAttributes attr;
229 attr = silc_calloc(1, sizeof(*attr));
233 if (silc_buffer_unformat(buffer,
234 SILC_STR_UI_INT(&attr->flags),
238 silc_buffer_pull(buffer, 4);
240 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
241 if (silc_buffer_unformat(buffer,
242 SILC_STR_UI_INT64(&attr->size),
246 silc_buffer_pull(buffer, 8);
249 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
250 if (silc_buffer_unformat(buffer,
251 SILC_STR_UI_INT(&attr->uid),
252 SILC_STR_UI_INT(&attr->gid),
256 silc_buffer_pull(buffer, 8);
259 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
260 if (silc_buffer_unformat(buffer,
261 SILC_STR_UI_INT(&attr->permissions),
265 silc_buffer_pull(buffer, 4);
268 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
269 if (silc_buffer_unformat(buffer,
270 SILC_STR_UI_INT(&attr->atime),
271 SILC_STR_UI_INT(&attr->mtime),
275 silc_buffer_pull(buffer, 8);
278 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
281 if (silc_buffer_unformat(buffer,
282 SILC_STR_UI_INT(&attr->extended_count),
286 silc_buffer_pull(buffer, 4);
288 attr->extended_type = silc_calloc(attr->extended_count,
289 sizeof(*attr->extended_type));
290 attr->extended_data = silc_calloc(attr->extended_count,
291 sizeof(*attr->extended_data));
292 if (!attr->extended_type || !attr->extended_data)
295 for (i = 0; i < attr->extended_count; i++) {
296 unsigned char *tmp, *tmp2;
297 SilcUInt32 tmp_len, tmp2_len;
299 if (silc_buffer_unformat(buffer,
300 SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
301 SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
305 attr->extended_type[i] = silc_buffer_alloc(tmp_len);
306 attr->extended_data[i] = silc_buffer_alloc(tmp2_len);
307 if (!attr->extended_type[i] || !attr->extended_data[i])
309 silc_buffer_put(attr->extended_type[i], tmp, tmp_len);
310 silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len);
312 silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
319 silc_sftp_attr_free(attr);
323 /* Frees the attributes context and its internals. */
325 void silc_sftp_attr_free(SilcSFTPAttributes attr)
329 for (i = 0; i < attr->extended_count; i++) {
330 silc_buffer_free(attr->extended_type[i]);
331 silc_buffer_free(attr->extended_data[i]);
333 silc_free(attr->extended_type);
334 silc_free(attr->extended_data);
338 /* Adds an entry to the `name' context. */
340 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
341 const char *long_name, SilcSFTPAttributes attrs)
343 name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
345 name->long_filename = silc_realloc(name->long_filename,
346 sizeof(*name->long_filename) *
348 name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
350 if (!name->filename || !name->long_filename || !name->attrs)
353 name->filename[name->count] = strdup(short_name);
354 name->long_filename[name->count] = strdup(long_name);
355 name->attrs[name->count] = attrs;
359 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
360 The caller must free the buffer. */
362 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
366 SilcBuffer *attr_buf;
368 attr_buf = silc_calloc(name->count, sizeof(*attr_buf));
372 for (i = 0; i < name->count; i++) {
373 len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i]));
374 attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
377 len += silc_buffer_len(attr_buf[i]);
380 buffer = silc_buffer_alloc(len);
383 silc_buffer_end(buffer);
385 silc_buffer_format(buffer,
386 SILC_STR_UI_INT(name->count),
388 silc_buffer_pull(buffer, 4);
390 for (i = 0; i < name->count; i++) {
392 silc_buffer_format(buffer,
393 SILC_STR_UI_INT(strlen(name->filename[i])),
394 SILC_STR_UI32_STRING(name->filename[i]),
395 SILC_STR_UI_INT(strlen(name->long_filename[i])),
396 SILC_STR_UI32_STRING(name->long_filename[i]),
397 SILC_STR_DATA(silc_buffer_data(attr_buf[i]),
398 silc_buffer_len(attr_buf[i])),
401 silc_buffer_pull(buffer, len);
402 silc_free(attr_buf[i]);
406 silc_buffer_push(buffer, buffer->data - buffer->head);
411 /* Decodes a SilcSFTPName structure from the `buffer' that must include
412 `count' many name, longname and attribute values. Returns the allocated
413 structure or NULL on error. */
415 SilcSFTPName silc_sftp_name_decode(SilcUInt32 count, SilcBuffer buffer)
421 name = silc_calloc(1, sizeof(*name));
424 name->filename = silc_calloc(count, sizeof(*name->filename));
425 name->long_filename = silc_calloc(count, sizeof(*name->filename));
426 name->attrs = silc_calloc(count, sizeof(*name->attrs));
427 if (!name->filename || !name->long_filename || !name->attrs) {
428 silc_sftp_name_free(name);
433 for (i = 0; i < count; i++) {
435 silc_buffer_unformat(buffer,
436 SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
437 SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
440 silc_sftp_name_free(name);
444 silc_buffer_pull(buffer, ret);
446 /* Decode attributes, this will pull the `buffer' to correct place
447 for next round automatically. */
448 name->attrs[i] = silc_sftp_attr_decode(buffer);
449 if (!name->attrs[i]) {
450 silc_sftp_name_free(name);
458 /* Frees the name context and its internals. */
460 void silc_sftp_name_free(SilcSFTPName name)
464 for (i = 0; i < name->count; i++) {
465 silc_free(name->filename[i]);
466 silc_free(name->long_filename[i]);
467 silc_sftp_attr_free(name->attrs[i]);
470 silc_free(name->filename);
471 silc_free(name->long_filename);
472 silc_free(name->attrs);
476 /* Maps errno to SFTP status message. */
478 SilcSFTPStatus silc_sftp_map_errno(int err)
484 ret = SILC_SFTP_STATUS_OK;
489 ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
494 ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
498 ret = SILC_SFTP_STATUS_BAD_MESSAGE;
501 ret = SILC_SFTP_STATUS_FAILURE;