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)
280 silc_file_close(handle->fd);
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 = silc_file_open_mode(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;
541 ret = silc_file_close(h->fd);
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 = silc_file_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 = silc_file_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 *)DIR_SEPARATOR;
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;
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 filesize = silc_file_size(entry->data + 7);
735 /* Long name format is:
736 drwx------ 1 324210 Apr 8 08:40 mail/
737 1234567890 123 12345678 123456789012 */
738 snprintf(long_name, sizeof(long_name) - 1,
739 "%c%c%c%c------ %3d %8llu %12s %s%s",
740 (entry->directory ? 'd' : '-'),
741 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
742 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
743 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
744 (entry->directory ? (int)entry->entry_count : 1),
745 filesize, date, entry->name,
746 (entry->directory ? "/" :
747 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
750 attrs = silc_calloc(1, sizeof(*attrs));
751 attrs->flags = (SILC_SFTP_ATTR_SIZE |
752 SILC_SFTP_ATTR_UIDGID);
753 attrs->size = filesize;
754 attrs->uid = 0; /* We use always 0 UID and GID */
756 if (!entry->directory) {
757 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
758 attrs->atime = stats.st_atime;
759 attrs->mtime = stats.st_mtime;
763 silc_sftp_name_add(name, entry->name, long_name, attrs);
766 /* If we didn't read all then udpate the index for next read */
767 if (i >= h->entry->entry_count)
772 /* If names was not found then return EOF. */
773 if (name->count == 0) {
774 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
775 silc_sftp_name_free(name);
780 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
783 silc_sftp_name_free(name);
786 void mem_stat(void *context, SilcSFTP sftp,
788 SilcSFTPAttrCallback callback,
789 void *callback_context)
791 MemFS fs = (MemFS)context;
793 SilcSFTPAttributes attrs;
797 if (!path || !strlen(path))
798 path = (const char *)DIR_SEPARATOR;
800 /* Find such directory */
801 entry = mem_find_entry_path(fs->root, path);
803 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
807 if (entry->directory || !entry->data) {
808 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
813 ret = stat(entry->data + 7, &stats);
815 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
819 attrs = silc_calloc(1, sizeof(*attrs));
820 attrs->flags = (SILC_SFTP_ATTR_SIZE |
821 SILC_SFTP_ATTR_UIDGID |
822 SILC_SFTP_ATTR_ACMODTIME);
823 attrs->size = stats.st_size;
824 attrs->uid = 0; /* We use always 0 UID and GID */
826 attrs->atime = stats.st_atime;
827 attrs->mtime = stats.st_mtime;
829 /* Return attributes */
830 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
833 silc_sftp_attr_free(attrs);
836 void mem_lstat(void *context, SilcSFTP sftp,
838 SilcSFTPAttrCallback callback,
839 void *callback_context)
841 MemFS fs = (MemFS)context;
843 SilcSFTPAttributes attrs;
847 if (!path || !strlen(path))
848 path = (const char *)DIR_SEPARATOR;
850 /* Find such directory */
851 entry = mem_find_entry_path(fs->root, path);
853 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
857 if (entry->directory || !entry->data) {
858 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
864 ret = lstat(entry->data + 7, &stats);
866 ret = stat(entry->data + 7, &stats);
869 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
873 attrs = silc_calloc(1, sizeof(*attrs));
874 attrs->flags = (SILC_SFTP_ATTR_SIZE |
875 SILC_SFTP_ATTR_UIDGID |
876 SILC_SFTP_ATTR_ACMODTIME);
877 attrs->size = stats.st_size;
878 attrs->uid = 0; /* We use always 0 UID and GID */
880 attrs->atime = stats.st_atime;
881 attrs->mtime = stats.st_mtime;
883 /* Return attributes */
884 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
887 silc_sftp_attr_free(attrs);
890 void mem_fstat(void *context, SilcSFTP sftp,
891 SilcSFTPHandle handle,
892 SilcSFTPAttrCallback callback,
893 void *callback_context)
895 MemFSFileHandle h = (MemFSFileHandle)handle;
896 SilcSFTPAttributes attrs;
900 if (h->entry->directory || !h->entry->data) {
901 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
906 ret = fstat(h->fd, &stats);
908 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
912 attrs = silc_calloc(1, sizeof(*attrs));
913 attrs->flags = (SILC_SFTP_ATTR_SIZE |
914 SILC_SFTP_ATTR_UIDGID |
915 SILC_SFTP_ATTR_ACMODTIME);
916 attrs->size = stats.st_size;
917 attrs->uid = 0; /* We use always 0 UID and GID */
919 attrs->atime = stats.st_atime;
920 attrs->mtime = stats.st_mtime;
922 /* Return attributes */
923 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
926 silc_sftp_attr_free(attrs);
929 void mem_setstat(void *context, SilcSFTP sftp,
931 SilcSFTPAttributes attrs,
932 SilcSFTPStatusCallback callback,
933 void *callback_context)
935 /* Setstat is not supported */
936 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
940 void mem_fsetstat(void *context, SilcSFTP sftp,
941 SilcSFTPHandle handle,
942 SilcSFTPAttributes attrs,
943 SilcSFTPStatusCallback callback,
944 void *callback_context)
946 /* Fsetstat is not supported */
947 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
951 void mem_readlink(void *context, SilcSFTP sftp,
953 SilcSFTPNameCallback callback,
954 void *callback_context)
956 /* Readlink is not supported */
957 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
961 void mem_symlink(void *context, SilcSFTP sftp,
962 const char *linkpath,
963 const char *targetpath,
964 SilcSFTPStatusCallback callback,
965 void *callback_context)
967 /* Symlink is not supported */
968 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
972 void mem_realpath(void *context, SilcSFTP sftp,
974 SilcSFTPNameCallback callback,
975 void *callback_context)
977 MemFS fs = (MemFS)context;
981 if (!path || !strlen(path))
982 path = (const char *)DIR_SEPARATOR;
984 realpath = mem_expand_path(fs->root, path);
986 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
990 name = silc_calloc(1, sizeof(*name));
991 name->filename = silc_calloc(1, sizeof(*name->filename));
992 name->filename[0] = realpath;
993 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
994 name->long_filename[0] = realpath;
995 name->attrs = silc_calloc(1, sizeof(*name->attrs));
996 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
999 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name,
1002 silc_sftp_name_free(name);
1005 void mem_extended(void *context, SilcSFTP sftp,
1006 const char *request,
1007 const unsigned char *data,
1009 SilcSFTPExtendedCallback callback,
1010 void *callback_context)
1012 /* Extended is not supported */
1013 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1017 struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {