1 /*
2
3 sftp_fs_memory.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2001 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19 /* $Id$ */
20 /* XXX TODO Win32 support */
21
22 #include "silc.h"
23 #include "silcsftp.h"
24 #include "silcsftp_fs.h"
25 #include "sftp_util.h"
26
27 #define DIR_SEPARATOR "/"
28
29 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory;
30
31 typedef struct MemFSEntryStruct {
32 struct MemFSEntryStruct **entry; /* Files and sub-directories */
33 SilcUInt32 entry_count; /* Number of files and sub-directories */
34 struct MemFSEntryStruct *parent; /* non-NULL if `directory' is TRUE,
35 includes parent directory. */
36 SilcUInt32 created; /* Time of creation */
37 char *name; /* Name of the entry */
38 char *data; /* Data of the entry */
39 unsigned int directory : 1; /* Set if this is directory */
40 unsigned int perm : 7; /* Permissions */
41 } *MemFSEntry;
42
43 /* File handle. */
44 typedef struct {
45 SilcUInt32 handle; /* Handle index */
46 int fd; /* Real file handle */
47 MemFSEntry entry; /* Filesystem entry */
48 } *MemFSFileHandle;
49
50 /* Memory filesystem */
51 typedef struct {
52 MemFSEntry root; /* Root of the filesystem hierarchy */
53 SilcSFTPFSMemoryPerm root_perm;
54 MemFSFileHandle *handles; /* Open file handles */
55 SilcUInt32 handles_count;
56 } *MemFS;
57
58 /* Generates absolute path from relative path that may include '.' and '..'
59 in the path. */
60
memfs_expand_path(MemFSEntry root,const char * path)61 static char *memfs_expand_path(MemFSEntry root, const char *path)
62 {
63 if (!strstr(path, "./") && !strstr(path, "../") &&
64 !strstr(path, "/..") && !strstr(path, "/."))
65 return strdup(path);
66
67 /* XXX TODO */
68 return NULL;
69 }
70
71 /* Add `entry' to directory `dir'. */
72
memfs_add_entry(MemFSEntry dir,MemFSEntry entry,SilcBool check_perm)73 static SilcBool memfs_add_entry(MemFSEntry dir, MemFSEntry entry,
74 SilcBool check_perm)
75 {
76 int i;
77
78 /* Must be both write and exec permissions */
79 if (check_perm &&
80 !((dir->perm & SILC_SFTP_FS_PERM_WRITE) &&
81 (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
82 return FALSE;
83
84 if (!dir->entry) {
85 dir->entry = silc_calloc(3, sizeof(*entry));
86 if (!dir->entry)
87 return FALSE;
88 dir->entry[0] = entry;
89 dir->entry_count = 3;
90 entry->created = time(0);
91 return TRUE;
92 }
93
94 for (i = 0; i < dir->entry_count; i++) {
95 if (dir->entry[i])
96 continue;
97
98 dir->entry[i] = entry;
99 entry->created = time(0);
100 return TRUE;
101 }
102
103 dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
104 (dir->entry_count + 3));
105 if (!dir->entry)
106 return FALSE;
107 for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
108 dir->entry[i] = NULL;
109 dir->entry[dir->entry_count] = entry;
110 dir->entry_count += 3;
111 entry->created = time(0);
112
113 return TRUE;
114 }
115
116 /* Removes entry `entry' and all entries under it recursively. */
117
memfs_del_entry(MemFSEntry entry,SilcBool check_perm)118 static SilcBool memfs_del_entry(MemFSEntry entry, SilcBool check_perm)
119 {
120 int i;
121
122 /* Directories cannot be removed from remote access */
123 if (check_perm)
124 return FALSE;
125
126 silc_free(entry->name);
127 silc_free(entry->data);
128
129 /* Delete all entries recursively under this entry */
130 for (i = 0; i < entry->entry_count; i++) {
131 if (entry->entry[i]) {
132 if (!memfs_del_entry(entry->entry[i], FALSE))
133 return FALSE;
134 }
135 }
136 silc_free(entry->entry);
137
138 /* Remove from parent */
139 if (entry->parent) {
140 for (i = 0; i < entry->parent->entry_count; i++) {
141 if (entry->parent->entry[i] == entry) {
142 entry->parent->entry[i] = NULL;
143 break;
144 }
145 }
146 }
147
148 silc_free(entry);
149
150 return TRUE;
151 }
152
153 /* Finds first occurence of entry named `name' under the directory `dir'.
154 This does not check subdirectories recursively. */
155
memfs_find_entry(MemFSEntry dir,const char * name,SilcUInt32 name_len)156 static MemFSEntry memfs_find_entry(MemFSEntry dir, const char *name,
157 SilcUInt32 name_len)
158 {
159 int i;
160
161 for (i = 0; i < dir->entry_count; i++) {
162 if (!dir->entry[i])
163 continue;
164
165 if (!strncmp(name, dir->entry[i]->name, name_len))
166 return dir->entry[i];
167 }
168
169 return NULL;
170 }
171
172 /* Finds the entry by the `path' which may include full path or
173 relative path. */
174
memfs_find_entry_path(MemFSEntry dir,const char * p)175 static MemFSEntry memfs_find_entry_path(MemFSEntry dir, const char *p)
176 {
177 MemFSEntry entry = NULL;
178 int len;
179 char *path, *cp;
180
181 cp = path = memfs_expand_path(dir, p);
182 if (!cp)
183 return NULL;
184
185 if (strlen(cp) == 1 && cp[0] == '/')
186 return dir;
187
188 if (cp[0] == '/')
189 cp++;
190 len = strcspn(cp, DIR_SEPARATOR);
191 while (cp && len) {
192 entry = memfs_find_entry(dir, cp, len);
193 if (!entry) {
194 silc_free(cp);
195 return NULL;
196 }
197 cp += len;
198 if (!strlen(cp))
199 break;
200 cp++;
201 len = strcspn(cp, DIR_SEPARATOR);
202 dir = entry;
203 }
204
205 silc_free(path);
206 return entry;
207 }
208
209 /* Deletes entry by the name `name' from the directory `dir'. This does
210 not check subdirectories recursively. */
211
memfs_del_entry_name(MemFSEntry dir,const char * name,SilcUInt32 name_len,SilcBool check_perm)212 static SilcBool memfs_del_entry_name(MemFSEntry dir, const char *name,
213 SilcUInt32 name_len, SilcBool check_perm)
214 {
215 MemFSEntry entry;
216
217 /* Files cannot be removed from remote access */
218 if (check_perm)
219 return FALSE;
220
221 entry = memfs_find_entry(dir, name, name_len);
222
223 if (entry)
224 return memfs_del_entry(entry, check_perm);
225
226 return FALSE;
227 }
228
229 /* Create new handle and add it to the list of open handles. */
230
memfs_create_handle(MemFS fs,int fd,MemFSEntry entry)231 static MemFSFileHandle memfs_create_handle(MemFS fs, int fd, MemFSEntry entry)
232 {
233 MemFSFileHandle handle;
234 int i;
235
236 handle = silc_calloc(1, sizeof(*handle));
237 if (!handle)
238 return NULL;
239 handle->fd = fd;
240 handle->entry = entry;
241
242 if (!fs->handles) {
243 fs->handles = silc_calloc(5, sizeof(*fs->handles));
244 if (!fs->handles)
245 return NULL;
246 fs->handles[0] = handle;
247 fs->handles_count = 5;
248
249 handle->handle = 0;
250
251 return handle;
252 }
253
254 for (i = 0; i < fs->handles_count; i++) {
255 if (fs->handles[i])
256 continue;
257
258 fs->handles[i] = handle;
259
260 handle->handle = i;
261
262 return handle;
263 }
264
265 fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
266 (fs->handles_count + 5));
267 if (!fs->handles)
268 return NULL;
269 for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
270 fs->handles[i] = NULL;
271 fs->handles[fs->handles_count] = handle;
272 handle->handle = fs->handles_count;
273 fs->handles_count += 5;
274
275 return handle;
276 }
277
278 /* Deletes the handle and remove it from the open handle list. */
279
memfs_del_handle(MemFS fs,MemFSFileHandle handle)280 static SilcBool memfs_del_handle(MemFS fs, MemFSFileHandle handle)
281 {
282 if (handle->handle > fs->handles_count)
283 return FALSE;
284
285 if (!fs->handles[handle->handle])
286 return FALSE;
287
288 if (fs->handles[handle->handle] == handle) {
289 fs->handles[handle->handle] = NULL;
290 if (handle->fd != -1)
291 silc_file_close(handle->fd);
292 silc_free(handle);
293 return TRUE;
294 }
295
296 return FALSE;
297 }
298
299 /* Find handle by handle index. */
300
memfs_find_handle(MemFS fs,SilcUInt32 handle)301 static MemFSFileHandle memfs_find_handle(MemFS fs, SilcUInt32 handle)
302 {
303 if (handle > fs->handles_count)
304 return NULL;
305
306 if (!fs->handles[handle])
307 return NULL;
308
309 if (fs->handles[handle]->handle != handle)
310 return NULL;
311
312 return fs->handles[handle];
313 }
314
315 /* Allocates memory filesystem context and returns the context. The
316 context can be given as argument to the silc_sftp_server_start function.
317 The context must be freed by the caller using the function
318 silc_sftp_fs_memory_free. The `perm' is the permissions for the root
319 directory of the filesystem (/ dir). */
320
silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)321 SilcSFTPFilesystem silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
322 {
323 SilcSFTPFilesystem filesystem;
324 MemFS fs;
325
326 fs = silc_calloc(1, sizeof(*fs));
327 if (!fs)
328 return NULL;
329
330 fs->root = silc_calloc(1, sizeof(*fs->root));
331 if (!fs->root) {
332 silc_free(fs);
333 return NULL;
334 }
335
336 fs->root->perm = perm;
337 fs->root_perm = perm;
338 fs->root->directory = TRUE;
339 fs->root->name = strdup(DIR_SEPARATOR);
340 if (!fs->root->name) {
341 silc_free(fs->root);
342 silc_free(fs);
343 }
344
345 filesystem = silc_calloc(1, sizeof(*filesystem));
346 if (!filesystem) {
347 silc_free(fs->root->name);
348 silc_free(fs->root);
349 silc_free(fs);
350 return NULL;
351 }
352
353 filesystem->fs = (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
354 filesystem->fs_context = (void *)fs;
355
356 return filesystem;
357 }
358
359 /* Frees the memory filesystem context. */
360
silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)361 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
362 {
363 MemFS memfs = (MemFS)fs->fs_context;
364
365 silc_free(memfs->root);
366 silc_free(memfs);
367 }
368
369 /* Adds a new directory to the memory filesystem. Returns the directory
370 context that can be used to add for example files to the directory
371 or new subdirectories under the directory. The `dir' is the parent
372 directory of the directory to be added. If this directory is to be
373 added to the root directory the `dir' is NULL. The `name' is the name
374 of the directory. If error occurs this returns NULL. The caller must
375 not free the returned context. The `perm' will indicate the permissions
376 for the directory and they work in POSIX style. */
377
silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs,void * dir,SilcSFTPFSMemoryPerm perm,const char * name)378 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
379 SilcSFTPFSMemoryPerm perm,
380 const char *name)
381 {
382 MemFS memfs = (MemFS)fs->fs_context;
383 MemFSEntry entry;
384
385 entry = silc_calloc(1, sizeof(*entry));
386 if (!entry)
387 return NULL;
388
389 entry->perm = perm;
390 entry->directory = TRUE;
391 entry->parent = dir ? dir : memfs->root;
392 entry->name = strdup(name);
393 if (!entry->name) {
394 silc_free(entry);
395 return NULL;
396 }
397
398 if (!memfs_add_entry(dir ? dir : memfs->root, entry, FALSE)) {
399 silc_free(entry->name);
400 silc_free(entry);
401 return NULL;
402 }
403
404 return entry;
405 }
406
407 /* Deletes a directory indicated by the `dir'. All files and subdirectories
408 in this directory is also removed. If the `dir' is NULL then all
409 directories and files are removed from the filesystem. Returns TRUE
410 if the removing was success. This is the only way to remove directories
411 in memory file system. The filesystem does not allow removing directories
412 with remote access using the filesystem access function sftp_rmdir. */
413
silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs,void * dir)414 SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
415 {
416 MemFS memfs = (MemFS)fs->fs_context;
417 SilcBool ret;
418
419 if (dir)
420 return memfs_del_entry(dir, FALSE);
421
422 /* Remove from root */
423 ret = memfs_del_entry(memfs->root, FALSE);
424
425 memfs->root = silc_calloc(1, sizeof(*memfs->root));
426 if (!memfs->root)
427 return FALSE;
428
429 memfs->root->perm = memfs->root_perm;
430 memfs->root->directory = TRUE;
431 memfs->root->name = strdup(DIR_SEPARATOR);
432 if (!memfs->root->name) {
433 silc_free(memfs->root);
434 memfs->root = NULL;
435 return FALSE;
436 }
437
438 return ret;
439 }
440
441 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
442 is NULL the file is added to the root directory. The `filename' is the
443 filename in the directory. The `realpath' is the real filepath in the
444 physical filesystem. It is used to actually access the file from the
445 memory filesystem. The `perm' will indicate the permissions for th e
446 file and they work in POSIX style. Returns TRUE if the file was
447 added to the directory. */
448
silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs,void * dir,SilcSFTPFSMemoryPerm perm,const char * filename,const char * realpath)449 SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
450 SilcSFTPFSMemoryPerm perm,
451 const char *filename,
452 const char *realpath)
453 {
454 MemFS memfs = (MemFS)fs->fs_context;
455 MemFSEntry entry;
456
457 entry = silc_calloc(1, sizeof(*entry));
458 if (!entry)
459 return FALSE;
460
461 entry->perm = perm;
462 entry->directory = FALSE;
463 entry->name = strdup(filename);
464 entry->data = strdup(realpath);
465 if (!entry->name || !entry->data) {
466 silc_free(entry->name);
467 silc_free(entry->data);
468 silc_free(entry);
469 return FALSE;
470 }
471
472 return memfs_add_entry(dir ? dir : memfs->root, entry, FALSE);
473 }
474
475 /* Removes a file indicated by the `filename' from the directory
476 indicated by the `dir'. Returns TRUE if the removing was success. */
477
silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs,void * dir,const char * filename)478 SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
479 const char *filename)
480 {
481 MemFS memfs = (MemFS)fs->fs_context;
482
483 if (!filename)
484 return FALSE;
485
486 return memfs_del_entry_name(dir ? dir : memfs->root, filename,
487 strlen(filename), FALSE);
488 }
489
memfs_get_handle(void * context,SilcSFTP sftp,const unsigned char * data,SilcUInt32 data_len)490 SilcSFTPHandle memfs_get_handle(void *context, SilcSFTP sftp,
491 const unsigned char *data,
492 SilcUInt32 data_len)
493 {
494 MemFS fs = (MemFS)context;
495 SilcUInt32 handle;
496
497 if (data_len < 4)
498 return NULL;
499
500 SILC_GET32_MSB(handle, data);
501 return (SilcSFTPHandle)memfs_find_handle(fs, handle);
502 }
503
memfs_encode_handle(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcUInt32 * handle_len)504 unsigned char *memfs_encode_handle(void *context, SilcSFTP sftp,
505 SilcSFTPHandle handle,
506 SilcUInt32 *handle_len)
507 {
508 unsigned char *data;
509 MemFSFileHandle h = (MemFSFileHandle)handle;
510
511 data = silc_calloc(4, sizeof(*data));
512 if (!data)
513 return NULL;
514
515 SILC_PUT32_MSB(h->handle, data);
516 *handle_len = 4;
517 return data;
518 }
519
memfs_open(void * context,SilcSFTP sftp,const char * filename,SilcSFTPFileOperation pflags,SilcSFTPAttributes attrs,SilcSFTPHandleCallback callback,void * callback_context)520 void memfs_open(void *context, SilcSFTP sftp,
521 const char *filename,
522 SilcSFTPFileOperation pflags,
523 SilcSFTPAttributes attrs,
524 SilcSFTPHandleCallback callback,
525 void *callback_context)
526 {
527 MemFS fs = (MemFS)context;
528 MemFSEntry entry;
529 MemFSFileHandle handle;
530 int flags = 0, fd;
531
532 /* CREAT and TRUNC not supported */
533 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
534 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
535 return;
536 }
537
538 /* Find such file */
539 entry = memfs_find_entry_path(fs->root, filename);
540 if (!entry) {
541 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
542 return;
543 }
544
545 if (entry->directory || !entry->data) {
546 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
547 return;
548 }
549
550 /* Check for reading */
551 if ((pflags & SILC_SFTP_FXF_READ) &&
552 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
553 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
554 callback_context);
555 return;
556 }
557
558 /* Check for writing */
559 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
560 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
561 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
562 callback_context);
563 return;
564 }
565
566 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
567 flags = O_RDWR;
568 else if (pflags & SILC_SFTP_FXF_READ)
569 flags = O_RDONLY;
570 else if (pflags & SILC_SFTP_FXF_WRITE)
571 flags = O_WRONLY;
572 if (pflags & SILC_SFTP_FXF_APPEND)
573 flags |= O_APPEND;
574
575 /* Attempt to open the file for real. */
576 fd = silc_file_open_mode(entry->data + 7, flags,
577 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
578 attrs->permissions : 0600));
579 if (fd == -1) {
580 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
581 return;
582 }
583
584 /* File opened, return handle */
585 handle = memfs_create_handle(fs, fd, entry);
586 if (handle)
587 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
588 callback_context);
589 else
590 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
591 callback_context);
592 }
593
memfs_close(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPStatusCallback callback,void * callback_context)594 void memfs_close(void *context, SilcSFTP sftp,
595 SilcSFTPHandle handle,
596 SilcSFTPStatusCallback callback,
597 void *callback_context)
598 {
599 MemFS fs = (MemFS)context;
600 MemFSFileHandle h = (MemFSFileHandle)handle;
601 int ret;
602
603 if (h->fd != -1) {
604 ret = silc_file_close(h->fd);
605 if (ret == -1) {
606 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
607 callback_context);
608 return;
609 }
610 }
611
612 memfs_del_handle(fs, h);
613 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
614 }
615
memfs_read(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcUInt64 offset,SilcUInt32 len,SilcSFTPDataCallback callback,void * callback_context)616 void memfs_read(void *context, SilcSFTP sftp,
617 SilcSFTPHandle handle,
618 SilcUInt64 offset,
619 SilcUInt32 len,
620 SilcSFTPDataCallback callback,
621 void *callback_context)
622 {
623 MemFSFileHandle h = (MemFSFileHandle)handle;
624 unsigned char data[63488];
625 int ret;
626
627 if (len > 63488)
628 len = 63488;
629
630 ret = lseek(h->fd, (off_t)offset, SEEK_SET);
631 if (ret < 0) {
632 if (!ret)
633 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
634 else
635 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
636 return;
637 }
638
639 /* Attempt to read */
640 ret = silc_file_read(h->fd, data, len);
641 if (ret <= 0) {
642 if (!ret)
643 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
644 else
645 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
646 return;
647 }
648
649 /* Return data */
650 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
651 ret, callback_context);
652 }
653
memfs_write(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcUInt64 offset,const unsigned char * data,SilcUInt32 data_len,SilcSFTPStatusCallback callback,void * callback_context)654 void memfs_write(void *context, SilcSFTP sftp,
655 SilcSFTPHandle handle,
656 SilcUInt64 offset,
657 const unsigned char *data,
658 SilcUInt32 data_len,
659 SilcSFTPStatusCallback callback,
660 void *callback_context)
661 {
662 MemFSFileHandle h = (MemFSFileHandle)handle;
663 int ret;
664
665 lseek(h->fd, (off_t)offset, SEEK_SET);
666
667 /* Attempt to write */
668 ret = silc_file_write(h->fd, data, data_len);
669 if (ret <= 0) {
670 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
671 callback_context);
672 return;
673 }
674
675 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
676 }
677
memfs_remove(void * context,SilcSFTP sftp,const char * filename,SilcSFTPStatusCallback callback,void * callback_context)678 void memfs_remove(void *context, SilcSFTP sftp,
679 const char *filename,
680 SilcSFTPStatusCallback callback,
681 void *callback_context)
682 {
683 /* Remove is not supported */
684 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
685 callback_context);
686 }
687
memfs_rename(void * context,SilcSFTP sftp,const char * oldname,const char * newname,SilcSFTPStatusCallback callback,void * callback_context)688 void memfs_rename(void *context, SilcSFTP sftp,
689 const char *oldname,
690 const char *newname,
691 SilcSFTPStatusCallback callback,
692 void *callback_context)
693 {
694 /* Rename is not supported */
695 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
696 callback_context);
697 }
698
memfs_mkdir(void * context,SilcSFTP sftp,const char * path,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * callback_context)699 void memfs_mkdir(void *context, SilcSFTP sftp,
700 const char *path,
701 SilcSFTPAttributes attrs,
702 SilcSFTPStatusCallback callback,
703 void *callback_context)
704 {
705 /* Mkdir is not supported */
706 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
707 callback_context);
708 }
709
memfs_rmdir(void * context,SilcSFTP sftp,const char * path,SilcSFTPStatusCallback callback,void * callback_context)710 void memfs_rmdir(void *context, SilcSFTP sftp,
711 const char *path,
712 SilcSFTPStatusCallback callback,
713 void *callback_context)
714 {
715 /* Rmdir is not supported */
716 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
717 callback_context);
718 }
719
memfs_opendir(void * context,SilcSFTP sftp,const char * path,SilcSFTPHandleCallback callback,void * callback_context)720 void memfs_opendir(void *context, SilcSFTP sftp,
721 const char *path,
722 SilcSFTPHandleCallback callback,
723 void *callback_context)
724 {
725 MemFS fs = (MemFS)context;
726 MemFSEntry entry;
727 MemFSFileHandle handle;
728
729 if (!path || !strlen(path))
730 path = (const char *)DIR_SEPARATOR;
731
732 /* Find such directory */
733 entry = memfs_find_entry_path(fs->root, path);
734 if (!entry) {
735 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
736 return;
737 }
738
739 if (!entry->directory) {
740 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
741 return;
742 }
743
744 /* Must be read permissions to open a directory */
745 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
746 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
747 callback_context);
748 return;
749 }
750
751 /* Directory opened, return handle */
752 handle = memfs_create_handle(fs, 0, entry);
753 if (handle)
754 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
755 callback_context);
756 else
757 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
758 callback_context);
759 }
760
memfs_readdir(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPNameCallback callback,void * callback_context)761 void memfs_readdir(void *context, SilcSFTP sftp,
762 SilcSFTPHandle handle,
763 SilcSFTPNameCallback callback,
764 void *callback_context)
765 {
766 MemFSFileHandle h = (MemFSFileHandle)handle;
767 MemFSEntry entry;
768 SilcSFTPName name;
769 SilcSFTPAttributes attrs;
770 int i;
771 char long_name[256];
772 SilcUInt64 filesize = 0;
773 char *date;
774 struct stat stats;
775
776 if (!h->entry->directory) {
777 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
778 return;
779 }
780
781 if (h->fd == -1) {
782 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
783 return;
784 }
785
786 name = silc_calloc(1, sizeof(*name));
787 if (!name) {
788 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
789 return;
790 }
791 for (i = h->fd; i < 100 + h->fd; i++) {
792 if (i >= h->entry->entry_count)
793 break;
794
795 entry = h->entry->entry[i];
796 if (!entry)
797 continue;
798
799 filesize = sizeof(*entry);
800 memset(long_name, 0, sizeof(long_name));
801
802 date = (char *)silc_time_string(entry->created);
803 if (strrchr(date, ':'))
804 *strrchr(date, ':') = '\0';
805
806 if (!entry->directory) {
807 filesize = silc_file_size(entry->data + 7);
808 memset(&stats, 0, sizeof(stats));
809 stat(entry->data + 7, &stats);
810 }
811
812 /* Long name format is:
813 drwx------ 1 324210 Apr 8 08:40 mail/
814 1234567890 123 12345678 123456789012 */
815 silc_snprintf(long_name, sizeof(long_name) - 1,
816 "%c%c%c%c------ %3d %8llu %12s %s%s",
817 (entry->directory ? 'd' : '-'),
818 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
819 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
820 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
821 (entry->directory ? (int)entry->entry_count : 1),
822 #ifndef SILC_WIN32
823 (unsigned long long)filesize,
824 #else
825 (unsigned long)filesize,
826 #endif
827 date, entry->name,
828 (entry->directory ? "/" :
829 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
830
831 /* Add attributes */
832 attrs = silc_calloc(1, sizeof(*attrs));
833 if (!attrs) {
834 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
835 return;
836 }
837 attrs->flags = (SILC_SFTP_ATTR_SIZE |
838 SILC_SFTP_ATTR_UIDGID);
839 attrs->size = filesize;
840 attrs->uid = 0; /* We use always 0 UID and GID */
841 attrs->gid = 0;
842 if (!entry->directory) {
843 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
844 attrs->atime = stats.st_atime;
845 attrs->mtime = stats.st_mtime;
846 }
847
848 /* Add the name */
849 silc_sftp_name_add(name, entry->name, long_name, attrs);
850 }
851
852 /* If we didn't read all then udpate the index for next read */
853 if (i >= h->entry->entry_count)
854 h->fd = -1;
855 else
856 h->fd = i;
857
858 /* If names was not found then return EOF. */
859 if (name->count == 0) {
860 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
861 silc_sftp_name_free(name);
862 return;
863 }
864
865 /* Return name(s) */
866 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
867 callback_context);
868
869 silc_sftp_name_free(name);
870 }
871
memfs_stat(void * context,SilcSFTP sftp,const char * path,SilcSFTPAttrCallback callback,void * callback_context)872 void memfs_stat(void *context, SilcSFTP sftp,
873 const char *path,
874 SilcSFTPAttrCallback callback,
875 void *callback_context)
876 {
877 MemFS fs = (MemFS)context;
878 MemFSEntry entry;
879 SilcSFTPAttributes attrs;
880 int ret;
881 struct stat stats;
882
883 if (!path || !strlen(path))
884 path = (const char *)DIR_SEPARATOR;
885
886 /* Find such directory */
887 entry = memfs_find_entry_path(fs->root, path);
888 if (!entry) {
889 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
890 return;
891 }
892
893 if (entry->directory || !entry->data) {
894 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
895 return;
896 }
897
898 /* Get real stat */
899 ret = stat(entry->data + 7, &stats);
900 if (ret == -1) {
901 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
902 return;
903 }
904
905 attrs = silc_calloc(1, sizeof(*attrs));
906 if (!attrs) {
907 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
908 return;
909 }
910 attrs->flags = (SILC_SFTP_ATTR_SIZE |
911 SILC_SFTP_ATTR_UIDGID |
912 SILC_SFTP_ATTR_ACMODTIME);
913 attrs->size = stats.st_size;
914 attrs->uid = 0; /* We use always 0 UID and GID */
915 attrs->gid = 0;
916 attrs->atime = stats.st_atime;
917 attrs->mtime = stats.st_mtime;
918
919 /* Return attributes */
920 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
921 callback_context);
922
923 silc_sftp_attr_free(attrs);
924 }
925
memfs_lstat(void * context,SilcSFTP sftp,const char * path,SilcSFTPAttrCallback callback,void * callback_context)926 void memfs_lstat(void *context, SilcSFTP sftp,
927 const char *path,
928 SilcSFTPAttrCallback callback,
929 void *callback_context)
930 {
931 MemFS fs = (MemFS)context;
932 MemFSEntry entry;
933 SilcSFTPAttributes attrs;
934 int ret;
935 struct stat stats;
936
937 if (!path || !strlen(path))
938 path = (const char *)DIR_SEPARATOR;
939
940 /* Find such directory */
941 entry = memfs_find_entry_path(fs->root, path);
942 if (!entry) {
943 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
944 return;
945 }
946
947 if (entry->directory || !entry->data) {
948 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
949 return;
950 }
951
952 /* Get real stat */
953 #ifdef SILC_WIN32
954 ret = stat(entry->data + 7, &stats);
955 #endif /* SILC_WIN32 */
956 #ifdef SILC_UNIX
957 ret = lstat(entry->data + 7, &stats);
958 #endif /* SILC_UNIX */
959 #ifdef SILC_SYMBIAN
960 ret = stat(entry->data + 7, &stats);
961 #endif /* SILC_SYMBIAN */
962 if (ret == -1) {
963 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
964 return;
965 }
966
967 attrs = silc_calloc(1, sizeof(*attrs));
968 if (!attrs) {
969 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
970 return;
971 }
972 attrs->flags = (SILC_SFTP_ATTR_SIZE |
973 SILC_SFTP_ATTR_UIDGID |
974 SILC_SFTP_ATTR_ACMODTIME);
975 attrs->size = stats.st_size;
976 attrs->uid = 0; /* We use always 0 UID and GID */
977 attrs->gid = 0;
978 attrs->atime = stats.st_atime;
979 attrs->mtime = stats.st_mtime;
980
981 /* Return attributes */
982 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
983 callback_context);
984
985 silc_sftp_attr_free(attrs);
986 }
987
memfs_fstat(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPAttrCallback callback,void * callback_context)988 void memfs_fstat(void *context, SilcSFTP sftp,
989 SilcSFTPHandle handle,
990 SilcSFTPAttrCallback callback,
991 void *callback_context)
992 {
993 MemFSFileHandle h = (MemFSFileHandle)handle;
994 SilcSFTPAttributes attrs;
995 int ret;
996 struct stat stats;
997
998 if (h->entry->directory || !h->entry->data) {
999 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1000 return;
1001 }
1002
1003 /* Get real stat */
1004 ret = fstat(h->fd, &stats);
1005 if (ret == -1) {
1006 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
1007 return;
1008 }
1009
1010 attrs = silc_calloc(1, sizeof(*attrs));
1011 if (!attrs) {
1012 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1013 return;
1014 }
1015 attrs->flags = (SILC_SFTP_ATTR_SIZE |
1016 SILC_SFTP_ATTR_UIDGID |
1017 SILC_SFTP_ATTR_ACMODTIME);
1018 attrs->size = stats.st_size;
1019 attrs->uid = 0; /* We use always 0 UID and GID */
1020 attrs->gid = 0;
1021 attrs->atime = stats.st_atime;
1022 attrs->mtime = stats.st_mtime;
1023
1024 /* Return attributes */
1025 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
1026 callback_context);
1027
1028 silc_sftp_attr_free(attrs);
1029 }
1030
memfs_setstat(void * context,SilcSFTP sftp,const char * path,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * callback_context)1031 void memfs_setstat(void *context, SilcSFTP sftp,
1032 const char *path,
1033 SilcSFTPAttributes attrs,
1034 SilcSFTPStatusCallback callback,
1035 void *callback_context)
1036 {
1037 /* Setstat is not supported */
1038 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1039 callback_context);
1040 }
1041
memfs_fsetstat(void * context,SilcSFTP sftp,SilcSFTPHandle handle,SilcSFTPAttributes attrs,SilcSFTPStatusCallback callback,void * callback_context)1042 void memfs_fsetstat(void *context, SilcSFTP sftp,
1043 SilcSFTPHandle handle,
1044 SilcSFTPAttributes attrs,
1045 SilcSFTPStatusCallback callback,
1046 void *callback_context)
1047 {
1048 /* Fsetstat is not supported */
1049 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1050 callback_context);
1051 }
1052
memfs_readlink(void * context,SilcSFTP sftp,const char * path,SilcSFTPNameCallback callback,void * callback_context)1053 void memfs_readlink(void *context, SilcSFTP sftp,
1054 const char *path,
1055 SilcSFTPNameCallback callback,
1056 void *callback_context)
1057 {
1058 /* Readlink is not supported */
1059 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
1060 callback_context);
1061 }
1062
memfs_symlink(void * context,SilcSFTP sftp,const char * linkpath,const char * targetpath,SilcSFTPStatusCallback callback,void * callback_context)1063 void memfs_symlink(void *context, SilcSFTP sftp,
1064 const char *linkpath,
1065 const char *targetpath,
1066 SilcSFTPStatusCallback callback,
1067 void *callback_context)
1068 {
1069 /* Symlink is not supported */
1070 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1071 callback_context);
1072 }
1073
memfs_realpath(void * context,SilcSFTP sftp,const char * path,SilcSFTPNameCallback callback,void * callback_context)1074 void memfs_realpath(void *context, SilcSFTP sftp,
1075 const char *path,
1076 SilcSFTPNameCallback callback,
1077 void *callback_context)
1078 {
1079 MemFS fs = (MemFS)context;
1080 char *realpath;
1081 SilcSFTPName name;
1082
1083 if (!path || !strlen(path))
1084 path = (const char *)DIR_SEPARATOR;
1085
1086 realpath = memfs_expand_path(fs->root, path);
1087 if (!realpath)
1088 goto fail;
1089
1090 name = silc_calloc(1, sizeof(*name));
1091 if (!name)
1092 goto fail;
1093
1094 name->filename = silc_calloc(1, sizeof(*name->filename));
1095 if (!name->filename)
1096 goto fail;
1097 name->filename[0] = realpath;
1098 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
1099 if (!name->long_filename)
1100 goto fail;
1101 name->long_filename[0] = realpath;
1102 name->attrs = silc_calloc(1, sizeof(*name->attrs));
1103 if (!name->attrs)
1104 goto fail;
1105 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1106 if (!name->attrs[0])
1107 goto fail;
1108 name->count = 1;
1109
1110 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
1111 callback_context);
1112
1113 silc_sftp_name_free(name);
1114 return;
1115
1116 fail:
1117 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1118 }
1119
memfs_extended(void * context,SilcSFTP sftp,const char * request,const unsigned char * data,SilcUInt32 data_len,SilcSFTPExtendedCallback callback,void * callback_context)1120 void memfs_extended(void *context, SilcSFTP sftp,
1121 const char *request,
1122 const unsigned char *data,
1123 SilcUInt32 data_len,
1124 SilcSFTPExtendedCallback callback,
1125 void *callback_context)
1126 {
1127 /* Extended is not supported */
1128 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1129 callback_context);
1130 }
1131
1132 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {
1133 memfs_get_handle,
1134 memfs_encode_handle,
1135 memfs_open,
1136 memfs_close,
1137 memfs_read,
1138 memfs_write,
1139 memfs_remove,
1140 memfs_rename,
1141 memfs_mkdir,
1142 memfs_rmdir,
1143 memfs_opendir,
1144 memfs_readdir,
1145 memfs_stat,
1146 memfs_lstat,
1147 memfs_fstat,
1148 memfs_setstat,
1149 memfs_fsetstat,
1150 memfs_readlink,
1151 memfs_symlink,
1152 memfs_realpath,
1153 memfs_extended
1154 };
1155