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)
733 if (!lstat(entry->data + 7, &stats))
734 filesize = stats.st_size;
736 /* Long name format is:
737 drwx------ 1 324210 Apr 8 08:40 mail/
738 1234567890 123 12345678 123456789012 */
739 snprintf(long_name, sizeof(long_name) - 1,
740 "%c%c%c%c------ %3d %8lu %12s %s%s",
741 (entry->directory ? 'd' : '-'),
742 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
743 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
744 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
745 (entry->directory ? (int)entry->entry_count : 1),
746 filesize, date, entry->name,
747 (entry->directory ? "/" :
748 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
751 attrs = silc_calloc(1, sizeof(*attrs));
752 attrs->flags = (SILC_SFTP_ATTR_SIZE |
753 SILC_SFTP_ATTR_UIDGID);
754 attrs->size = filesize;
755 attrs->uid = 0; /* We use always 0 UID and GID */
757 if (!entry->directory) {
758 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
759 attrs->atime = stats.st_atime;
760 attrs->mtime = stats.st_mtime;
764 silc_sftp_name_add(name, entry->name, long_name, attrs);
767 /* If we didn't read all then udpate the index for next read */
768 if (i >= h->entry->entry_count)
773 /* If names was not found then return EOF. */
774 if (name->count == 0) {
775 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
776 silc_sftp_name_free(name);
781 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
784 silc_sftp_name_free(name);
787 void mem_stat(void *context, SilcSFTP sftp,
789 SilcSFTPAttrCallback callback,
790 void *callback_context)
792 MemFS fs = (MemFS)context;
794 SilcSFTPAttributes attrs;
798 if (!path || !strlen(path))
799 path = (const char *)strdup("/");
801 /* Find such directory */
802 entry = mem_find_entry_path(fs->root, path);
804 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
808 if (entry->directory || !entry->data) {
809 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
814 ret = stat(entry->data + 7, &stats);
816 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
820 attrs = silc_calloc(1, sizeof(*attrs));
821 attrs->flags = (SILC_SFTP_ATTR_SIZE |
822 SILC_SFTP_ATTR_UIDGID |
823 SILC_SFTP_ATTR_ACMODTIME);
824 attrs->size = stats.st_size;
825 attrs->uid = 0; /* We use always 0 UID and GID */
827 attrs->atime = stats.st_atime;
828 attrs->mtime = stats.st_mtime;
830 /* Return attributes */
831 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
834 silc_sftp_attr_free(attrs);
837 void mem_lstat(void *context, SilcSFTP sftp,
839 SilcSFTPAttrCallback callback,
840 void *callback_context)
842 MemFS fs = (MemFS)context;
844 SilcSFTPAttributes attrs;
848 if (!path || !strlen(path))
849 path = (const char *)strdup("/");
851 /* Find such directory */
852 entry = mem_find_entry_path(fs->root, path);
854 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
858 if (entry->directory || !entry->data) {
859 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
864 ret = lstat(entry->data + 7, &stats);
866 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
870 attrs = silc_calloc(1, sizeof(*attrs));
871 attrs->flags = (SILC_SFTP_ATTR_SIZE |
872 SILC_SFTP_ATTR_UIDGID |
873 SILC_SFTP_ATTR_ACMODTIME);
874 attrs->size = stats.st_size;
875 attrs->uid = 0; /* We use always 0 UID and GID */
877 attrs->atime = stats.st_atime;
878 attrs->mtime = stats.st_mtime;
880 /* Return attributes */
881 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
884 silc_sftp_attr_free(attrs);
887 void mem_fstat(void *context, SilcSFTP sftp,
888 SilcSFTPHandle handle,
889 SilcSFTPAttrCallback callback,
890 void *callback_context)
892 MemFSFileHandle h = (MemFSFileHandle)handle;
893 SilcSFTPAttributes attrs;
897 if (h->entry->directory || !h->entry->data) {
898 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
903 ret = fstat(h->fd, &stats);
905 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
909 attrs = silc_calloc(1, sizeof(*attrs));
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 */
916 attrs->atime = stats.st_atime;
917 attrs->mtime = stats.st_mtime;
919 /* Return attributes */
920 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
923 silc_sftp_attr_free(attrs);
926 void mem_setstat(void *context, SilcSFTP sftp,
928 SilcSFTPAttributes attrs,
929 SilcSFTPStatusCallback callback,
930 void *callback_context)
932 /* Setstat is not supported */
933 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
937 void mem_fsetstat(void *context, SilcSFTP sftp,
938 SilcSFTPHandle handle,
939 SilcSFTPAttributes attrs,
940 SilcSFTPStatusCallback callback,
941 void *callback_context)
943 /* Fsetstat is not supported */
944 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
948 void mem_readlink(void *context, SilcSFTP sftp,
950 SilcSFTPNameCallback callback,
951 void *callback_context)
953 /* Readlink is not supported */
954 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
958 void mem_symlink(void *context, SilcSFTP sftp,
959 const char *linkpath,
960 const char *targetpath,
961 SilcSFTPStatusCallback callback,
962 void *callback_context)
964 /* Symlink is not supported */
965 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
969 void mem_realpath(void *context, SilcSFTP sftp,
971 SilcSFTPNameCallback callback,
972 void *callback_context)
974 MemFS fs = (MemFS)context;
978 if (!path || !strlen(path))
979 path = (const char *)strdup("/");
981 realpath = mem_expand_path(fs->root, path);
983 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
987 name = silc_calloc(1, sizeof(*name));
988 name->filename = silc_calloc(1, sizeof(*name->filename));
989 name->filename[0] = realpath;
990 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
991 name->long_filename[0] = realpath;
992 name->attrs = silc_calloc(1, sizeof(*name->attrs));
993 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
996 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name,
999 silc_sftp_name_free(name);
1002 void mem_extended(void *context, SilcSFTP sftp,
1003 const char *request,
1004 const unsigned char *data,
1006 SilcSFTPExtendedCallback callback,
1007 void *callback_context)
1009 /* Extended is not supported */
1010 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1014 struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {