5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 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);
185 if (strlen(cp) == 1 && cp[0] == '/')
190 len = strcspn(cp, DIR_SEPARATOR);
192 entry = memfs_find_entry(dir, cp, len);
201 len = strcspn(cp, DIR_SEPARATOR);
209 /* Deletes entry by the name `name' from the directory `dir'. This does
210 not check subdirectories recursively. */
212 static SilcBool memfs_del_entry_name(MemFSEntry dir, const char *name,
213 SilcUInt32 name_len, SilcBool check_perm)
217 /* Files cannot be removed from remote access */
221 entry = memfs_find_entry(dir, name, name_len);
224 return memfs_del_entry(entry, check_perm);
229 /* Create new handle and add it to the list of open handles. */
231 static MemFSFileHandle memfs_create_handle(MemFS fs, int fd, MemFSEntry entry)
233 MemFSFileHandle handle;
236 handle = silc_calloc(1, sizeof(*handle));
240 handle->entry = entry;
243 fs->handles = silc_calloc(5, sizeof(*fs->handles));
246 fs->handles[0] = handle;
247 fs->handles_count = 5;
254 for (i = 0; i < fs->handles_count; i++) {
258 fs->handles[i] = handle;
265 fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
266 (fs->handles_count + 5));
269 for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
270 fs->handles[i] = NULL;
271 fs->handles[fs->handles_count] = handle;
272 handle->handle = fs->handles_count;
273 fs->handles_count += 5;
278 /* Deletes the handle and remove it from the open handle list. */
280 static SilcBool memfs_del_handle(MemFS fs, MemFSFileHandle handle)
282 if (handle->handle > fs->handles_count)
285 if (!fs->handles[handle->handle])
288 if (fs->handles[handle->handle] == handle) {
289 fs->handles[handle->handle] = NULL;
290 if (handle->fd != -1)
291 silc_file_close(handle->fd);
299 /* Find handle by handle index. */
301 static MemFSFileHandle memfs_find_handle(MemFS fs, SilcUInt32 handle)
303 if (handle > fs->handles_count)
306 if (!fs->handles[handle])
309 if (fs->handles[handle]->handle != handle)
312 return fs->handles[handle];
315 /* Allocates memory filesystem context and returns the context. The
316 context can be given as argument to the silc_sftp_server_start function.
317 The context must be freed by the caller using the function
318 silc_sftp_fs_memory_free. The `perm' is the permissions for the root
319 directory of the filesystem (/ dir). */
321 SilcSFTPFilesystem silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
323 SilcSFTPFilesystem filesystem;
326 fs = silc_calloc(1, sizeof(*fs));
330 fs->root = silc_calloc(1, sizeof(*fs->root));
336 fs->root->perm = perm;
337 fs->root_perm = perm;
338 fs->root->directory = TRUE;
339 fs->root->name = strdup(DIR_SEPARATOR);
340 if (!fs->root->name) {
345 filesystem = silc_calloc(1, sizeof(*filesystem));
347 silc_free(fs->root->name);
353 filesystem->fs = (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
354 filesystem->fs_context = (void *)fs;
359 /* Frees the memory filesystem context. */
361 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
363 MemFS memfs = (MemFS)fs->fs_context;
365 silc_free(memfs->root);
369 /* Adds a new directory to the memory filesystem. Returns the directory
370 context that can be used to add for example files to the directory
371 or new subdirectories under the directory. The `dir' is the parent
372 directory of the directory to be added. If this directory is to be
373 added to the root directory the `dir' is NULL. The `name' is the name
374 of the directory. If error occurs this returns NULL. The caller must
375 not free the returned context. The `perm' will indicate the permissions
376 for the directory and they work in POSIX style. */
378 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
379 SilcSFTPFSMemoryPerm perm,
382 MemFS memfs = (MemFS)fs->fs_context;
385 entry = silc_calloc(1, sizeof(*entry));
390 entry->directory = TRUE;
391 entry->parent = dir ? dir : memfs->root;
392 entry->name = strdup(name);
398 if (!memfs_add_entry(dir ? dir : memfs->root, entry, FALSE)) {
399 silc_free(entry->name);
407 /* Deletes a directory indicated by the `dir'. All files and subdirectories
408 in this directory is also removed. If the `dir' is NULL then all
409 directories and files are removed from the filesystem. Returns TRUE
410 if the removing was success. This is the only way to remove directories
411 in memory file system. The filesystem does not allow removing directories
412 with remote access using the filesystem access function sftp_rmdir. */
414 SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
416 MemFS memfs = (MemFS)fs->fs_context;
420 return memfs_del_entry(dir, FALSE);
422 /* Remove from root */
423 ret = memfs_del_entry(memfs->root, FALSE);
425 memfs->root = silc_calloc(1, sizeof(*memfs->root));
429 memfs->root->perm = memfs->root_perm;
430 memfs->root->directory = TRUE;
431 memfs->root->name = strdup(DIR_SEPARATOR);
432 if (!memfs->root->name) {
433 silc_free(memfs->root);
441 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
442 is NULL the file is added to the root directory. The `filename' is the
443 filename in the directory. The `realpath' is the real filepath in the
444 physical filesystem. It is used to actually access the file from the
445 memory filesystem. The `perm' will indicate the permissions for th e
446 file and they work in POSIX style. Returns TRUE if the file was
447 added to the directory. */
449 SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
450 SilcSFTPFSMemoryPerm perm,
451 const char *filename,
452 const char *realpath)
454 MemFS memfs = (MemFS)fs->fs_context;
457 entry = silc_calloc(1, sizeof(*entry));
462 entry->directory = FALSE;
463 entry->name = strdup(filename);
464 entry->data = strdup(realpath);
465 if (!entry->name || !entry->data) {
466 silc_free(entry->name);
467 silc_free(entry->data);
472 return memfs_add_entry(dir ? dir : memfs->root, entry, FALSE);
475 /* Removes a file indicated by the `filename' from the directory
476 indicated by the `dir'. Returns TRUE if the removing was success. */
478 SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
479 const char *filename)
481 MemFS memfs = (MemFS)fs->fs_context;
486 return memfs_del_entry_name(dir ? dir : memfs->root, filename,
487 strlen(filename), FALSE);
490 SilcSFTPHandle memfs_get_handle(void *context, SilcSFTP sftp,
491 const unsigned char *data,
494 MemFS fs = (MemFS)context;
500 SILC_GET32_MSB(handle, data);
501 return (SilcSFTPHandle)memfs_find_handle(fs, handle);
504 unsigned char *memfs_encode_handle(void *context, SilcSFTP sftp,
505 SilcSFTPHandle handle,
506 SilcUInt32 *handle_len)
509 MemFSFileHandle h = (MemFSFileHandle)handle;
511 data = silc_calloc(4, sizeof(*data));
515 SILC_PUT32_MSB(h->handle, data);
520 void memfs_open(void *context, SilcSFTP sftp,
521 const char *filename,
522 SilcSFTPFileOperation pflags,
523 SilcSFTPAttributes attrs,
524 SilcSFTPHandleCallback callback,
525 void *callback_context)
527 MemFS fs = (MemFS)context;
529 MemFSFileHandle handle;
532 /* CREAT and TRUNC not supported */
533 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
534 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
539 entry = memfs_find_entry_path(fs->root, filename);
541 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
545 if (entry->directory || !entry->data) {
546 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
550 /* Check for reading */
551 if ((pflags & SILC_SFTP_FXF_READ) &&
552 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
553 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
558 /* Check for writing */
559 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
560 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
561 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
566 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
568 else if (pflags & SILC_SFTP_FXF_READ)
570 else if (pflags & SILC_SFTP_FXF_WRITE)
572 if (pflags & SILC_SFTP_FXF_APPEND)
575 /* Attempt to open the file for real. */
576 fd = silc_file_open_mode(entry->data + 7, flags,
577 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
578 attrs->permissions : 0600));
580 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
584 /* File opened, return handle */
585 handle = memfs_create_handle(fs, fd, entry);
587 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
590 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
594 void memfs_close(void *context, SilcSFTP sftp,
595 SilcSFTPHandle handle,
596 SilcSFTPStatusCallback callback,
597 void *callback_context)
599 MemFS fs = (MemFS)context;
600 MemFSFileHandle h = (MemFSFileHandle)handle;
604 ret = silc_file_close(h->fd);
606 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
612 memfs_del_handle(fs, h);
613 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
616 void memfs_read(void *context, SilcSFTP sftp,
617 SilcSFTPHandle handle,
620 SilcSFTPDataCallback callback,
621 void *callback_context)
623 MemFSFileHandle h = (MemFSFileHandle)handle;
624 unsigned char data[63488];
630 ret = lseek(h->fd, (off_t)offset, SEEK_SET);
633 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
635 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
639 /* Attempt to read */
640 ret = silc_file_read(h->fd, data, len);
643 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
645 (*callback)(sftp, silc_sftp_map_errno(errno), 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(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;
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 memset(&stats, 0, sizeof(stats));
809 stat(entry->data + 7, &stats);
812 /* Long name format is:
813 drwx------ 1 324210 Apr 8 08:40 mail/
814 1234567890 123 12345678 123456789012 */
815 silc_snprintf(long_name, sizeof(long_name) - 1,
816 "%c%c%c%c------ %3d %8llu %12s %s%s",
817 (entry->directory ? 'd' : '-'),
818 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
819 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
820 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
821 (entry->directory ? (int)entry->entry_count : 1),
823 (unsigned long long)filesize,
825 (unsigned long)filesize,
828 (entry->directory ? "/" :
829 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
832 attrs = silc_calloc(1, sizeof(*attrs));
834 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
837 attrs->flags = (SILC_SFTP_ATTR_SIZE |
838 SILC_SFTP_ATTR_UIDGID);
839 attrs->size = filesize;
840 attrs->uid = 0; /* We use always 0 UID and GID */
842 if (!entry->directory) {
843 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
844 attrs->atime = stats.st_atime;
845 attrs->mtime = stats.st_mtime;
849 silc_sftp_name_add(name, entry->name, long_name, attrs);
852 /* If we didn't read all then udpate the index for next read */
853 if (i >= h->entry->entry_count)
858 /* If names was not found then return EOF. */
859 if (name->count == 0) {
860 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
861 silc_sftp_name_free(name);
866 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
869 silc_sftp_name_free(name);
872 void memfs_stat(void *context, SilcSFTP sftp,
874 SilcSFTPAttrCallback callback,
875 void *callback_context)
877 MemFS fs = (MemFS)context;
879 SilcSFTPAttributes attrs;
883 if (!path || !strlen(path))
884 path = (const char *)DIR_SEPARATOR;
886 /* Find such directory */
887 entry = memfs_find_entry_path(fs->root, path);
889 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
893 if (entry->directory || !entry->data) {
894 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
899 ret = stat(entry->data + 7, &stats);
901 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
905 attrs = silc_calloc(1, sizeof(*attrs));
907 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
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 memfs_lstat(void *context, SilcSFTP sftp,
928 SilcSFTPAttrCallback callback,
929 void *callback_context)
931 MemFS fs = (MemFS)context;
933 SilcSFTPAttributes attrs;
937 if (!path || !strlen(path))
938 path = (const char *)DIR_SEPARATOR;
940 /* Find such directory */
941 entry = memfs_find_entry_path(fs->root, path);
943 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
947 if (entry->directory || !entry->data) {
948 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
954 ret = stat(entry->data + 7, &stats);
955 #endif /* SILC_WIN32 */
957 ret = lstat(entry->data + 7, &stats);
958 #endif /* SILC_UNIX */
960 ret = stat(entry->data + 7, &stats);
961 #endif /* SILC_SYMBIAN */
963 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
967 attrs = silc_calloc(1, sizeof(*attrs));
969 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
972 attrs->flags = (SILC_SFTP_ATTR_SIZE |
973 SILC_SFTP_ATTR_UIDGID |
974 SILC_SFTP_ATTR_ACMODTIME);
975 attrs->size = stats.st_size;
976 attrs->uid = 0; /* We use always 0 UID and GID */
978 attrs->atime = stats.st_atime;
979 attrs->mtime = stats.st_mtime;
981 /* Return attributes */
982 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
985 silc_sftp_attr_free(attrs);
988 void memfs_fstat(void *context, SilcSFTP sftp,
989 SilcSFTPHandle handle,
990 SilcSFTPAttrCallback callback,
991 void *callback_context)
993 MemFSFileHandle h = (MemFSFileHandle)handle;
994 SilcSFTPAttributes attrs;
998 if (h->entry->directory || !h->entry->data) {
999 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1004 ret = fstat(h->fd, &stats);
1006 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
1010 attrs = silc_calloc(1, sizeof(*attrs));
1012 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1015 attrs->flags = (SILC_SFTP_ATTR_SIZE |
1016 SILC_SFTP_ATTR_UIDGID |
1017 SILC_SFTP_ATTR_ACMODTIME);
1018 attrs->size = stats.st_size;
1019 attrs->uid = 0; /* We use always 0 UID and GID */
1021 attrs->atime = stats.st_atime;
1022 attrs->mtime = stats.st_mtime;
1024 /* Return attributes */
1025 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
1028 silc_sftp_attr_free(attrs);
1031 void memfs_setstat(void *context, SilcSFTP sftp,
1033 SilcSFTPAttributes attrs,
1034 SilcSFTPStatusCallback callback,
1035 void *callback_context)
1037 /* Setstat is not supported */
1038 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1042 void memfs_fsetstat(void *context, SilcSFTP sftp,
1043 SilcSFTPHandle handle,
1044 SilcSFTPAttributes attrs,
1045 SilcSFTPStatusCallback callback,
1046 void *callback_context)
1048 /* Fsetstat is not supported */
1049 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1053 void memfs_readlink(void *context, SilcSFTP sftp,
1055 SilcSFTPNameCallback callback,
1056 void *callback_context)
1058 /* Readlink is not supported */
1059 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
1063 void memfs_symlink(void *context, SilcSFTP sftp,
1064 const char *linkpath,
1065 const char *targetpath,
1066 SilcSFTPStatusCallback callback,
1067 void *callback_context)
1069 /* Symlink is not supported */
1070 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1074 void memfs_realpath(void *context, SilcSFTP sftp,
1076 SilcSFTPNameCallback callback,
1077 void *callback_context)
1079 MemFS fs = (MemFS)context;
1083 if (!path || !strlen(path))
1084 path = (const char *)DIR_SEPARATOR;
1086 realpath = memfs_expand_path(fs->root, path);
1090 name = silc_calloc(1, sizeof(*name));
1094 name->filename = silc_calloc(1, sizeof(*name->filename));
1095 if (!name->filename)
1097 name->filename[0] = realpath;
1098 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
1099 if (!name->long_filename)
1101 name->long_filename[0] = realpath;
1102 name->attrs = silc_calloc(1, sizeof(*name->attrs));
1105 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1106 if (!name->attrs[0])
1110 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
1113 silc_sftp_name_free(name);
1117 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1120 void memfs_extended(void *context, SilcSFTP sftp,
1121 const char *request,
1122 const unsigned char *data,
1123 SilcUInt32 data_len,
1124 SilcSFTPExtendedCallback callback,
1125 void *callback_context)
1127 /* Extended is not supported */
1128 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1132 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {
1134 memfs_encode_handle,