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, 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 (packet_buf->truelen < 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, SILC_BUFFER_END(buffer));
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 > (packet->len - 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)
138 if (attr->flags & SILC_SFTP_ATTR_SIZE)
140 if (attr->flags & SILC_SFTP_ATTR_UIDGID)
142 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
144 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
146 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
148 for (i = 0; i < attr->extended_count; i++) {
150 len += attr->extended_type[i]->len;
151 len += attr->extended_data[i]->len;
155 buffer = silc_buffer_alloc(len);
158 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
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++) {
203 silc_buffer_format(buffer,
204 SILC_STR_UI_INT(attr->extended_type[i]->len),
205 SILC_STR_UI_XNSTRING(attr->extended_type[i]->data,
206 attr->extended_type[i]->len),
207 SILC_STR_UI_INT(attr->extended_data[i]->len),
208 SILC_STR_UI_XNSTRING(attr->extended_data[i]->data,
209 attr->extended_data[i]->len),
211 silc_buffer_pull(buffer, ret);
215 silc_buffer_push(buffer, buffer->data - buffer->head);
220 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
221 attributes that the caller must free or NULL on error. */
223 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
225 SilcSFTPAttributes attr;
227 attr = silc_calloc(1, sizeof(*attr));
231 if (silc_buffer_unformat(buffer,
232 SILC_STR_UI_INT(&attr->flags),
236 silc_buffer_pull(buffer, 4);
238 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
239 if (silc_buffer_unformat(buffer,
240 SILC_STR_UI_INT64(&attr->size),
244 silc_buffer_pull(buffer, 8);
247 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
248 if (silc_buffer_unformat(buffer,
249 SILC_STR_UI_INT(&attr->uid),
250 SILC_STR_UI_INT(&attr->gid),
254 silc_buffer_pull(buffer, 8);
257 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
258 if (silc_buffer_unformat(buffer,
259 SILC_STR_UI_INT(&attr->permissions),
263 silc_buffer_pull(buffer, 4);
266 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
267 if (silc_buffer_unformat(buffer,
268 SILC_STR_UI_INT(&attr->atime),
269 SILC_STR_UI_INT(&attr->mtime),
273 silc_buffer_pull(buffer, 8);
276 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
279 if (silc_buffer_unformat(buffer,
280 SILC_STR_UI_INT(&attr->extended_count),
284 silc_buffer_pull(buffer, 4);
286 attr->extended_type = silc_calloc(attr->extended_count,
287 sizeof(*attr->extended_type));
288 attr->extended_data = silc_calloc(attr->extended_count,
289 sizeof(*attr->extended_data));
290 if (!attr->extended_type || !attr->extended_data)
293 for (i = 0; i < attr->extended_count; i++) {
294 unsigned char *tmp, *tmp2;
295 SilcUInt32 tmp_len, tmp2_len;
297 if (silc_buffer_unformat(buffer,
298 SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
299 SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
303 attr->extended_type[i] = silc_buffer_alloc(tmp_len);
304 attr->extended_data[i] = silc_buffer_alloc(tmp2_len);
305 if (!attr->extended_type[i] || !attr->extended_data[i])
307 silc_buffer_put(attr->extended_type[i], tmp, tmp_len);
308 silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len);
310 silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
317 silc_sftp_attr_free(attr);
321 /* Frees the attributes context and its internals. */
323 void silc_sftp_attr_free(SilcSFTPAttributes attr)
327 for (i = 0; i < attr->extended_count; i++) {
328 silc_buffer_free(attr->extended_type[i]);
329 silc_buffer_free(attr->extended_data[i]);
331 silc_free(attr->extended_type);
332 silc_free(attr->extended_data);
336 /* Adds an entry to the `name' context. */
338 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
339 const char *long_name, SilcSFTPAttributes attrs)
341 name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
343 name->long_filename = silc_realloc(name->long_filename,
344 sizeof(*name->long_filename) *
346 name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
348 if (!name->filename || !name->long_filename || !name->attrs)
351 name->filename[name->count] = strdup(short_name);
352 name->long_filename[name->count] = strdup(long_name);
353 name->attrs[name->count] = attrs;
357 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
358 The caller must free the buffer. */
360 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
364 SilcBuffer *attr_buf;
366 attr_buf = silc_calloc(name->count, sizeof(*attr_buf));
370 for (i = 0; i < name->count; i++) {
371 len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i]));
372 attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
375 len += attr_buf[i]->len;
378 buffer = silc_buffer_alloc(len);
381 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
383 silc_buffer_format(buffer,
384 SILC_STR_UI_INT(name->count),
386 silc_buffer_pull(buffer, 4);
388 for (i = 0; i < name->count; i++) {
390 silc_buffer_format(buffer,
391 SILC_STR_UI_INT(strlen(name->filename[i])),
392 SILC_STR_UI32_STRING(name->filename[i]),
393 SILC_STR_UI_INT(strlen(name->long_filename[i])),
394 SILC_STR_UI32_STRING(name->long_filename[i]),
395 SILC_STR_UI_XNSTRING(attr_buf[i]->data,
399 silc_buffer_pull(buffer, len);
400 silc_free(attr_buf[i]);
404 silc_buffer_push(buffer, buffer->data - buffer->head);
409 /* Decodes a SilcSFTPName structure from the `buffer' that must include
410 `count' many name, longname and attribute values. Returns the allocated
411 structure or NULL on error. */
413 SilcSFTPName silc_sftp_name_decode(SilcUInt32 count, SilcBuffer buffer)
419 name = silc_calloc(1, sizeof(*name));
422 name->filename = silc_calloc(count, sizeof(*name->filename));
423 name->long_filename = silc_calloc(count, sizeof(*name->filename));
424 name->attrs = silc_calloc(count, sizeof(*name->attrs));
425 if (!name->filename || !name->long_filename || !name->attrs) {
426 silc_sftp_name_free(name);
431 for (i = 0; i < count; i++) {
433 silc_buffer_unformat(buffer,
434 SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
435 SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
438 silc_sftp_name_free(name);
442 silc_buffer_pull(buffer, ret);
444 /* Decode attributes, this will pull the `buffer' to correct place
445 for next round automatically. */
446 name->attrs[i] = silc_sftp_attr_decode(buffer);
447 if (!name->attrs[i]) {
448 silc_sftp_name_free(name);
456 /* Frees the name context and its internals. */
458 void silc_sftp_name_free(SilcSFTPName name)
462 for (i = 0; i < name->count; i++) {
463 silc_free(name->filename[i]);
464 silc_free(name->long_filename[i]);
465 silc_sftp_attr_free(name->attrs[i]);
468 silc_free(name->filename);
469 silc_free(name->long_filename);
470 silc_free(name->attrs);
474 /* Maps errno to SFTP status message. */
476 SilcSFTPStatus silc_sftp_map_errno(int err)
482 ret = SILC_SFTP_STATUS_OK;
487 ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
492 ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
496 ret = SILC_SFTP_STATUS_BAD_MESSAGE;
499 ret = SILC_SFTP_STATUS_FAILURE;