5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2008 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 */
24 #include "silcsftp_fs.h"
25 #include "sftp_util.h"
27 #define DIR_SEPARATOR "/"
29 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory;
31 typedef struct MemFSEntryStruct {
32 struct MemFSEntryStruct **entry; /* Files and sub-directories */
33 SilcUInt32 entry_count; /* Number of files and sub-directories */
34 struct MemFSEntryStruct *parent; /* non-NULL if `directory' is TRUE,
35 includes parent directory. */
36 SilcUInt32 created; /* Time of creation */
37 char *name; /* Name of the entry */
38 char *data; /* Data of the entry */
39 unsigned int directory : 1; /* Set if this is directory */
40 unsigned int perm : 7; /* Permissions */
45 SilcUInt32 handle; /* Handle index */
46 int fd; /* Real file handle */
47 MemFSEntry entry; /* Filesystem entry */
50 /* Memory filesystem */
52 MemFSEntry root; /* Root of the filesystem hierarchy */
53 SilcSFTPFSMemoryPerm root_perm;
54 MemFSFileHandle *handles; /* Open file handles */
55 SilcUInt32 handles_count;
58 /* Generates absolute path from relative path that may include '.' and '..'
61 static char *memfs_expand_path(MemFSEntry root, const char *path)
63 if (!strstr(path, "./") && !strstr(path, "../") &&
64 !strstr(path, "/..") && !strstr(path, "/."))
71 /* Add `entry' to directory `dir'. */
73 static SilcBool memfs_add_entry(MemFSEntry dir, MemFSEntry entry,
78 /* Must be both write and exec permissions */
80 !((dir->perm & SILC_SFTP_FS_PERM_WRITE) &&
81 (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
85 dir->entry = silc_calloc(3, sizeof(*entry));
88 dir->entry[0] = entry;
90 entry->created = time(0);
94 for (i = 0; i < dir->entry_count; i++) {
98 dir->entry[i] = entry;
99 entry->created = time(0);
103 dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
104 (dir->entry_count + 3));
107 for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
108 dir->entry[i] = NULL;
109 dir->entry[dir->entry_count] = entry;
110 dir->entry_count += 3;
111 entry->created = time(0);
116 /* Removes entry `entry' and all entries under it recursively. */
118 static SilcBool memfs_del_entry(MemFSEntry entry, SilcBool check_perm)
122 /* Directories cannot be removed from remote access */
126 silc_free(entry->name);
127 silc_free(entry->data);
129 /* Delete all entries recursively under this entry */
130 for (i = 0; i < entry->entry_count; i++) {
131 if (entry->entry[i]) {
132 if (!memfs_del_entry(entry->entry[i], FALSE))
136 silc_free(entry->entry);
138 /* Remove from parent */
140 for (i = 0; i < entry->parent->entry_count; i++) {
141 if (entry->parent->entry[i] == entry) {
142 entry->parent->entry[i] = NULL;
153 /* Finds first occurence of entry named `name' under the directory `dir'.
154 This does not check subdirectories recursively. */
156 static MemFSEntry memfs_find_entry(MemFSEntry dir, const char *name,
161 for (i = 0; i < dir->entry_count; i++) {
165 if (!strncmp(name, dir->entry[i]->name, name_len))
166 return dir->entry[i];
172 /* Finds the entry by the `path' which may include full path or
175 static MemFSEntry memfs_find_entry_path(MemFSEntry dir, const char *p)
177 MemFSEntry entry = NULL;
181 cp = path = memfs_expand_path(dir, p);
183 if (strlen(cp) == 1 && cp[0] == '/')
188 len = strcspn(cp, DIR_SEPARATOR);
190 entry = memfs_find_entry(dir, cp, len);
199 len = strcspn(cp, DIR_SEPARATOR);
207 /* Deletes entry by the name `name' from the directory `dir'. This does
208 not check subdirectories recursively. */
210 static SilcBool memfs_del_entry_name(MemFSEntry dir, const char *name,
211 SilcUInt32 name_len, SilcBool check_perm)
215 /* Files cannot be removed from remote access */
219 entry = memfs_find_entry(dir, name, name_len);
222 return memfs_del_entry(entry, check_perm);
227 /* Create new handle and add it to the list of open handles. */
229 static MemFSFileHandle memfs_create_handle(MemFS fs, int fd, MemFSEntry entry)
231 MemFSFileHandle handle;
234 handle = silc_calloc(1, sizeof(*handle));
238 handle->entry = entry;
241 fs->handles = silc_calloc(5, sizeof(*fs->handles));
244 fs->handles[0] = handle;
245 fs->handles_count = 5;
252 for (i = 0; i < fs->handles_count; i++) {
256 fs->handles[i] = handle;
263 fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
264 (fs->handles_count + 5));
267 for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
268 fs->handles[i] = NULL;
269 fs->handles[fs->handles_count] = handle;
270 handle->handle = fs->handles_count;
271 fs->handles_count += 5;
276 /* Deletes the handle and remove it from the open handle list. */
278 static SilcBool memfs_del_handle(MemFS fs, MemFSFileHandle handle)
280 if (handle->handle > fs->handles_count)
283 if (!fs->handles[handle->handle])
286 if (fs->handles[handle->handle] == handle) {
287 fs->handles[handle->handle] = NULL;
288 if (handle->fd != -1)
289 silc_file_close(handle->fd);
297 /* Find handle by handle index. */
299 static MemFSFileHandle memfs_find_handle(MemFS fs, SilcUInt32 handle)
301 if (handle > fs->handles_count)
304 if (!fs->handles[handle])
307 if (fs->handles[handle]->handle != handle)
310 return fs->handles[handle];
313 /* Allocates memory filesystem context and returns the context. The
314 context can be given as argument to the silc_sftp_server_start function.
315 The context must be freed by the caller using the function
316 silc_sftp_fs_memory_free. The `perm' is the permissions for the root
317 directory of the filesystem (/ dir). */
319 SilcSFTPFilesystem silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
321 SilcSFTPFilesystem filesystem;
324 fs = silc_calloc(1, sizeof(*fs));
328 fs->root = silc_calloc(1, sizeof(*fs->root));
334 fs->root->perm = perm;
335 fs->root_perm = perm;
336 fs->root->directory = TRUE;
337 fs->root->name = strdup(DIR_SEPARATOR);
338 if (!fs->root->name) {
343 filesystem = silc_calloc(1, sizeof(*filesystem));
345 silc_free(fs->root->name);
351 filesystem->fs = (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
352 filesystem->fs_context = (void *)fs;
357 /* Frees the memory filesystem context. */
359 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
361 MemFS memfs = (MemFS)fs->fs_context;
363 silc_free(memfs->root);
367 /* Adds a new directory to the memory filesystem. Returns the directory
368 context that can be used to add for example files to the directory
369 or new subdirectories under the directory. The `dir' is the parent
370 directory of the directory to be added. If this directory is to be
371 added to the root directory the `dir' is NULL. The `name' is the name
372 of the directory. If error occurs this returns NULL. The caller must
373 not free the returned context. The `perm' will indicate the permissions
374 for the directory and they work in POSIX style. */
376 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
377 SilcSFTPFSMemoryPerm perm,
380 MemFS memfs = (MemFS)fs->fs_context;
383 entry = silc_calloc(1, sizeof(*entry));
388 entry->directory = TRUE;
389 entry->parent = dir ? dir : memfs->root;
390 entry->name = strdup(name);
396 if (!memfs_add_entry(dir ? dir : memfs->root, entry, FALSE)) {
397 silc_free(entry->name);
405 /* Deletes a directory indicated by the `dir'. All files and subdirectories
406 in this directory is also removed. If the `dir' is NULL then all
407 directories and files are removed from the filesystem. Returns TRUE
408 if the removing was success. This is the only way to remove directories
409 in memory file system. The filesystem does not allow removing directories
410 with remote access using the filesystem access function sftp_rmdir. */
412 SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
414 MemFS memfs = (MemFS)fs->fs_context;
418 return memfs_del_entry(dir, FALSE);
420 /* Remove from root */
421 ret = memfs_del_entry(memfs->root, FALSE);
423 memfs->root = silc_calloc(1, sizeof(*memfs->root));
427 memfs->root->perm = memfs->root_perm;
428 memfs->root->directory = TRUE;
429 memfs->root->name = strdup(DIR_SEPARATOR);
430 if (!memfs->root->name) {
431 silc_free(memfs->root);
439 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
440 is NULL the file is added to the root directory. The `filename' is the
441 filename in the directory. The `realpath' is the real filepath in the
442 physical filesystem. It is used to actually access the file from the
443 memory filesystem. The `perm' will indicate the permissions for th e
444 file and they work in POSIX style. Returns TRUE if the file was
445 added to the directory. */
447 SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
448 SilcSFTPFSMemoryPerm perm,
449 const char *filename,
450 const char *realpath)
452 MemFS memfs = (MemFS)fs->fs_context;
455 entry = silc_calloc(1, sizeof(*entry));
460 entry->directory = FALSE;
461 entry->name = strdup(filename);
462 entry->data = strdup(realpath);
463 if (!entry->name || !entry->data) {
464 silc_free(entry->name);
465 silc_free(entry->data);
470 return memfs_add_entry(dir ? dir : memfs->root, entry, FALSE);
473 /* Removes a file indicated by the `filename' from the directory
474 indicated by the `dir'. Returns TRUE if the removing was success. */
476 SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
477 const char *filename)
479 MemFS memfs = (MemFS)fs->fs_context;
484 return memfs_del_entry_name(dir ? dir : memfs->root, filename,
485 strlen(filename), FALSE);
488 SilcSFTPHandle memfs_get_handle(void *context, SilcSFTP sftp,
489 const unsigned char *data,
492 MemFS fs = (MemFS)context;
498 SILC_GET32_MSB(handle, data);
499 return (SilcSFTPHandle)memfs_find_handle(fs, handle);
502 unsigned char *memfs_encode_handle(void *context, SilcSFTP sftp,
503 SilcSFTPHandle handle,
504 SilcUInt32 *handle_len)
507 MemFSFileHandle h = (MemFSFileHandle)handle;
509 data = silc_calloc(4, sizeof(*data));
513 SILC_PUT32_MSB(h->handle, data);
518 void memfs_open(void *context, SilcSFTP sftp,
519 const char *filename,
520 SilcSFTPFileOperation pflags,
521 SilcSFTPAttributes attrs,
522 SilcSFTPHandleCallback callback,
523 void *callback_context)
525 MemFS fs = (MemFS)context;
527 MemFSFileHandle handle;
530 /* CREAT and TRUNC not supported */
531 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
532 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
537 entry = memfs_find_entry_path(fs->root, filename);
539 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
543 if (entry->directory || !entry->data) {
544 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
548 /* Check for reading */
549 if ((pflags & SILC_SFTP_FXF_READ) &&
550 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
551 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
556 /* Check for writing */
557 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
558 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
559 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
564 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
566 else if (pflags & SILC_SFTP_FXF_READ)
568 else if (pflags & SILC_SFTP_FXF_WRITE)
570 if (pflags & SILC_SFTP_FXF_APPEND)
573 /* Attempt to open the file for real. */
574 fd = silc_file_open_mode(entry->data + 7, flags,
575 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
576 attrs->permissions : 0600));
578 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, callback_context);
582 /* File opened, return handle */
583 handle = memfs_create_handle(fs, fd, entry);
585 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
588 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
592 void memfs_close(void *context, SilcSFTP sftp,
593 SilcSFTPHandle handle,
594 SilcSFTPStatusCallback callback,
595 void *callback_context)
597 MemFS fs = (MemFS)context;
598 MemFSFileHandle h = (MemFSFileHandle)handle;
602 ret = silc_file_close(h->fd);
604 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, NULL,
610 memfs_del_handle(fs, h);
611 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
614 void memfs_read(void *context, SilcSFTP sftp,
615 SilcSFTPHandle handle,
618 SilcSFTPDataCallback callback,
619 void *callback_context)
621 MemFSFileHandle h = (MemFSFileHandle)handle;
622 unsigned char data[63488];
628 ret = lseek(h->fd, (off_t)offset, SEEK_SET);
631 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
633 (*callback)(sftp, silc_sftp_map_errno(silc_errno),
634 NULL, 0, callback_context);
638 /* Attempt to read */
639 ret = silc_file_read(h->fd, data, len);
642 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
644 (*callback)(sftp, silc_sftp_map_errno(silc_errno),
645 NULL, 0, callback_context);
650 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
651 ret, callback_context);
654 void memfs_write(void *context, SilcSFTP sftp,
655 SilcSFTPHandle handle,
657 const unsigned char *data,
659 SilcSFTPStatusCallback callback,
660 void *callback_context)
662 MemFSFileHandle h = (MemFSFileHandle)handle;
665 lseek(h->fd, (off_t)offset, SEEK_SET);
667 /* Attempt to write */
668 ret = silc_file_write(h->fd, data, data_len);
670 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, NULL,
675 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
678 void memfs_remove(void *context, SilcSFTP sftp,
679 const char *filename,
680 SilcSFTPStatusCallback callback,
681 void *callback_context)
683 /* Remove is not supported */
684 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
688 void memfs_rename(void *context, SilcSFTP sftp,
691 SilcSFTPStatusCallback callback,
692 void *callback_context)
694 /* Rename is not supported */
695 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
699 void memfs_mkdir(void *context, SilcSFTP sftp,
701 SilcSFTPAttributes attrs,
702 SilcSFTPStatusCallback callback,
703 void *callback_context)
705 /* Mkdir is not supported */
706 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
710 void memfs_rmdir(void *context, SilcSFTP sftp,
712 SilcSFTPStatusCallback callback,
713 void *callback_context)
715 /* Rmdir is not supported */
716 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
720 void memfs_opendir(void *context, SilcSFTP sftp,
722 SilcSFTPHandleCallback callback,
723 void *callback_context)
725 MemFS fs = (MemFS)context;
727 MemFSFileHandle handle;
729 if (!path || !strlen(path))
730 path = (const char *)DIR_SEPARATOR;
732 /* Find such directory */
733 entry = memfs_find_entry_path(fs->root, path);
735 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
739 if (!entry->directory) {
740 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
744 /* Must be read permissions to open a directory */
745 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
746 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
751 /* Directory opened, return handle */
752 handle = memfs_create_handle(fs, 0, entry);
754 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
757 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
761 void memfs_readdir(void *context, SilcSFTP sftp,
762 SilcSFTPHandle handle,
763 SilcSFTPNameCallback callback,
764 void *callback_context)
766 MemFSFileHandle h = (MemFSFileHandle)handle;
769 SilcSFTPAttributes attrs;
772 SilcUInt64 filesize = 0;
774 SilcFileStatStruct stats;
776 if (!h->entry->directory) {
777 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
782 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
786 name = silc_calloc(1, sizeof(*name));
788 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
791 for (i = h->fd; i < 100 + h->fd; i++) {
792 if (i >= h->entry->entry_count)
795 entry = h->entry->entry[i];
799 filesize = sizeof(*entry);
800 memset(long_name, 0, sizeof(long_name));
802 date = (char *)silc_time_string(entry->created);
803 if (strrchr(date, ':'))
804 *strrchr(date, ':') = '\0';
806 if (!entry->directory) {
807 filesize = silc_file_size(entry->data + 7);
808 silc_file_stat(entry->data + 7, TRUE, &stats);
811 /* Long name format is:
812 drwx------ 1 324210 Apr 8 08:40 mail/
813 1234567890 123 12345678 123456789012 */
814 silc_snprintf(long_name, sizeof(long_name) - 1,
815 "%c%c%c%c------ %3d %8llu %12s %s%s",
816 (entry->directory ? 'd' : '-'),
817 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
818 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
819 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
820 (entry->directory ? (int)entry->entry_count : 1),
822 (unsigned long long)filesize,
824 (unsigned long)filesize,
827 (entry->directory ? "/" :
828 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
831 attrs = silc_calloc(1, sizeof(*attrs));
833 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
836 attrs->flags = (SILC_SFTP_ATTR_SIZE |
837 SILC_SFTP_ATTR_UIDGID);
838 attrs->size = filesize;
839 attrs->uid = 0; /* We use always 0 UID and GID */
841 if (!entry->directory) {
842 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
843 attrs->atime = silc_time_epoch(&stats.last_access);
844 attrs->mtime = silc_time_epoch(&stats.last_mod);
848 silc_sftp_name_add(name, entry->name, long_name, attrs);
851 /* If we didn't read all then udpate the index for next read */
852 if (i >= h->entry->entry_count)
857 /* If names was not found then return EOF. */
858 if (name->count == 0) {
859 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
860 silc_sftp_name_free(name);
865 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
868 silc_sftp_name_free(name);
871 void memfs_stat(void *context, SilcSFTP sftp,
873 SilcSFTPAttrCallback callback,
874 void *callback_context)
876 MemFS fs = (MemFS)context;
878 SilcSFTPAttributes attrs;
879 SilcFileStatStruct stats;
881 if (!path || !strlen(path))
882 path = (const char *)DIR_SEPARATOR;
884 /* Find such directory */
885 entry = memfs_find_entry_path(fs->root, path);
887 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
891 if (entry->directory || !entry->data) {
892 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
897 if (!silc_file_stat(entry->data + 7, TRUE, &stats)) {
898 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, callback_context);
902 attrs = silc_calloc(1, sizeof(*attrs));
904 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
907 attrs->flags = (SILC_SFTP_ATTR_SIZE |
908 SILC_SFTP_ATTR_UIDGID |
909 SILC_SFTP_ATTR_ACMODTIME);
910 attrs->size = stats.size;
911 attrs->uid = 0; /* We use always 0 UID and GID */
913 attrs->atime = silc_time_epoch(&stats.last_access);
914 attrs->mtime = silc_time_epoch(&stats.last_mod);
916 /* Return attributes */
917 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
920 silc_sftp_attr_free(attrs);
923 void memfs_lstat(void *context, SilcSFTP sftp,
925 SilcSFTPAttrCallback callback,
926 void *callback_context)
928 MemFS fs = (MemFS)context;
930 SilcSFTPAttributes attrs;
931 SilcFileStatStruct stats;
933 if (!path || !strlen(path))
934 path = (const char *)DIR_SEPARATOR;
936 /* Find such directory */
937 entry = memfs_find_entry_path(fs->root, path);
939 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
943 if (entry->directory || !entry->data) {
944 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
949 if (!silc_file_stat(entry->data + 7, FALSE, &stats)) {
950 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, callback_context);
954 attrs = silc_calloc(1, sizeof(*attrs));
956 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
959 attrs->flags = (SILC_SFTP_ATTR_SIZE |
960 SILC_SFTP_ATTR_UIDGID |
961 SILC_SFTP_ATTR_ACMODTIME);
962 attrs->size = stats.size;
963 attrs->uid = 0; /* We use always 0 UID and GID */
965 attrs->atime = silc_time_epoch(&stats.last_access);
966 attrs->mtime = silc_time_epoch(&stats.last_mod);
968 /* Return attributes */
969 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
972 silc_sftp_attr_free(attrs);
975 void memfs_fstat(void *context, SilcSFTP sftp,
976 SilcSFTPHandle handle,
977 SilcSFTPAttrCallback callback,
978 void *callback_context)
980 MemFSFileHandle h = (MemFSFileHandle)handle;
981 SilcSFTPAttributes attrs;
982 SilcFileStatStruct stats;
984 if (h->entry->directory || !h->entry->data) {
985 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
990 if (!silc_file_fstat(h->fd, &stats)) {
991 (*callback)(sftp, silc_sftp_map_errno(silc_errno), NULL, callback_context);
995 attrs = silc_calloc(1, sizeof(*attrs));
997 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1000 attrs->flags = (SILC_SFTP_ATTR_SIZE |
1001 SILC_SFTP_ATTR_UIDGID |
1002 SILC_SFTP_ATTR_ACMODTIME);
1003 attrs->size = stats.size;
1004 attrs->uid = 0; /* We use always 0 UID and GID */
1006 attrs->atime = silc_time_epoch(&stats.last_access);
1007 attrs->mtime = silc_time_epoch(&stats.last_mod);
1009 /* Return attributes */
1010 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
1013 silc_sftp_attr_free(attrs);
1016 void memfs_setstat(void *context, SilcSFTP sftp,
1018 SilcSFTPAttributes attrs,
1019 SilcSFTPStatusCallback callback,
1020 void *callback_context)
1022 /* Setstat is not supported */
1023 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1027 void memfs_fsetstat(void *context, SilcSFTP sftp,
1028 SilcSFTPHandle handle,
1029 SilcSFTPAttributes attrs,
1030 SilcSFTPStatusCallback callback,
1031 void *callback_context)
1033 /* Fsetstat is not supported */
1034 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1038 void memfs_readlink(void *context, SilcSFTP sftp,
1040 SilcSFTPNameCallback callback,
1041 void *callback_context)
1043 /* Readlink is not supported */
1044 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
1048 void memfs_symlink(void *context, SilcSFTP sftp,
1049 const char *linkpath,
1050 const char *targetpath,
1051 SilcSFTPStatusCallback callback,
1052 void *callback_context)
1054 /* Symlink is not supported */
1055 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1059 void memfs_realpath(void *context, SilcSFTP sftp,
1061 SilcSFTPNameCallback callback,
1062 void *callback_context)
1064 MemFS fs = (MemFS)context;
1068 if (!path || !strlen(path))
1069 path = (const char *)DIR_SEPARATOR;
1071 realpath = memfs_expand_path(fs->root, path);
1075 name = silc_calloc(1, sizeof(*name));
1079 name->filename = silc_calloc(1, sizeof(*name->filename));
1080 if (!name->filename)
1082 name->filename[0] = realpath;
1083 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
1084 if (!name->long_filename)
1086 name->long_filename[0] = realpath;
1087 name->attrs = silc_calloc(1, sizeof(*name->attrs));
1090 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1091 if (!name->attrs[0])
1095 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
1098 silc_sftp_name_free(name);
1102 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1105 void memfs_extended(void *context, SilcSFTP sftp,
1106 const char *request,
1107 const unsigned char *data,
1108 SilcUInt32 data_len,
1109 SilcSFTPExtendedCallback callback,
1110 void *callback_context)
1112 /* Extended is not supported */
1113 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1117 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {
1119 memfs_encode_handle,