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 const 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 SilcUInt32 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 SilcUInt32 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 */
56 SilcUInt32 handles_count;
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 SilcUInt32 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, SilcUInt32 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));
324 (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
325 filesystem->fs_context = (void *)fs;
330 /* Frees the memory filesystem context. */
332 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
334 MemFS memfs = (MemFS)fs->fs_context;
336 silc_free(memfs->root);
340 /* Adds a new directory to the memory filesystem. Returns the directory
341 context that can be used to add for example files to the directory
342 or new subdirectories under the directory. The `dir' is the parent
343 directory of the directory to be added. If this directory is to be
344 added to the root directory the `dir' is NULL. The `name' is the name
345 of the directory. If error occurs this returns NULL. The caller must
346 not free the returned context. The `perm' will indicate the permissions
347 for the directory and they work in POSIX style. */
349 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
350 SilcSFTPFSMemoryPerm perm,
353 MemFS memfs = (MemFS)fs->fs_context;
356 entry = silc_calloc(1, sizeof(*entry));
358 entry->name = strdup(name);
359 entry->directory = TRUE;
360 entry->parent = dir ? dir : memfs->root;
362 if (!mem_add_entry(dir ? dir : memfs->root, entry, FALSE))
368 /* Deletes a directory indicated by the `dir'. All files and subdirectories
369 in this directory is also removed. If the `dir' is NULL then all
370 directories and files are removed from the filesystem. Returns TRUE
371 if the removing was success. This is the only way to remove directories
372 in memory file system. The filesystem does not allow removing directories
373 with remote access using the filesystem access function sftp_rmdir. */
375 bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
377 MemFS memfs = (MemFS)fs->fs_context;
381 return mem_del_entry(dir, FALSE);
383 /* Remove from root */
384 ret = mem_del_entry(memfs->root, FALSE);
386 memfs->root = silc_calloc(1, sizeof(*memfs->root));
387 memfs->root->perm = memfs->root_perm;
388 memfs->root->directory = TRUE;
389 memfs->root->name = strdup(DIR_SEPARATOR);
394 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
395 is NULL the file is added to the root directory. The `filename' is the
396 filename in the directory. The `realpath' is the real filepath in the
397 physical filesystem. It is used to actually access the file from the
398 memory filesystem. The `perm' will indicate the permissions for th e
399 file and they work in POSIX style. Returns TRUE if the file was
400 added to the directory. */
402 bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
403 SilcSFTPFSMemoryPerm perm,
404 const char *filename,
405 const char *realpath)
407 MemFS memfs = (MemFS)fs->fs_context;
410 entry = silc_calloc(1, sizeof(*entry));
412 entry->name = strdup(filename);
413 entry->data = strdup(realpath);
414 entry->directory = FALSE;
416 return mem_add_entry(dir ? dir : memfs->root, entry, FALSE);
419 /* Removes a file indicated by the `filename' from the directory
420 indicated by the `dir'. Returns TRUE if the removing was success. */
422 bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
423 const char *filename)
425 MemFS memfs = (MemFS)fs->fs_context;
430 return mem_del_entry_name(dir ? dir : memfs->root, filename,
431 strlen(filename), FALSE);
434 SilcSFTPHandle mem_get_handle(void *context, SilcSFTP sftp,
435 const unsigned char *data,
438 MemFS fs = (MemFS)context;
444 SILC_GET32_MSB(handle, data);
445 return (SilcSFTPHandle)mem_find_handle(fs, handle);
448 unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
449 SilcSFTPHandle handle,
450 SilcUInt32 *handle_len)
453 MemFSFileHandle h = (MemFSFileHandle)handle;
455 data = silc_calloc(4, sizeof(*data));
456 SILC_PUT32_MSB(h->handle, data);
462 void mem_open(void *context, SilcSFTP sftp,
463 const char *filename,
464 SilcSFTPFileOperation pflags,
465 SilcSFTPAttributes attrs,
466 SilcSFTPHandleCallback callback,
467 void *callback_context)
469 MemFS fs = (MemFS)context;
471 MemFSFileHandle handle;
474 /* CREAT and TRUNC not supported */
475 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
476 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
481 entry = mem_find_entry_path(fs->root, filename);
483 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
487 if (entry->directory || !entry->data) {
488 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
492 /* Check for reading */
493 if ((pflags & SILC_SFTP_FXF_READ) &&
494 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
495 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
500 /* Check for writing */
501 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
502 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
503 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
508 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
510 else if (pflags & SILC_SFTP_FXF_READ)
512 else if (pflags & SILC_SFTP_FXF_WRITE)
514 if (pflags & SILC_SFTP_FXF_APPEND)
517 /* Attempt to open the file for real. */
518 fd = silc_file_open_mode(entry->data + 7, flags,
519 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
520 attrs->permissions : 0600));
522 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
526 /* File opened, return handle */
527 handle = mem_create_handle(fs, fd, entry);
528 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
532 void mem_close(void *context, SilcSFTP sftp,
533 SilcSFTPHandle handle,
534 SilcSFTPStatusCallback callback,
535 void *callback_context)
537 MemFS fs = (MemFS)context;
538 MemFSFileHandle h = (MemFSFileHandle)handle;
542 ret = silc_file_close(h->fd);
544 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
550 mem_del_handle(fs, h);
551 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
554 void mem_read(void *context, SilcSFTP sftp,
555 SilcSFTPHandle handle,
558 SilcSFTPDataCallback callback,
559 void *callback_context)
561 MemFSFileHandle h = (MemFSFileHandle)handle;
568 data = silc_malloc(len);
569 lseek(h->fd, (off_t)offset, SEEK_SET);
571 /* Attempt to read */
572 ret = silc_file_read(h->fd, data, len);
575 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
577 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
583 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
584 ret, callback_context);
589 void mem_write(void *context, SilcSFTP sftp,
590 SilcSFTPHandle handle,
592 const unsigned char *data,
594 SilcSFTPStatusCallback callback,
595 void *callback_context)
597 MemFSFileHandle h = (MemFSFileHandle)handle;
600 lseek(h->fd, (off_t)offset, SEEK_SET);
602 /* Attempt to write */
603 ret = silc_file_write(h->fd, data, data_len);
605 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
610 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
613 void mem_remove(void *context, SilcSFTP sftp,
614 const char *filename,
615 SilcSFTPStatusCallback callback,
616 void *callback_context)
618 /* Remove is not supported */
619 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
623 void mem_rename(void *context, SilcSFTP sftp,
626 SilcSFTPStatusCallback callback,
627 void *callback_context)
629 /* Rename is not supported */
630 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
634 void mem_mkdir(void *context, SilcSFTP sftp,
636 SilcSFTPAttributes attrs,
637 SilcSFTPStatusCallback callback,
638 void *callback_context)
640 /* Mkdir is not supported */
641 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
645 void mem_rmdir(void *context, SilcSFTP sftp,
647 SilcSFTPStatusCallback callback,
648 void *callback_context)
650 /* Rmdir is not supported */
651 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
655 void mem_opendir(void *context, SilcSFTP sftp,
657 SilcSFTPHandleCallback callback,
658 void *callback_context)
660 MemFS fs = (MemFS)context;
662 MemFSFileHandle handle;
664 if (!path || !strlen(path))
665 path = (const char *)DIR_SEPARATOR;
667 /* Find such directory */
668 entry = mem_find_entry_path(fs->root, path);
670 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
674 if (!entry->directory) {
675 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
679 /* Must be read permissions to open a directory */
680 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
681 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
686 /* Directory opened, return handle */
687 handle = mem_create_handle(fs, 0, entry);
688 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
692 void mem_readdir(void *context, SilcSFTP sftp,
693 SilcSFTPHandle handle,
694 SilcSFTPNameCallback callback,
695 void *callback_context)
697 MemFSFileHandle h = (MemFSFileHandle)handle;
700 SilcSFTPAttributes attrs;
703 SilcUInt64 filesize = 0;
707 if (!h->entry->directory) {
708 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
713 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
717 name = silc_calloc(1, sizeof(*name));
718 for (i = h->fd; i < 100 + h->fd; i++) {
719 if (i >= h->entry->entry_count)
722 entry = h->entry->entry[i];
726 filesize = sizeof(*entry);
727 memset(long_name, 0, sizeof(long_name));
729 date = ctime(&entry->created);
730 if (strrchr(date, ':'))
731 *strrchr(date, ':') = '\0';
733 if (!entry->directory)
734 filesize = silc_file_size(entry->data + 7);
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 %8llu %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 *)DIR_SEPARATOR;
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 *)DIR_SEPARATOR;
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);
865 ret = lstat(entry->data + 7, &stats);
867 ret = stat(entry->data + 7, &stats);
870 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
874 attrs = silc_calloc(1, sizeof(*attrs));
875 attrs->flags = (SILC_SFTP_ATTR_SIZE |
876 SILC_SFTP_ATTR_UIDGID |
877 SILC_SFTP_ATTR_ACMODTIME);
878 attrs->size = stats.st_size;
879 attrs->uid = 0; /* We use always 0 UID and GID */
881 attrs->atime = stats.st_atime;
882 attrs->mtime = stats.st_mtime;
884 /* Return attributes */
885 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
888 silc_sftp_attr_free(attrs);
891 void mem_fstat(void *context, SilcSFTP sftp,
892 SilcSFTPHandle handle,
893 SilcSFTPAttrCallback callback,
894 void *callback_context)
896 MemFSFileHandle h = (MemFSFileHandle)handle;
897 SilcSFTPAttributes attrs;
901 if (h->entry->directory || !h->entry->data) {
902 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
907 ret = fstat(h->fd, &stats);
909 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
913 attrs = silc_calloc(1, sizeof(*attrs));
914 attrs->flags = (SILC_SFTP_ATTR_SIZE |
915 SILC_SFTP_ATTR_UIDGID |
916 SILC_SFTP_ATTR_ACMODTIME);
917 attrs->size = stats.st_size;
918 attrs->uid = 0; /* We use always 0 UID and GID */
920 attrs->atime = stats.st_atime;
921 attrs->mtime = stats.st_mtime;
923 /* Return attributes */
924 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
927 silc_sftp_attr_free(attrs);
930 void mem_setstat(void *context, SilcSFTP sftp,
932 SilcSFTPAttributes attrs,
933 SilcSFTPStatusCallback callback,
934 void *callback_context)
936 /* Setstat is not supported */
937 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
941 void mem_fsetstat(void *context, SilcSFTP sftp,
942 SilcSFTPHandle handle,
943 SilcSFTPAttributes attrs,
944 SilcSFTPStatusCallback callback,
945 void *callback_context)
947 /* Fsetstat is not supported */
948 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
952 void mem_readlink(void *context, SilcSFTP sftp,
954 SilcSFTPNameCallback callback,
955 void *callback_context)
957 /* Readlink is not supported */
958 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
962 void mem_symlink(void *context, SilcSFTP sftp,
963 const char *linkpath,
964 const char *targetpath,
965 SilcSFTPStatusCallback callback,
966 void *callback_context)
968 /* Symlink is not supported */
969 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
973 void mem_realpath(void *context, SilcSFTP sftp,
975 SilcSFTPNameCallback callback,
976 void *callback_context)
978 MemFS fs = (MemFS)context;
982 if (!path || !strlen(path))
983 path = (const char *)DIR_SEPARATOR;
985 realpath = mem_expand_path(fs->root, path);
987 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
991 name = silc_calloc(1, sizeof(*name));
992 name->filename = silc_calloc(1, sizeof(*name->filename));
993 name->filename[0] = realpath;
994 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
995 name->long_filename[0] = realpath;
996 name->attrs = silc_calloc(1, sizeof(*name->attrs));
997 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1000 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name,
1003 silc_sftp_name_free(name);
1006 void mem_extended(void *context, SilcSFTP sftp,
1007 const char *request,
1008 const unsigned char *data,
1009 SilcUInt32 data_len,
1010 SilcSFTPExtendedCallback callback,
1011 void *callback_context)
1013 /* Extended is not supported */
1014 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1018 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {