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.
20 /* XXX TODO Win32 support */
22 #include "silcincludes.h"
24 #include "silcsftp_fs.h"
25 #include "sftp_util.h"
27 #define DIR_SEPARATOR "/"
29 struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory;
31 /* Memory filesystem entry */
32 typedef struct MemFSEntryStruct {
33 char *name; /* Name of the entry */
34 char *data; /* Data of the entry */
35 bool directory; /* TRUE if this is directory */
36 SilcSFTPFSMemoryPerm perm; /* Permissions */
37 struct MemFSEntryStruct **entry; /* Files and sub-directories */
38 uint32 entry_count; /* Number of files and sub-directories */
39 struct MemFSEntryStruct *parent; /* non-NULL if `directory' is TRUE,
40 includes parent directory. */
41 unsigned long created; /* Time of creation */
46 uint32 handle; /* Handle index */
47 int fd; /* Real file handle */
48 MemFSEntry entry; /* Filesystem entry */
51 /* Memory filesystem */
53 MemFSEntry root; /* Root of the filesystem hierarchy */
54 SilcSFTPFSMemoryPerm root_perm;
55 MemFSFileHandle *handles; /* Open file handles */
59 /* Generates absolute path from relative path that may include '.' and '..'
62 static char *mem_expand_path(MemFSEntry root, const char *path)
64 if (!strstr(path, "./") && !strstr(path, "../") &&
65 !strstr(path, "/..") && !strstr(path, "/."))
72 /* Add `entry' to directory `dir'. */
74 static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
79 /* Must be both write and exec permissions */
81 !((dir->perm & SILC_SFTP_FS_PERM_WRITE) &&
82 (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
86 dir->entry = silc_calloc(3, sizeof(*entry));
87 dir->entry[0] = entry;
89 entry->created = time(0);
93 for (i = 0; i < dir->entry_count; i++) {
97 dir->entry[i] = entry;
98 entry->created = time(0);
102 dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
103 (dir->entry_count + 3));
104 for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
105 dir->entry[i] = NULL;
106 dir->entry[dir->entry_count] = entry;
107 dir->entry_count += 3;
108 entry->created = time(0);
113 /* Removes entry `entry' and all entries under it recursively. */
115 static bool mem_del_entry(MemFSEntry entry, bool check_perm)
119 /* Directories cannot be removed from remote access */
123 silc_free(entry->name);
124 silc_free(entry->data);
126 /* Delete all entries recursively under this entry */
127 for (i = 0; i < entry->entry_count; i++) {
128 if (entry->entry[i]) {
129 if (!mem_del_entry(entry->entry[i], FALSE))
133 silc_free(entry->entry);
135 /* Remove from parent */
137 for (i = 0; i < entry->parent->entry_count; i++) {
138 if (entry->parent->entry[i] == entry) {
139 entry->parent->entry[i] = NULL;
150 /* Finds first occurence of entry named `name' under the directory `dir'.
151 This does not check subdirectories recursively. */
153 static MemFSEntry mem_find_entry(MemFSEntry dir, const char *name,
158 for (i = 0; i < dir->entry_count; i++) {
162 if (!strncmp(name, dir->entry[i]->name, name_len))
163 return dir->entry[i];
169 /* Finds the entry by the `path' which may include full path or
172 static MemFSEntry mem_find_entry_path(MemFSEntry dir, const char *p)
174 MemFSEntry entry = NULL;
178 cp = path = mem_expand_path(dir, p);
180 if (strlen(cp) == 1 && cp[0] == '/')
185 len = strcspn(cp, DIR_SEPARATOR);
187 entry = mem_find_entry(dir, cp, len);
196 len = strcspn(cp, DIR_SEPARATOR);
204 /* Deletes entry by the name `name' from the directory `dir'. This does
205 not check subdirectories recursively. */
207 static bool mem_del_entry_name(MemFSEntry dir, const char *name,
208 uint32 name_len, bool check_perm)
212 /* Files cannot be removed from remote access */
216 entry = mem_find_entry(dir, name, name_len);
219 return mem_del_entry(entry, check_perm);
224 /* Create new handle and add it to the list of open handles. */
226 static MemFSFileHandle mem_create_handle(MemFS fs, int fd, MemFSEntry entry)
228 MemFSFileHandle handle;
231 handle = silc_calloc(1, sizeof(*handle));
233 handle->entry = entry;
236 fs->handles = silc_calloc(5, sizeof(*fs->handles));
237 fs->handles[0] = handle;
238 fs->handles_count = 5;
245 for (i = 0; i < fs->handles_count; i++) {
249 fs->handles[i] = handle;
256 fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
257 (fs->handles_count + 5));
258 for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
259 fs->handles[i] = NULL;
260 fs->handles[fs->handles_count] = handle;
261 handle->handle = fs->handles_count;
262 fs->handles_count += 5;
267 /* Deletes the handle and remove it from the open handle list. */
269 static bool mem_del_handle(MemFS fs, MemFSFileHandle handle)
271 if (handle->handle > fs->handles_count)
274 if (!fs->handles[handle->handle])
277 if (fs->handles[handle->handle] == handle) {
278 fs->handles[handle->handle] = NULL;
279 if (handle->fd != -1)
288 /* Find handle by handle index. */
290 static MemFSFileHandle mem_find_handle(MemFS fs, uint32 handle)
292 if (handle > fs->handles_count)
295 if (!fs->handles[handle])
298 if (fs->handles[handle]->handle != handle)
301 return fs->handles[handle];
304 /* Allocates memory filesystem context and returns the context. The
305 context can be given as argument to the silc_sftp_server_start function.
306 The context must be freed by the caller using the function
307 silc_sftp_fs_memory_free. The `perm' is the permissions for the root
308 directory of the filesystem (/ dir). */
310 SilcSFTPFilesystem silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
312 SilcSFTPFilesystem filesystem;
315 fs = silc_calloc(1, sizeof(*fs));
316 fs->root = silc_calloc(1, sizeof(*fs->root));
317 fs->root->perm = perm;
318 fs->root_perm = perm;
319 fs->root->directory = TRUE;
320 fs->root->name = strdup(DIR_SEPARATOR);
322 filesystem = silc_calloc(1, sizeof(*filesystem));
323 filesystem->fs = &silc_sftp_fs_memory;
324 filesystem->fs_context = (void *)fs;
329 /* Frees the memory filesystem context. */
331 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
333 MemFS memfs = (MemFS)fs->fs_context;
335 silc_free(memfs->root);
339 /* Adds a new directory to the memory filesystem. Returns the directory
340 context that can be used to add for example files to the directory
341 or new subdirectories under the directory. The `dir' is the parent
342 directory of the directory to be added. If this directory is to be
343 added to the root directory the `dir' is NULL. The `name' is the name
344 of the directory. If error occurs this returns NULL. The caller must
345 not free the returned context. The `perm' will indicate the permissions
346 for the directory and they work in POSIX style. */
348 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
349 SilcSFTPFSMemoryPerm perm,
352 MemFS memfs = (MemFS)fs->fs_context;
355 entry = silc_calloc(1, sizeof(*entry));
357 entry->name = strdup(name);
358 entry->directory = TRUE;
359 entry->parent = dir ? dir : memfs->root;
361 if (!mem_add_entry(dir ? dir : memfs->root, entry, FALSE))
367 /* Deletes a directory indicated by the `dir'. All files and subdirectories
368 in this directory is also removed. If the `dir' is NULL then all
369 directories and files are removed from the filesystem. Returns TRUE
370 if the removing was success. This is the only way to remove directories
371 in memory file system. The filesystem does not allow removing directories
372 with remote access using the filesystem access function sftp_rmdir. */
374 bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
376 MemFS memfs = (MemFS)fs->fs_context;
380 return mem_del_entry(dir, FALSE);
382 /* Remove from root */
383 ret = mem_del_entry(memfs->root, FALSE);
385 memfs->root = silc_calloc(1, sizeof(*memfs->root));
386 memfs->root->perm = memfs->root_perm;
387 memfs->root->directory = TRUE;
388 memfs->root->name = strdup(DIR_SEPARATOR);
393 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
394 is NULL the file is added to the root directory. The `filename' is the
395 filename in the directory. The `realpath' is the real filepath in the
396 physical filesystem. It is used to actually access the file from the
397 memory filesystem. The `perm' will indicate the permissions for th e
398 file and they work in POSIX style. Returns TRUE if the file was
399 added to the directory. */
401 bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
402 SilcSFTPFSMemoryPerm perm,
403 const char *filename,
404 const char *realpath)
406 MemFS memfs = (MemFS)fs->fs_context;
409 entry = silc_calloc(1, sizeof(*entry));
411 entry->name = strdup(filename);
412 entry->data = strdup(realpath);
413 entry->directory = FALSE;
415 return mem_add_entry(dir ? dir : memfs->root, entry, FALSE);
418 /* Removes a file indicated by the `filename' from the directory
419 indicated by the `dir'. Returns TRUE if the removing was success. */
421 bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
422 const char *filename)
424 MemFS memfs = (MemFS)fs->fs_context;
429 return mem_del_entry_name(dir ? dir : memfs->root, filename,
430 strlen(filename), FALSE);
433 SilcSFTPHandle mem_get_handle(void *context, SilcSFTP sftp,
434 const unsigned char *data,
437 MemFS fs = (MemFS)context;
443 SILC_GET32_MSB(handle, data);
444 return (SilcSFTPHandle)mem_find_handle(fs, handle);
447 unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
448 SilcSFTPHandle handle,
452 MemFSFileHandle h = (MemFSFileHandle)handle;
454 data = silc_calloc(4, sizeof(*data));
455 SILC_PUT32_MSB(h->handle, data);
461 void mem_open(void *context, SilcSFTP sftp,
462 const char *filename,
463 SilcSFTPFileOperation pflags,
464 SilcSFTPAttributes attrs,
465 SilcSFTPHandleCallback callback,
466 void *callback_context)
468 MemFS fs = (MemFS)context;
470 MemFSFileHandle handle;
473 /* CREAT and TRUNC not supported */
474 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
475 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
480 entry = mem_find_entry_path(fs->root, filename);
482 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
486 if (entry->directory || !entry->data) {
487 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
491 /* Check for reading */
492 if ((pflags & SILC_SFTP_FXF_READ) &&
493 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
494 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
499 /* Check for writing */
500 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
501 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
502 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
507 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
509 else if (pflags & SILC_SFTP_FXF_READ)
511 else if (pflags & SILC_SFTP_FXF_WRITE)
513 if (pflags & SILC_SFTP_FXF_APPEND)
516 /* Attempt to open the file for real. */
517 fd = open(entry->data + 7, flags,
518 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
519 attrs->permissions : 0600));
521 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
525 /* File opened, return handle */
526 handle = mem_create_handle(fs, fd, entry);
527 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
531 void mem_close(void *context, SilcSFTP sftp,
532 SilcSFTPHandle handle,
533 SilcSFTPStatusCallback callback,
534 void *callback_context)
536 MemFS fs = (MemFS)context;
537 MemFSFileHandle h = (MemFSFileHandle)handle;
543 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
549 mem_del_handle(fs, h);
550 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
553 void mem_read(void *context, SilcSFTP sftp,
554 SilcSFTPHandle handle,
557 SilcSFTPDataCallback callback,
558 void *callback_context)
560 MemFSFileHandle h = (MemFSFileHandle)handle;
567 data = silc_malloc(len);
568 lseek(h->fd, (off_t)offset, SEEK_SET);
570 /* Attempt to read */
571 ret = read(h->fd, data, len);
574 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
576 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
582 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
583 ret, callback_context);
588 void mem_write(void *context, SilcSFTP sftp,
589 SilcSFTPHandle handle,
591 const unsigned char *data,
593 SilcSFTPStatusCallback callback,
594 void *callback_context)
596 MemFSFileHandle h = (MemFSFileHandle)handle;
599 lseek(h->fd, (off_t)offset, SEEK_SET);
601 /* Attempt to write */
602 ret = write(h->fd, data, data_len);
604 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
609 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
612 void mem_remove(void *context, SilcSFTP sftp,
613 const char *filename,
614 SilcSFTPStatusCallback callback,
615 void *callback_context)
617 /* Remove is not supported */
618 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
622 void mem_rename(void *context, SilcSFTP sftp,
625 SilcSFTPStatusCallback callback,
626 void *callback_context)
628 /* Rename is not supported */
629 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
633 void mem_mkdir(void *context, SilcSFTP sftp,
635 SilcSFTPAttributes attrs,
636 SilcSFTPStatusCallback callback,
637 void *callback_context)
639 /* Mkdir is not supported */
640 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
644 void mem_rmdir(void *context, SilcSFTP sftp,
646 SilcSFTPStatusCallback callback,
647 void *callback_context)
649 /* Rmdir is not supported */
650 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
654 void mem_opendir(void *context, SilcSFTP sftp,
656 SilcSFTPHandleCallback callback,
657 void *callback_context)
659 MemFS fs = (MemFS)context;
661 MemFSFileHandle handle;
663 if (!path || !strlen(path))
664 path = (const char *)strdup("/");
666 /* Find such directory */
667 entry = mem_find_entry_path(fs->root, path);
669 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
673 if (!entry->directory) {
674 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
678 /* Must be read permissions to open a directory */
679 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
680 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
685 /* Directory opened, return handle */
686 handle = mem_create_handle(fs, 0, entry);
687 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
691 void mem_readdir(void *context, SilcSFTP sftp,
692 SilcSFTPHandle handle,
693 SilcSFTPNameCallback callback,
694 void *callback_context)
696 MemFSFileHandle h = (MemFSFileHandle)handle;
699 SilcSFTPAttributes attrs;
702 unsigned long filesize = 0;
706 if (!h->entry->directory) {
707 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
712 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
716 name = silc_calloc(1, sizeof(*name));
717 for (i = h->fd; i < 100 + h->fd; i++) {
718 if (i >= h->entry->entry_count)
721 entry = h->entry->entry[i];
725 filesize = sizeof(*entry);
726 memset(long_name, 0, sizeof(long_name));
728 date = ctime(&entry->created);
729 if (strrchr(date, ':'))
730 *strrchr(date, ':') = '\0';
732 if (!entry->directory)
734 if (!lstat(entry->data + 7, &stats))
736 if (!stat(entry->data + 7, &stats))
\r
738 filesize = stats.st_size;
\r
740 /* Long name format is:
741 drwx------ 1 324210 Apr 8 08:40 mail/
742 1234567890 123 12345678 123456789012 */
743 snprintf(long_name, sizeof(long_name) - 1,
744 "%c%c%c%c------ %3d %8lu %12s %s%s",
745 (entry->directory ? 'd' : '-'),
746 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
747 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
748 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
749 (entry->directory ? (int)entry->entry_count : 1),
750 filesize, date, entry->name,
751 (entry->directory ? "/" :
752 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
755 attrs = silc_calloc(1, sizeof(*attrs));
756 attrs->flags = (SILC_SFTP_ATTR_SIZE |
757 SILC_SFTP_ATTR_UIDGID);
758 attrs->size = filesize;
759 attrs->uid = 0; /* We use always 0 UID and GID */
761 if (!entry->directory) {
762 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
763 attrs->atime = stats.st_atime;
764 attrs->mtime = stats.st_mtime;
768 silc_sftp_name_add(name, entry->name, long_name, attrs);
771 /* If we didn't read all then udpate the index for next read */
772 if (i >= h->entry->entry_count)
777 /* If names was not found then return EOF. */
778 if (name->count == 0) {
779 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
780 silc_sftp_name_free(name);
785 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
788 silc_sftp_name_free(name);
791 void mem_stat(void *context, SilcSFTP sftp,
793 SilcSFTPAttrCallback callback,
794 void *callback_context)
796 MemFS fs = (MemFS)context;
798 SilcSFTPAttributes attrs;
802 if (!path || !strlen(path))
803 path = (const char *)strdup("/");
805 /* Find such directory */
806 entry = mem_find_entry_path(fs->root, path);
808 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
812 if (entry->directory || !entry->data) {
813 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
818 ret = stat(entry->data + 7, &stats);
820 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
824 attrs = silc_calloc(1, sizeof(*attrs));
825 attrs->flags = (SILC_SFTP_ATTR_SIZE |
826 SILC_SFTP_ATTR_UIDGID |
827 SILC_SFTP_ATTR_ACMODTIME);
828 attrs->size = stats.st_size;
829 attrs->uid = 0; /* We use always 0 UID and GID */
831 attrs->atime = stats.st_atime;
832 attrs->mtime = stats.st_mtime;
834 /* Return attributes */
835 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
838 silc_sftp_attr_free(attrs);
841 void mem_lstat(void *context, SilcSFTP sftp,
843 SilcSFTPAttrCallback callback,
844 void *callback_context)
846 MemFS fs = (MemFS)context;
848 SilcSFTPAttributes attrs;
852 if (!path || !strlen(path))
853 path = (const char *)strdup("/");
855 /* Find such directory */
856 entry = mem_find_entry_path(fs->root, path);
858 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
862 if (entry->directory || !entry->data) {
863 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
869 ret = lstat(entry->data + 7, &stats);
871 ret = stat(entry->data + 7, &stats);
\r
874 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
878 attrs = silc_calloc(1, sizeof(*attrs));
879 attrs->flags = (SILC_SFTP_ATTR_SIZE |
880 SILC_SFTP_ATTR_UIDGID |
881 SILC_SFTP_ATTR_ACMODTIME);
882 attrs->size = stats.st_size;
883 attrs->uid = 0; /* We use always 0 UID and GID */
885 attrs->atime = stats.st_atime;
886 attrs->mtime = stats.st_mtime;
888 /* Return attributes */
889 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
892 silc_sftp_attr_free(attrs);
895 void mem_fstat(void *context, SilcSFTP sftp,
896 SilcSFTPHandle handle,
897 SilcSFTPAttrCallback callback,
898 void *callback_context)
900 MemFSFileHandle h = (MemFSFileHandle)handle;
901 SilcSFTPAttributes attrs;
905 if (h->entry->directory || !h->entry->data) {
906 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
911 ret = fstat(h->fd, &stats);
913 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
917 attrs = silc_calloc(1, sizeof(*attrs));
918 attrs->flags = (SILC_SFTP_ATTR_SIZE |
919 SILC_SFTP_ATTR_UIDGID |
920 SILC_SFTP_ATTR_ACMODTIME);
921 attrs->size = stats.st_size;
922 attrs->uid = 0; /* We use always 0 UID and GID */
924 attrs->atime = stats.st_atime;
925 attrs->mtime = stats.st_mtime;
927 /* Return attributes */
928 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
931 silc_sftp_attr_free(attrs);
934 void mem_setstat(void *context, SilcSFTP sftp,
936 SilcSFTPAttributes attrs,
937 SilcSFTPStatusCallback callback,
938 void *callback_context)
940 /* Setstat is not supported */
941 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
945 void mem_fsetstat(void *context, SilcSFTP sftp,
946 SilcSFTPHandle handle,
947 SilcSFTPAttributes attrs,
948 SilcSFTPStatusCallback callback,
949 void *callback_context)
951 /* Fsetstat is not supported */
952 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
956 void mem_readlink(void *context, SilcSFTP sftp,
958 SilcSFTPNameCallback callback,
959 void *callback_context)
961 /* Readlink is not supported */
962 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
966 void mem_symlink(void *context, SilcSFTP sftp,
967 const char *linkpath,
968 const char *targetpath,
969 SilcSFTPStatusCallback callback,
970 void *callback_context)
972 /* Symlink is not supported */
973 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
977 void mem_realpath(void *context, SilcSFTP sftp,
979 SilcSFTPNameCallback callback,
980 void *callback_context)
982 MemFS fs = (MemFS)context;
986 if (!path || !strlen(path))
987 path = (const char *)strdup("/");
989 realpath = mem_expand_path(fs->root, path);
991 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
995 name = silc_calloc(1, sizeof(*name));
996 name->filename = silc_calloc(1, sizeof(*name->filename));
997 name->filename[0] = realpath;
998 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
999 name->long_filename[0] = realpath;
1000 name->attrs = silc_calloc(1, sizeof(*name->attrs));
1001 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1004 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name,
1007 silc_sftp_name_free(name);
1010 void mem_extended(void *context, SilcSFTP sftp,
1011 const char *request,
1012 const unsigned char *data,
1014 SilcSFTPExtendedCallback callback,
1015 void *callback_context)
1017 /* Extended is not supported */
1018 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1022 struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {