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
30 SilcBuffer silc_sftp_packet_encode(SilcSFTPPacket packet, uint32 len, ...)
36 buffer = silc_sftp_packet_encode_vp(packet, len, vp);
42 /* Same as silc_sftp_packet_encode but takes the variable argument list
43 pointer as argument. */
45 SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet, uint32 len,
51 buffer = silc_buffer_alloc(4 + 1 + len);
52 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
53 silc_buffer_format(buffer,
55 SILC_STR_UI_CHAR(packet),
57 silc_buffer_pull(buffer, 5);
59 ret = silc_buffer_format_vp(buffer, vp);
61 silc_buffer_free(buffer);
65 silc_buffer_push(buffer, 5);
70 /* Decodes the SFTP packet data `packet' and return the SFTP packet type.
71 The payload of the packet is returned to the `payload' pointer. Returns
72 0 if error occurred during decoding. */
74 SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
75 unsigned char **payload,
82 ret = silc_buffer_unformat(packet,
83 SILC_STR_UI_INT(&len),
84 SILC_STR_UI_CHAR(&type),
89 if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
92 if (len > (packet->len - 5))
95 silc_buffer_pull(packet, 5);
96 ret = silc_buffer_unformat(packet,
97 SILC_STR_UI_XNSTRING(payload, len),
102 silc_buffer_push(packet, 5);
106 return (SilcSFTPPacket)type;
109 /* Encodes the SFTP attributes to a buffer and returns the allocated buffer.
110 The caller must free the buffer. */
112 SilcBuffer silc_sftp_attr_encode(SilcSFTPAttributes attr)
117 if (attr->flags & SILC_SFTP_ATTR_SIZE)
119 if (attr->flags & SILC_SFTP_ATTR_UIDGID)
121 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS)
123 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME)
125 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
127 for (i = 0; i < attr->extended_count; i++) {
129 len += attr->extended_type[i]->len;
130 len += attr->extended_data[i]->len;
134 buffer = silc_buffer_alloc(len);
135 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
137 silc_buffer_format(buffer,
138 SILC_STR_UI_INT(attr->flags),
140 silc_buffer_pull(buffer, 4);
142 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
143 silc_buffer_format(buffer,
144 SILC_STR_UI_INT64(attr->size),
146 silc_buffer_pull(buffer, 8);
149 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
150 silc_buffer_format(buffer,
151 SILC_STR_UI_INT(attr->uid),
152 SILC_STR_UI_INT(attr->gid),
154 silc_buffer_pull(buffer, 8);
157 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
158 silc_buffer_format(buffer,
159 SILC_STR_UI_INT(attr->permissions),
161 silc_buffer_pull(buffer, 4);
164 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
165 silc_buffer_format(buffer,
166 SILC_STR_UI_INT(attr->atime),
167 SILC_STR_UI_INT(attr->mtime),
169 silc_buffer_pull(buffer, 8);
172 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
173 silc_buffer_format(buffer,
174 SILC_STR_UI_INT(attr->extended_count),
176 silc_buffer_pull(buffer, 4);
178 for (i = 0; i < attr->extended_count; i++) {
180 silc_buffer_format(buffer,
181 SILC_STR_UI_INT(attr->extended_type[i]->len),
182 SILC_STR_UI_XNSTRING(attr->extended_type[i]->data,
183 attr->extended_type[i]->len),
184 SILC_STR_UI_INT(attr->extended_data[i]->len),
185 SILC_STR_UI_XNSTRING(attr->extended_data[i]->data,
186 attr->extended_data[i]->len),
188 silc_buffer_pull(buffer, ret);
192 silc_buffer_push(buffer, buffer->data - buffer->head);
197 /* Decodes SilcSFTPAttributes from the buffer `buffer'. Returns the allocated
198 attributes that the caller must free or NULL on error. */
200 SilcSFTPAttributes silc_sftp_attr_decode(SilcBuffer buffer)
202 SilcSFTPAttributes attr;
204 attr = silc_calloc(1, sizeof(*attr));
206 if (silc_buffer_unformat(buffer,
207 SILC_STR_UI_INT(&attr->flags),
211 silc_buffer_pull(buffer, 4);
213 if (attr->flags & SILC_SFTP_ATTR_SIZE) {
214 if (silc_buffer_unformat(buffer,
215 SILC_STR_UI_INT64(&attr->size),
219 silc_buffer_pull(buffer, 8);
222 if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
223 if (silc_buffer_unformat(buffer,
224 SILC_STR_UI_INT(&attr->uid),
225 SILC_STR_UI_INT(&attr->gid),
229 silc_buffer_pull(buffer, 8);
232 if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
233 if (silc_buffer_unformat(buffer,
234 SILC_STR_UI_INT(&attr->permissions),
238 silc_buffer_pull(buffer, 4);
241 if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
242 if (silc_buffer_unformat(buffer,
243 SILC_STR_UI_INT(&attr->atime),
244 SILC_STR_UI_INT(&attr->mtime),
248 silc_buffer_pull(buffer, 8);
251 if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
254 if (silc_buffer_unformat(buffer,
255 SILC_STR_UI_INT(&attr->extended_count),
259 silc_buffer_pull(buffer, 4);
261 attr->extended_type = silc_calloc(attr->extended_count,
262 sizeof(*attr->extended_type));
263 attr->extended_data = silc_calloc(attr->extended_count,
264 sizeof(*attr->extended_data));
265 for (i = 0; i < attr->extended_count; i++) {
266 unsigned char *tmp, *tmp2;
267 uint32 tmp_len, tmp2_len;
269 if (silc_buffer_unformat(buffer,
270 SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
271 SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
275 attr->extended_type[i] = silc_buffer_alloc(tmp_len);
276 attr->extended_data[i] = silc_buffer_alloc(tmp2_len);
277 silc_buffer_put(attr->extended_type[i], tmp, tmp_len);
278 silc_buffer_put(attr->extended_data[i], tmp2, tmp2_len);
280 silc_buffer_pull(buffer, tmp_len + 4 + tmp2_len + 4);
287 silc_sftp_attr_free(attr);
291 /* Frees the attributes context and its internals. */
293 void silc_sftp_attr_free(SilcSFTPAttributes attr)
297 for (i = 0; i < attr->extended_count; i++) {
298 silc_buffer_free(attr->extended_type[i]);
299 silc_buffer_free(attr->extended_data[i]);
301 silc_free(attr->extended_type);
302 silc_free(attr->extended_data);
306 /* Adds an entry to the `name' context. */
308 void silc_sftp_name_add(SilcSFTPName name, const char *short_name,
309 const char *long_name, SilcSFTPAttributes attrs)
311 name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
313 name->long_filename = silc_realloc(name->long_filename,
314 sizeof(*name->long_filename) *
316 name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
319 name->filename[name->count] = strdup(short_name);
320 name->long_filename[name->count] = strdup(long_name);
321 name->attrs[name->count] = attrs;
325 /* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
326 The caller must free the buffer. */
328 SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
332 SilcBuffer *attr_buf;
334 attr_buf = silc_calloc(name->count, sizeof(*attr_buf));
335 for (i = 0; i < name->count; i++) {
336 len += (8 + strlen(name->filename[i]) + strlen(name->long_filename[i]));
337 attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
338 len += attr_buf[i]->len;
341 buffer = silc_buffer_alloc(len);
342 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
344 silc_buffer_format(buffer,
345 SILC_STR_UI_INT(name->count),
347 silc_buffer_pull(buffer, 4);
349 for (i = 0; i < name->count; i++) {
351 silc_buffer_format(buffer,
352 SILC_STR_UI_INT(strlen(name->filename[i])),
353 SILC_STR_UI32_STRING(name->filename[i]),
354 SILC_STR_UI_INT(strlen(name->long_filename[i])),
355 SILC_STR_UI32_STRING(name->long_filename[i]),
356 SILC_STR_UI_XNSTRING(attr_buf[i]->data,
360 silc_buffer_pull(buffer, len);
361 silc_free(attr_buf[i]);
365 silc_buffer_push(buffer, buffer->data - buffer->head);
370 /* Decodes a SilcSFTPName structure from the `buffer' that must include
371 `count' many name, longname and attribute values. Returns the allocated
372 structure or NULL on error. */
374 SilcSFTPName silc_sftp_name_decode(uint32 count, SilcBuffer buffer)
380 name = silc_calloc(1, sizeof(*name));
381 name->filename = silc_calloc(count, sizeof(*name->filename));
382 name->long_filename = silc_calloc(count, sizeof(*name->filename));
383 name->attrs = silc_calloc(count, sizeof(*name->attrs));
386 for (i = 0; i < count; i++) {
388 silc_buffer_unformat(buffer,
389 SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
390 SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
393 silc_sftp_name_free(name);
397 silc_buffer_pull(buffer, ret);
399 /* Decode attributes, this will pull the `buffer' to correct place
400 for next round automatically. */
401 name->attrs[i] = silc_sftp_attr_decode(buffer);
407 /* Frees the name context and its internals. */
409 void silc_sftp_name_free(SilcSFTPName name)
413 for (i = 0; i < name->count; i++) {
414 silc_free(name->filename[i]);
415 silc_free(name->long_filename[i]);
416 silc_sftp_attr_free(name->attrs[i]);
419 silc_free(name->filename);
420 silc_free(name->long_filename);
421 silc_free(name->attrs);
425 /* Maps errno to SFTP status message. */
427 SilcSFTPStatus silc_sftp_map_errno(int err)
433 ret = SILC_SFTP_STATUS_OK;
438 ret = SILC_SFTP_STATUS_NO_SUCH_FILE;
443 ret = SILC_SFTP_STATUS_PERMISSION_DENIED;
447 ret = SILC_SFTP_STATUS_BAD_MESSAGE;
450 ret = SILC_SFTP_STATUS_FAILURE;