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.
19 /* XXX TODO Win32 support */
21 #include "silcincludes.h"
23 #include "silcsftp_fs.h"
24 #include "sftp_util.h"
26 #define DIR_SEPARATOR "/"
28 /* Memory filesystem entry */
29 typedef struct MemFSEntryStruct {
30 char *name; /* Name of the entry */
31 char *data; /* Data of the entry */
32 bool directory; /* TRUE if this is directory */
33 SilcSFTPFSMemoryPerm perm; /* Permissions */
34 struct MemFSEntryStruct **entry; /* Files and sub-directories */
35 uint32 entry_count; /* Number of files and sub-directories */
36 struct MemFSEntryStruct *parent; /* non-NULL if `directory' is TRUE,
37 includes parent directory. */
38 unsigned long created; /* Time of creation */
43 uint32 handle; /* Handle index */
44 int fd; /* Real file handle */
45 MemFSEntry entry; /* Filesystem entry */
48 /* Memory filesystem */
50 MemFSEntry root; /* Root of the filesystem hierarchy */
51 SilcSFTPFSMemoryPerm root_perm;
52 MemFSFileHandle *handles; /* Open file handles */
56 /* Generates absolute path from relative path that may include '.' and '..'
59 static char *mem_expand_path(MemFSEntry root, const char *path)
61 if (!strstr(path, "./") && !strstr(path, "../") &&
62 !strstr(path, "/..") && !strstr(path, "/."))
69 /* Add `entry' to directory `dir'. */
71 static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
76 /* Must be both write and exec permissions */
78 !((dir->perm & SILC_SFTP_FS_PERM_WRITE) &&
79 (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
83 dir->entry = silc_calloc(3, sizeof(*entry));
84 dir->entry[0] = entry;
86 entry->created = time(0);
90 for (i = 0; i < dir->entry_count; i++) {
94 dir->entry[i] = entry;
95 entry->created = time(0);
99 dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
100 (dir->entry_count + 3));
101 for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
102 dir->entry[i] = NULL;
103 dir->entry[dir->entry_count] = entry;
104 dir->entry_count += 3;
105 entry->created = time(0);
110 /* Removes entry `entry' and all entries under it recursively. */
112 static bool mem_del_entry(MemFSEntry entry, bool check_perm)
116 /* Directories cannot be removed from remote access */
120 silc_free(entry->name);
121 silc_free(entry->data);
123 /* Delete all entries recursively under this entry */
124 for (i = 0; i < entry->entry_count; i++) {
125 if (entry->entry[i]) {
126 if (!mem_del_entry(entry->entry[i], FALSE))
130 silc_free(entry->entry);
132 /* Remove from parent */
134 for (i = 0; i < entry->parent->entry_count; i++) {
135 if (entry->parent->entry[i] == entry) {
136 entry->parent->entry[i] = NULL;
147 /* Finds first occurence of entry named `name' under the directory `dir'.
148 This does not check subdirectories recursively. */
150 static MemFSEntry mem_find_entry(MemFSEntry dir, const char *name,
155 for (i = 0; i < dir->entry_count; i++) {
159 if (!strncmp(name, dir->entry[i]->name, name_len))
160 return dir->entry[i];
166 /* Finds the entry by the `path' which may include full path or
169 static MemFSEntry mem_find_entry_path(MemFSEntry dir, const char *p)
171 MemFSEntry entry = NULL;
175 cp = path = mem_expand_path(dir, p);
177 if (strlen(cp) == 1 && cp[0] == '/')
182 len = strcspn(cp, DIR_SEPARATOR);
184 entry = mem_find_entry(dir, cp, len);
193 len = strcspn(cp, DIR_SEPARATOR);
201 /* Deletes entry by the name `name' from the directory `dir'. This does
202 not check subdirectories recursively. */
204 static bool mem_del_entry_name(MemFSEntry dir, const char *name,
205 uint32 name_len, bool check_perm)
209 /* Files cannot be removed from remote access */
213 entry = mem_find_entry(dir, name, name_len);
216 return mem_del_entry(entry, check_perm);
221 /* Create new handle and add it to the list of open handles. */
223 static MemFSFileHandle mem_create_handle(MemFS fs, int fd, MemFSEntry entry)
225 MemFSFileHandle handle;
228 handle = silc_calloc(1, sizeof(*handle));
230 handle->entry = entry;
233 fs->handles = silc_calloc(5, sizeof(*fs->handles));
234 fs->handles[0] = handle;
235 fs->handles_count = 5;
242 for (i = 0; i < fs->handles_count; i++) {
246 fs->handles[i] = handle;
253 fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
254 (fs->handles_count + 5));
255 for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
256 fs->handles[i] = NULL;
257 fs->handles[fs->handles_count] = handle;
258 handle->handle = fs->handles_count;
259 fs->handles_count += 5;
264 /* Deletes the handle and remove it from the open handle list. */
266 static bool mem_del_handle(MemFS fs, MemFSFileHandle handle)
268 if (handle->handle > fs->handles_count)
271 if (!fs->handles[handle->handle])
274 if (fs->handles[handle->handle] == handle) {
275 fs->handles[handle->handle] = NULL;
276 if (handle->fd != -1)
285 /* Find handle by handle index. */
287 static MemFSFileHandle mem_find_handle(MemFS fs, uint32 handle)
289 if (handle > fs->handles_count)
292 if (!fs->handles[handle])
295 if (fs->handles[handle]->handle != handle)
298 return fs->handles[handle];
301 /* Allocates memory filesystem context and returns the context. The
302 context can be given as argument to the silc_sftp_server_start function.
303 The context must be freed by the caller using the function
304 silc_sftp_fs_memory_free. The `perm' is the permissions for the root
305 directory of the filesystem (/ dir). */
307 void *silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
311 fs = silc_calloc(1, sizeof(*fs));
312 fs->root = silc_calloc(1, sizeof(*fs->root));
313 fs->root->perm = perm;
314 fs->root_perm = perm;
315 fs->root->directory = TRUE;
316 fs->root->name = strdup(DIR_SEPARATOR);
321 /* Frees the memory filesystem context. */
323 void silc_sftp_fs_memory_free(void *context)
325 MemFS fs = (MemFS)context;
331 /* Adds a new directory to the memory filesystem. Returns the directory
332 context that can be used to add for example files to the directory
333 or new subdirectories under the directory. The `dir' is the parent
334 directory of the directory to be added. If this directory is to be
335 added to the root directory the `dir' is NULL. The `name' is the name
336 of the directory. If error occurs this returns NULL. The caller must
337 not free the returned context. The `perm' will indicate the permissions
338 for the directory and they work in POSIX style. */
340 void *silc_sftp_fs_memory_add_dir(void *context, void *dir,
341 SilcSFTPFSMemoryPerm perm,
344 MemFS fs = (MemFS)context;
347 entry = silc_calloc(1, sizeof(*entry));
349 entry->name = strdup(name);
350 entry->directory = TRUE;
351 entry->parent = dir ? dir : fs->root;
353 if (!mem_add_entry(dir ? dir : fs->root, entry, FALSE))
359 /* Deletes a directory indicated by the `dir'. All files and subdirectories
360 in this directory is also removed. If the `dir' is NULL then all
361 directories and files are removed from the filesystem. Returns TRUE
362 if the removing was success. This is the only way to remove directories
363 in memory file system. The filesystem does not allow removing directories
364 with remote access using the filesystem access function sftp_rmdir. */
366 bool silc_sftp_fs_memory_del_dir(void *context, void *dir)
368 MemFS fs = (MemFS)context;
372 return mem_del_entry(dir, FALSE);
374 /* Remove from root */
375 ret = mem_del_entry(fs->root, FALSE);
377 fs->root = silc_calloc(1, sizeof(*fs->root));
378 fs->root->perm = fs->root_perm;
379 fs->root->directory = TRUE;
380 fs->root->name = strdup(DIR_SEPARATOR);
385 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
386 is NULL the file is added to the root directory. The `filename' is the
387 filename in the directory. The `realpath' is the real filepath in the
388 physical filesystem. It is used to actually access the file from the
389 memory filesystem. The `perm' will indicate the permissions for th e
390 file and they work in POSIX style. Returns TRUE if the file was
391 added to the directory. */
393 bool silc_sftp_fs_memory_add_file(void *context,
395 SilcSFTPFSMemoryPerm perm,
396 const char *filename,
397 const char *realpath)
399 MemFS fs = (MemFS)context;
402 entry = silc_calloc(1, sizeof(*entry));
404 entry->name = strdup(filename);
405 entry->data = strdup(realpath);
406 entry->directory = FALSE;
408 return mem_add_entry(dir ? dir : fs->root, entry, FALSE);
411 /* Removes a file indicated by the `filename' from the directory
412 indicated by the `dir'. Returns TRUE if the removing was success. */
414 bool silc_sftp_fs_memory_del_file(void *context, void *dir,
415 const char *filename)
417 MemFS fs = (MemFS)context;
422 return mem_del_entry_name(dir ? dir : fs->root, filename,
423 strlen(filename), FALSE);
426 SilcSFTPHandle mem_get_handle(void *context, SilcSFTP sftp,
427 const unsigned char *data,
430 MemFS fs = (MemFS)context;
436 SILC_GET32_MSB(handle, data);
437 return (SilcSFTPHandle)mem_find_handle(fs, handle);
440 unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
441 SilcSFTPHandle handle,
445 MemFSFileHandle h = (MemFSFileHandle)handle;
447 data = silc_calloc(4, sizeof(*data));
448 SILC_PUT32_MSB(h->handle, data);
454 void mem_open(void *context, SilcSFTP sftp,
455 const char *filename,
456 SilcSFTPFileOperation pflags,
457 SilcSFTPAttributes attrs,
458 SilcSFTPHandleCallback callback,
459 void *callback_context)
461 MemFS fs = (MemFS)context;
463 MemFSFileHandle handle;
466 /* CREAT and TRUNC not supported */
467 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
468 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
473 entry = mem_find_entry_path(fs->root, filename);
475 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
479 if (entry->directory || !entry->data) {
480 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
484 /* Check for reading */
485 if ((pflags & SILC_SFTP_FXF_READ) &&
486 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
487 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
492 /* Check for writing */
493 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
494 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
495 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
500 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
502 else if (pflags & SILC_SFTP_FXF_READ)
504 else if (pflags & SILC_SFTP_FXF_WRITE)
506 if (pflags & SILC_SFTP_FXF_APPEND)
509 /* Attempt to open the file for real. */
510 fd = open(entry->data + 7, flags,
511 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
512 attrs->permissions : 0600));
514 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
518 /* File opened, return handle */
519 handle = mem_create_handle(fs, fd, entry);
520 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
524 void mem_close(void *context, SilcSFTP sftp,
525 SilcSFTPHandle handle,
526 SilcSFTPStatusCallback callback,
527 void *callback_context)
529 MemFS fs = (MemFS)context;
530 MemFSFileHandle h = (MemFSFileHandle)handle;
536 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
542 mem_del_handle(fs, h);
543 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
546 void mem_read(void *context, SilcSFTP sftp,
547 SilcSFTPHandle handle,
550 SilcSFTPDataCallback callback,
551 void *callback_context)
553 MemFSFileHandle h = (MemFSFileHandle)handle;
560 data = silc_malloc(len);
561 lseek(h->fd, (off_t)offset, SEEK_SET);
563 /* Attempt to read */
564 ret = read(h->fd, data, len);
567 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
569 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
575 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
576 ret, callback_context);
581 void mem_write(void *context, SilcSFTP sftp,
582 SilcSFTPHandle handle,
584 const unsigned char *data,
586 SilcSFTPStatusCallback callback,
587 void *callback_context)
589 MemFSFileHandle h = (MemFSFileHandle)handle;
592 lseek(h->fd, (off_t)offset, SEEK_SET);
594 /* Attempt to write */
595 ret = write(h->fd, data, data_len);
597 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
602 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
605 void mem_remove(void *context, SilcSFTP sftp,
606 const char *filename,
607 SilcSFTPStatusCallback callback,
608 void *callback_context)
610 /* Remove is not supported */
611 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
615 void mem_rename(void *context, SilcSFTP sftp,
618 SilcSFTPStatusCallback callback,
619 void *callback_context)
621 /* Rename is not supported */
622 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
626 void mem_mkdir(void *context, SilcSFTP sftp,
628 SilcSFTPAttributes attrs,
629 SilcSFTPStatusCallback callback,
630 void *callback_context)
632 /* Mkdir is not supported */
633 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
637 void mem_rmdir(void *context, SilcSFTP sftp,
639 SilcSFTPStatusCallback callback,
640 void *callback_context)
642 /* Rmdir is not supported */
643 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
647 void mem_opendir(void *context, SilcSFTP sftp,
649 SilcSFTPHandleCallback callback,
650 void *callback_context)
652 MemFS fs = (MemFS)context;
654 MemFSFileHandle handle;
656 if (!path || !strlen(path))
657 path = (const char *)strdup("/");
659 /* Find such directory */
660 entry = mem_find_entry_path(fs->root, path);
662 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
666 if (!entry->directory) {
667 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
671 /* Must be read permissions to open a directory */
672 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
673 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
678 /* Directory opened, return handle */
679 handle = mem_create_handle(fs, 0, entry);
680 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
684 void mem_readdir(void *context, SilcSFTP sftp,
685 SilcSFTPHandle handle,
686 SilcSFTPNameCallback callback,
687 void *callback_context)
689 MemFSFileHandle h = (MemFSFileHandle)handle;
692 SilcSFTPAttributes attrs;
695 unsigned long filesize = 0;
699 if (!h->entry->directory) {
700 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
705 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
709 name = silc_calloc(1, sizeof(*name));
710 for (i = h->fd; i < 100 + h->fd; i++) {
711 if (i >= h->entry->entry_count)
714 entry = h->entry->entry[i];
718 filesize = sizeof(*entry);
719 memset(long_name, 0, sizeof(long_name));
721 date = ctime(&entry->created);
722 if (strrchr(date, ':'))
723 *strrchr(date, ':') = '\0';
725 if (!entry->directory)
726 if (!lstat(entry->data + 7, &stats))
727 filesize = stats.st_size;
729 /* Long name format is:
730 drwx------ 1 324210 Apr 8 08:40 mail/
731 1234567890 123 12345678 123456789012 */
732 snprintf(long_name, sizeof(long_name),
733 "%c%c%c%c------ %3d %8lu %12s %s%s",
734 (entry->directory ? 'd' : '-'),
735 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
736 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
737 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
738 (entry->directory ? (int)entry->entry_count : 1),
739 filesize, date, entry->name,
740 (entry->directory ? "/" :
741 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
744 attrs = silc_calloc(1, sizeof(*attrs));
745 attrs->flags = (SILC_SFTP_ATTR_SIZE |
746 SILC_SFTP_ATTR_UIDGID);
747 attrs->size = filesize;
748 attrs->uid = 0; /* We use always 0 UID and GID */
750 if (!entry->directory) {
751 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
752 attrs->atime = stats.st_atime;
753 attrs->mtime = stats.st_mtime;
757 silc_sftp_name_add(name, entry->name, long_name, attrs);
760 /* If we didn't read all then udpate the index for next read */
761 if (i >= h->entry->entry_count)
766 /* If names was not found then return EOF. */
767 if (name->count == 0) {
768 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
769 silc_sftp_name_free(name);
774 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
777 silc_sftp_name_free(name);
780 void mem_stat(void *context, SilcSFTP sftp,
782 SilcSFTPAttrCallback callback,
783 void *callback_context)
785 MemFS fs = (MemFS)context;
787 SilcSFTPAttributes attrs;
791 if (!path || !strlen(path))
792 path = (const char *)strdup("/");
794 /* Find such directory */
795 entry = mem_find_entry_path(fs->root, path);
797 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
801 if (entry->directory || !entry->data) {
802 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
807 ret = stat(entry->data + 7, &stats);
809 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
813 attrs = silc_calloc(1, sizeof(*attrs));
814 attrs->flags = (SILC_SFTP_ATTR_SIZE |
815 SILC_SFTP_ATTR_UIDGID |
816 SILC_SFTP_ATTR_ACMODTIME);
817 attrs->size = stats.st_size;
818 attrs->uid = 0; /* We use always 0 UID and GID */
820 attrs->atime = stats.st_atime;
821 attrs->mtime = stats.st_mtime;
823 /* Return attributes */
824 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
827 silc_sftp_attr_free(attrs);
830 void mem_lstat(void *context, SilcSFTP sftp,
832 SilcSFTPAttrCallback callback,
833 void *callback_context)
835 MemFS fs = (MemFS)context;
837 SilcSFTPAttributes attrs;
841 if (!path || !strlen(path))
842 path = (const char *)strdup("/");
844 /* Find such directory */
845 entry = mem_find_entry_path(fs->root, path);
847 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
851 if (entry->directory || !entry->data) {
852 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
857 ret = lstat(entry->data + 7, &stats);
859 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
863 attrs = silc_calloc(1, sizeof(*attrs));
864 attrs->flags = (SILC_SFTP_ATTR_SIZE |
865 SILC_SFTP_ATTR_UIDGID |
866 SILC_SFTP_ATTR_ACMODTIME);
867 attrs->size = stats.st_size;
868 attrs->uid = 0; /* We use always 0 UID and GID */
870 attrs->atime = stats.st_atime;
871 attrs->mtime = stats.st_mtime;
873 /* Return attributes */
874 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
877 silc_sftp_attr_free(attrs);
880 void mem_fstat(void *context, SilcSFTP sftp,
881 SilcSFTPHandle handle,
882 SilcSFTPAttrCallback callback,
883 void *callback_context)
885 MemFSFileHandle h = (MemFSFileHandle)handle;
886 SilcSFTPAttributes attrs;
890 if (h->entry->directory || !h->entry->data) {
891 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
896 ret = fstat(h->fd, &stats);
898 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
902 attrs = silc_calloc(1, sizeof(*attrs));
903 attrs->flags = (SILC_SFTP_ATTR_SIZE |
904 SILC_SFTP_ATTR_UIDGID |
905 SILC_SFTP_ATTR_ACMODTIME);
906 attrs->size = stats.st_size;
907 attrs->uid = 0; /* We use always 0 UID and GID */
909 attrs->atime = stats.st_atime;
910 attrs->mtime = stats.st_mtime;
912 /* Return attributes */
913 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
916 silc_sftp_attr_free(attrs);
919 void mem_setstat(void *context, SilcSFTP sftp,
921 SilcSFTPAttributes attrs,
922 SilcSFTPStatusCallback callback,
923 void *callback_context)
925 /* Setstat is not supported */
926 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
930 void mem_fsetstat(void *context, SilcSFTP sftp,
931 SilcSFTPHandle handle,
932 SilcSFTPAttributes attrs,
933 SilcSFTPStatusCallback callback,
934 void *callback_context)
936 /* Fsetstat is not supported */
937 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
941 void mem_readlink(void *context, SilcSFTP sftp,
943 SilcSFTPNameCallback callback,
944 void *callback_context)
946 /* Readlink is not supported */
947 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
951 void mem_symlink(void *context, SilcSFTP sftp,
952 const char *linkpath,
953 const char *targetpath,
954 SilcSFTPStatusCallback callback,
955 void *callback_context)
957 /* Symlink is not supported */
958 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
962 void mem_realpath(void *context, SilcSFTP sftp,
964 SilcSFTPNameCallback callback,
965 void *callback_context)
967 MemFS fs = (MemFS)context;
971 if (!path || !strlen(path))
972 path = (const char *)strdup("/");
974 realpath = mem_expand_path(fs->root, path);
976 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
980 name = silc_calloc(1, sizeof(*name));
981 name->filename = silc_calloc(1, sizeof(*name->filename));
982 name->filename[0] = realpath;
983 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
984 name->long_filename[0] = realpath;
985 name->attrs = silc_calloc(1, sizeof(*name->attrs));
986 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
989 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name,
992 silc_sftp_name_free(name);
995 void mem_extended(void *context, SilcSFTP sftp,
997 const unsigned char *data,
999 SilcSFTPExtendedCallback callback,
1000 void *callback_context)
1002 /* Extended is not supported */
1003 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1007 struct SilcSFTPFilesystemStruct silc_sftp_fs_memory = {