5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2004 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 *mem_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 bool mem_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 bool mem_del_entry(MemFSEntry entry, bool 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 (!mem_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 mem_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 mem_find_entry_path(MemFSEntry dir, const char *p)
177 MemFSEntry entry = NULL;
181 cp = path = mem_expand_path(dir, p);
183 if (strlen(cp) == 1 && cp[0] == '/')
188 len = strcspn(cp, DIR_SEPARATOR);
190 entry = mem_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 bool mem_del_entry_name(MemFSEntry dir, const char *name,
211 SilcUInt32 name_len, bool check_perm)
215 /* Files cannot be removed from remote access */
219 entry = mem_find_entry(dir, name, name_len);
222 return mem_del_entry(entry, check_perm);
227 /* Create new handle and add it to the list of open handles. */
229 static MemFSFileHandle mem_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 bool mem_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 mem_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);
339 filesystem = silc_calloc(1, sizeof(*filesystem));
346 filesystem->fs = (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
347 filesystem->fs_context = (void *)fs;
352 /* Frees the memory filesystem context. */
354 void silc_sftp_fs_memory_free(SilcSFTPFilesystem fs)
356 MemFS memfs = (MemFS)fs->fs_context;
358 silc_free(memfs->root);
362 /* Adds a new directory to the memory filesystem. Returns the directory
363 context that can be used to add for example files to the directory
364 or new subdirectories under the directory. The `dir' is the parent
365 directory of the directory to be added. If this directory is to be
366 added to the root directory the `dir' is NULL. The `name' is the name
367 of the directory. If error occurs this returns NULL. The caller must
368 not free the returned context. The `perm' will indicate the permissions
369 for the directory and they work in POSIX style. */
371 void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
372 SilcSFTPFSMemoryPerm perm,
375 MemFS memfs = (MemFS)fs->fs_context;
378 entry = silc_calloc(1, sizeof(*entry));
383 entry->name = strdup(name);
384 entry->directory = TRUE;
385 entry->parent = dir ? dir : memfs->root;
387 if (!mem_add_entry(dir ? dir : memfs->root, entry, FALSE))
393 /* Deletes a directory indicated by the `dir'. All files and subdirectories
394 in this directory is also removed. If the `dir' is NULL then all
395 directories and files are removed from the filesystem. Returns TRUE
396 if the removing was success. This is the only way to remove directories
397 in memory file system. The filesystem does not allow removing directories
398 with remote access using the filesystem access function sftp_rmdir. */
400 bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
402 MemFS memfs = (MemFS)fs->fs_context;
406 return mem_del_entry(dir, FALSE);
408 /* Remove from root */
409 ret = mem_del_entry(memfs->root, FALSE);
411 memfs->root = silc_calloc(1, sizeof(*memfs->root));
415 memfs->root->perm = memfs->root_perm;
416 memfs->root->directory = TRUE;
417 memfs->root->name = strdup(DIR_SEPARATOR);
422 /* Adds a new file to the directory indicated by the `dir'. If the `dir'
423 is NULL the file is added to the root directory. The `filename' is the
424 filename in the directory. The `realpath' is the real filepath in the
425 physical filesystem. It is used to actually access the file from the
426 memory filesystem. The `perm' will indicate the permissions for th e
427 file and they work in POSIX style. Returns TRUE if the file was
428 added to the directory. */
430 bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
431 SilcSFTPFSMemoryPerm perm,
432 const char *filename,
433 const char *realpath)
435 MemFS memfs = (MemFS)fs->fs_context;
438 entry = silc_calloc(1, sizeof(*entry));
443 entry->name = strdup(filename);
444 entry->data = strdup(realpath);
445 entry->directory = FALSE;
447 return mem_add_entry(dir ? dir : memfs->root, entry, FALSE);
450 /* Removes a file indicated by the `filename' from the directory
451 indicated by the `dir'. Returns TRUE if the removing was success. */
453 bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
454 const char *filename)
456 MemFS memfs = (MemFS)fs->fs_context;
461 return mem_del_entry_name(dir ? dir : memfs->root, filename,
462 strlen(filename), FALSE);
465 SilcSFTPHandle mem_get_handle(void *context, SilcSFTP sftp,
466 const unsigned char *data,
469 MemFS fs = (MemFS)context;
475 SILC_GET32_MSB(handle, data);
476 return (SilcSFTPHandle)mem_find_handle(fs, handle);
479 unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
480 SilcSFTPHandle handle,
481 SilcUInt32 *handle_len)
484 MemFSFileHandle h = (MemFSFileHandle)handle;
486 data = silc_calloc(4, sizeof(*data));
490 SILC_PUT32_MSB(h->handle, data);
495 void mem_open(void *context, SilcSFTP sftp,
496 const char *filename,
497 SilcSFTPFileOperation pflags,
498 SilcSFTPAttributes attrs,
499 SilcSFTPHandleCallback callback,
500 void *callback_context)
502 MemFS fs = (MemFS)context;
504 MemFSFileHandle handle;
507 /* CREAT and TRUNC not supported */
508 if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
509 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
514 entry = mem_find_entry_path(fs->root, filename);
516 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
520 if (entry->directory || !entry->data) {
521 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
525 /* Check for reading */
526 if ((pflags & SILC_SFTP_FXF_READ) &&
527 !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
528 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
533 /* Check for writing */
534 if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
535 !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
536 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
541 if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
543 else if (pflags & SILC_SFTP_FXF_READ)
545 else if (pflags & SILC_SFTP_FXF_WRITE)
547 if (pflags & SILC_SFTP_FXF_APPEND)
550 /* Attempt to open the file for real. */
551 fd = silc_file_open_mode(entry->data + 7, flags,
552 (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
553 attrs->permissions : 0600));
555 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
559 /* File opened, return handle */
560 handle = mem_create_handle(fs, fd, entry);
562 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
565 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
569 void mem_close(void *context, SilcSFTP sftp,
570 SilcSFTPHandle handle,
571 SilcSFTPStatusCallback callback,
572 void *callback_context)
574 MemFS fs = (MemFS)context;
575 MemFSFileHandle h = (MemFSFileHandle)handle;
579 ret = silc_file_close(h->fd);
581 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
587 mem_del_handle(fs, h);
588 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
591 void mem_read(void *context, SilcSFTP sftp,
592 SilcSFTPHandle handle,
595 SilcSFTPDataCallback callback,
596 void *callback_context)
598 MemFSFileHandle h = (MemFSFileHandle)handle;
605 data = silc_malloc(len);
607 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
610 lseek(h->fd, (off_t)offset, SEEK_SET);
612 /* Attempt to read */
613 ret = silc_file_read(h->fd, data, len);
616 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
618 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
624 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
625 ret, callback_context);
630 void mem_write(void *context, SilcSFTP sftp,
631 SilcSFTPHandle handle,
633 const unsigned char *data,
635 SilcSFTPStatusCallback callback,
636 void *callback_context)
638 MemFSFileHandle h = (MemFSFileHandle)handle;
641 lseek(h->fd, (off_t)offset, SEEK_SET);
643 /* Attempt to write */
644 ret = silc_file_write(h->fd, data, data_len);
646 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
651 (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
654 void mem_remove(void *context, SilcSFTP sftp,
655 const char *filename,
656 SilcSFTPStatusCallback callback,
657 void *callback_context)
659 /* Remove is not supported */
660 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
664 void mem_rename(void *context, SilcSFTP sftp,
667 SilcSFTPStatusCallback callback,
668 void *callback_context)
670 /* Rename is not supported */
671 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
675 void mem_mkdir(void *context, SilcSFTP sftp,
677 SilcSFTPAttributes attrs,
678 SilcSFTPStatusCallback callback,
679 void *callback_context)
681 /* Mkdir is not supported */
682 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
686 void mem_rmdir(void *context, SilcSFTP sftp,
688 SilcSFTPStatusCallback callback,
689 void *callback_context)
691 /* Rmdir is not supported */
692 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
696 void mem_opendir(void *context, SilcSFTP sftp,
698 SilcSFTPHandleCallback callback,
699 void *callback_context)
701 MemFS fs = (MemFS)context;
703 MemFSFileHandle handle;
705 if (!path || !strlen(path))
706 path = (const char *)DIR_SEPARATOR;
708 /* Find such directory */
709 entry = mem_find_entry_path(fs->root, path);
711 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
715 if (!entry->directory) {
716 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
720 /* Must be read permissions to open a directory */
721 if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
722 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
727 /* Directory opened, return handle */
728 handle = mem_create_handle(fs, 0, entry);
730 (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
733 (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
737 void mem_readdir(void *context, SilcSFTP sftp,
738 SilcSFTPHandle handle,
739 SilcSFTPNameCallback callback,
740 void *callback_context)
742 MemFSFileHandle h = (MemFSFileHandle)handle;
745 SilcSFTPAttributes attrs;
748 SilcUInt64 filesize = 0;
752 if (!h->entry->directory) {
753 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
758 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
762 name = silc_calloc(1, sizeof(*name));
764 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
767 for (i = h->fd; i < 100 + h->fd; i++) {
768 if (i >= h->entry->entry_count)
771 entry = h->entry->entry[i];
775 filesize = sizeof(*entry);
776 memset(long_name, 0, sizeof(long_name));
778 date = (char *)silc_get_time(entry->created);
779 if (strrchr(date, ':'))
780 *strrchr(date, ':') = '\0';
782 if (!entry->directory) {
783 filesize = silc_file_size(entry->data + 7);
784 memset(&stats, 0, sizeof(stats));
785 stat(entry->data + 7, &stats);
788 /* Long name format is:
789 drwx------ 1 324210 Apr 8 08:40 mail/
790 1234567890 123 12345678 123456789012 */
791 silc_snprintf(long_name, sizeof(long_name) - 1,
792 "%c%c%c%c------ %3d %8llu %12s %s%s",
793 (entry->directory ? 'd' : '-'),
794 ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
795 ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
796 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
797 (entry->directory ? (int)entry->entry_count : 1),
799 (unsigned long long)filesize,
801 (unsigned long)filesize,
804 (entry->directory ? "/" :
805 ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
808 attrs = silc_calloc(1, sizeof(*attrs));
810 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
813 attrs->flags = (SILC_SFTP_ATTR_SIZE |
814 SILC_SFTP_ATTR_UIDGID);
815 attrs->size = filesize;
816 attrs->uid = 0; /* We use always 0 UID and GID */
818 if (!entry->directory) {
819 attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
820 attrs->atime = stats.st_atime;
821 attrs->mtime = stats.st_mtime;
825 silc_sftp_name_add(name, entry->name, long_name, attrs);
828 /* If we didn't read all then udpate the index for next read */
829 if (i >= h->entry->entry_count)
834 /* If names was not found then return EOF. */
835 if (name->count == 0) {
836 (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
837 silc_sftp_name_free(name);
842 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
845 silc_sftp_name_free(name);
848 void mem_stat(void *context, SilcSFTP sftp,
850 SilcSFTPAttrCallback callback,
851 void *callback_context)
853 MemFS fs = (MemFS)context;
855 SilcSFTPAttributes attrs;
859 if (!path || !strlen(path))
860 path = (const char *)DIR_SEPARATOR;
862 /* Find such directory */
863 entry = mem_find_entry_path(fs->root, path);
865 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
869 if (entry->directory || !entry->data) {
870 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
875 ret = stat(entry->data + 7, &stats);
877 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
881 attrs = silc_calloc(1, sizeof(*attrs));
883 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
886 attrs->flags = (SILC_SFTP_ATTR_SIZE |
887 SILC_SFTP_ATTR_UIDGID |
888 SILC_SFTP_ATTR_ACMODTIME);
889 attrs->size = stats.st_size;
890 attrs->uid = 0; /* We use always 0 UID and GID */
892 attrs->atime = stats.st_atime;
893 attrs->mtime = stats.st_mtime;
895 /* Return attributes */
896 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
899 silc_sftp_attr_free(attrs);
902 void mem_lstat(void *context, SilcSFTP sftp,
904 SilcSFTPAttrCallback callback,
905 void *callback_context)
907 MemFS fs = (MemFS)context;
909 SilcSFTPAttributes attrs;
913 if (!path || !strlen(path))
914 path = (const char *)DIR_SEPARATOR;
916 /* Find such directory */
917 entry = mem_find_entry_path(fs->root, path);
919 (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
923 if (entry->directory || !entry->data) {
924 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
930 ret = lstat(entry->data + 7, &stats);
932 ret = stat(entry->data + 7, &stats);
935 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
939 attrs = silc_calloc(1, sizeof(*attrs));
941 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
944 attrs->flags = (SILC_SFTP_ATTR_SIZE |
945 SILC_SFTP_ATTR_UIDGID |
946 SILC_SFTP_ATTR_ACMODTIME);
947 attrs->size = stats.st_size;
948 attrs->uid = 0; /* We use always 0 UID and GID */
950 attrs->atime = stats.st_atime;
951 attrs->mtime = stats.st_mtime;
953 /* Return attributes */
954 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
957 silc_sftp_attr_free(attrs);
960 void mem_fstat(void *context, SilcSFTP sftp,
961 SilcSFTPHandle handle,
962 SilcSFTPAttrCallback callback,
963 void *callback_context)
965 MemFSFileHandle h = (MemFSFileHandle)handle;
966 SilcSFTPAttributes attrs;
970 if (h->entry->directory || !h->entry->data) {
971 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
976 ret = fstat(h->fd, &stats);
978 (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
982 attrs = silc_calloc(1, sizeof(*attrs));
984 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
987 attrs->flags = (SILC_SFTP_ATTR_SIZE |
988 SILC_SFTP_ATTR_UIDGID |
989 SILC_SFTP_ATTR_ACMODTIME);
990 attrs->size = stats.st_size;
991 attrs->uid = 0; /* We use always 0 UID and GID */
993 attrs->atime = stats.st_atime;
994 attrs->mtime = stats.st_mtime;
996 /* Return attributes */
997 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
1000 silc_sftp_attr_free(attrs);
1003 void mem_setstat(void *context, SilcSFTP sftp,
1005 SilcSFTPAttributes attrs,
1006 SilcSFTPStatusCallback callback,
1007 void *callback_context)
1009 /* Setstat is not supported */
1010 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1014 void mem_fsetstat(void *context, SilcSFTP sftp,
1015 SilcSFTPHandle handle,
1016 SilcSFTPAttributes attrs,
1017 SilcSFTPStatusCallback callback,
1018 void *callback_context)
1020 /* Fsetstat is not supported */
1021 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1025 void mem_readlink(void *context, SilcSFTP sftp,
1027 SilcSFTPNameCallback callback,
1028 void *callback_context)
1030 /* Readlink is not supported */
1031 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
1035 void mem_symlink(void *context, SilcSFTP sftp,
1036 const char *linkpath,
1037 const char *targetpath,
1038 SilcSFTPStatusCallback callback,
1039 void *callback_context)
1041 /* Symlink is not supported */
1042 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
1046 void mem_realpath(void *context, SilcSFTP sftp,
1048 SilcSFTPNameCallback callback,
1049 void *callback_context)
1051 MemFS fs = (MemFS)context;
1055 if (!path || !strlen(path))
1056 path = (const char *)DIR_SEPARATOR;
1058 realpath = mem_expand_path(fs->root, path);
1062 name = silc_calloc(1, sizeof(*name));
1066 name->filename = silc_calloc(1, sizeof(*name->filename));
1067 if (!name->filename)
1069 name->filename[0] = realpath;
1070 name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
1071 if (!name->long_filename)
1073 name->long_filename[0] = realpath;
1074 name->attrs = silc_calloc(1, sizeof(*name->attrs));
1077 name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
1078 if (!name->attrs[0])
1082 (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
1085 silc_sftp_name_free(name);
1089 (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
1092 void mem_extended(void *context, SilcSFTP sftp,
1093 const char *request,
1094 const unsigned char *data,
1095 SilcUInt32 data_len,
1096 SilcSFTPExtendedCallback callback,
1097 void *callback_context)
1099 /* Extended is not supported */
1100 (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
1104 const struct SilcSFTPFilesystemOpsStruct silc_sftp_fs_memory = {