23d032a5ea47a090497e311e09d6f3c75faa5a96
[silc.git] / lib / silcsftp / sftp_fs_memory.c
1 /*
2
3   sftp_fs_memory.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20 /* XXX TODO Win32 support */
21
22 #include "silcincludes.h"
23 #include "silcsftp.h"
24 #include "silcsftp_fs.h"
25 #include "sftp_util.h"
26
27 #define DIR_SEPARATOR "/"
28
29 /* Memory filesystem entry */
30 typedef struct MemFSEntryStruct {
31   char *name;                       /* Name of the entry */
32   char *data;                       /* Data of the entry */
33   bool directory;                   /* TRUE if this is directory */
34   SilcSFTPFSMemoryPerm perm;        /* Permissions */
35   struct MemFSEntryStruct **entry;  /* Files and sub-directories */
36   uint32 entry_count;               /* Number of files and sub-directories */
37   struct MemFSEntryStruct *parent;  /* non-NULL if `directory' is TRUE,
38                                        includes parent directory. */
39   unsigned long created;            /* Time of creation */
40 } *MemFSEntry;
41
42 /* File handle. */
43 typedef struct {
44   uint32 handle;                    /* Handle index */
45   int fd;                           /* Real file handle */
46   MemFSEntry entry;                 /* Filesystem entry */
47 } *MemFSFileHandle;
48
49 /* Memory filesystem */
50 typedef struct {
51   MemFSEntry root;                  /* Root of the filesystem hierarchy */
52   SilcSFTPFSMemoryPerm root_perm;
53   MemFSFileHandle *handles;         /* Open file handles */
54   uint32 handles_count;
55 } *MemFS;
56
57 /* Generates absolute path from relative path that may include '.' and '..'
58    in the path. */
59
60 static char *mem_expand_path(MemFSEntry root, const char *path)
61 {
62   if (!strstr(path, "./") && !strstr(path, "../") &&
63       !strstr(path, "/..") && !strstr(path, "/."))
64     return strdup(path);
65
66   /* XXX TODO */
67   return NULL;
68 }
69
70 /* Add `entry' to directory `dir'. */
71
72 static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
73                           bool check_perm)
74 {
75   int i;
76
77   /* Must be both write and exec permissions */
78   if (check_perm && 
79       !((dir->perm & SILC_SFTP_FS_PERM_WRITE) && 
80         (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
81     return FALSE;
82
83   if (!dir->entry) {
84     dir->entry = silc_calloc(3, sizeof(*entry));
85     dir->entry[0] = entry;
86     dir->entry_count = 3;
87     entry->created = time(0);
88     return TRUE;
89   }
90
91   for (i = 0; i < dir->entry_count; i++) {
92     if (dir->entry[i])
93       continue;
94
95     dir->entry[i] = entry;
96     entry->created = time(0);
97     return TRUE;
98   }
99
100   dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
101                             (dir->entry_count + 3));
102   for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
103     dir->entry[i] = NULL;
104   dir->entry[dir->entry_count] = entry;
105   dir->entry_count += 3;
106   entry->created = time(0);
107
108   return TRUE;
109 }
110
111 /* Removes entry `entry' and all entries under it recursively. */
112
113 static bool mem_del_entry(MemFSEntry entry, bool check_perm)
114 {
115   int i;
116
117   /* Directories cannot be removed from remote access */
118   if (check_perm)
119     return FALSE;
120
121   silc_free(entry->name);
122   silc_free(entry->data);
123
124   /* Delete all entries recursively under this entry */
125   for (i = 0; i < entry->entry_count; i++) {
126     if (entry->entry[i]) {
127       if (!mem_del_entry(entry->entry[i], FALSE))
128         return FALSE;
129     }
130   }
131   silc_free(entry->entry);
132
133   /* Remove from parent */
134   if (entry->parent) {
135     for (i = 0; i < entry->parent->entry_count; i++) {
136       if (entry->parent->entry[i] == entry) {
137         entry->parent->entry[i] = NULL;
138         break;
139       }
140     }
141   }
142
143   silc_free(entry);
144
145   return TRUE;
146 }
147
148 /* Finds first occurence of entry named `name' under the directory `dir'. 
149    This does not check subdirectories recursively. */
150
151 static MemFSEntry mem_find_entry(MemFSEntry dir, const char *name,
152                                  uint32 name_len)
153 {
154   int i;
155
156   for (i = 0; i < dir->entry_count; i++) {
157     if (!dir->entry[i])
158       continue;
159
160     if (!strncmp(name, dir->entry[i]->name, name_len))
161       return dir->entry[i];
162   }
163
164   return NULL;
165 }
166
167 /* Finds the entry by the `path' which may include full path or
168    relative path. */
169
170 static MemFSEntry mem_find_entry_path(MemFSEntry dir, const char *p)
171 {
172   MemFSEntry entry = NULL;
173   int len;
174   char *path, *cp;
175
176   cp = path = mem_expand_path(dir, p);
177
178   if (strlen(cp) == 1 && cp[0] == '/')
179     return dir;
180
181   if (cp[0] == '/')
182     cp++;
183   len = strcspn(cp, DIR_SEPARATOR);
184   while (cp && len) {
185     entry = mem_find_entry(dir, cp, len);
186     if (!entry) {
187       silc_free(cp);
188       return NULL;
189     }
190     cp += len;
191     if (!strlen(cp))
192       break;
193     cp++;
194     len = strcspn(cp, DIR_SEPARATOR);
195     dir = entry;
196   }
197
198   silc_free(path);
199   return entry;
200 }
201
202 /* Deletes entry by the name `name' from the directory `dir'. This does
203    not check subdirectories recursively. */
204
205 static bool mem_del_entry_name(MemFSEntry dir, const char *name,
206                                uint32 name_len, bool check_perm)
207 {
208   MemFSEntry entry;
209
210   /* Files cannot be removed from remote access */
211   if (check_perm)
212     return FALSE;
213
214   entry = mem_find_entry(dir, name, name_len);
215
216   if (entry)
217     return mem_del_entry(entry, check_perm);
218
219   return FALSE;
220 }
221
222 /* Create new handle and add it to the list of open handles. */
223
224 static MemFSFileHandle mem_create_handle(MemFS fs, int fd, MemFSEntry entry)
225 {
226   MemFSFileHandle handle;
227   int i;
228
229   handle = silc_calloc(1, sizeof(*handle));
230   handle->fd = fd;
231   handle->entry = entry;
232
233   if (!fs->handles) {
234     fs->handles = silc_calloc(5, sizeof(*fs->handles));
235     fs->handles[0] = handle;
236     fs->handles_count = 5;
237
238     handle->handle = 0;
239
240     return handle;
241   }
242
243   for (i = 0; i < fs->handles_count; i++) {
244     if (fs->handles[i])
245       continue;
246
247     fs->handles[i] = handle;
248
249     handle->handle = i;
250
251     return handle;
252   }
253
254   fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
255                              (fs->handles_count + 5));
256   for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
257     fs->handles[i] = NULL;
258   fs->handles[fs->handles_count] = handle;
259   handle->handle = fs->handles_count;
260   fs->handles_count += 5;
261
262   return handle;
263 }
264
265 /* Deletes the handle and remove it from the open handle list. */
266
267 static bool mem_del_handle(MemFS fs, MemFSFileHandle handle)
268 {
269   if (handle->handle > fs->handles_count)
270     return FALSE;
271
272   if (!fs->handles[handle->handle])
273     return FALSE;
274
275   if (fs->handles[handle->handle] == handle) {
276     fs->handles[handle->handle] = NULL;
277     if (handle->fd != -1)
278       close(handle->fd);
279     silc_free(handle);
280     return TRUE;
281   }
282
283   return FALSE;
284 }
285
286 /* Find handle by handle index. */
287
288 static MemFSFileHandle mem_find_handle(MemFS fs, uint32 handle)
289 {
290   if (handle > fs->handles_count)
291     return NULL;
292
293   if (!fs->handles[handle])
294     return NULL;
295
296   if (fs->handles[handle]->handle != handle)
297     return NULL;
298
299   return fs->handles[handle];
300 }
301
302 /* Allocates memory filesystem context and returns the context.  The
303    context can be given as argument to the silc_sftp_server_start function.
304    The context must be freed by the caller using the function
305    silc_sftp_fs_memory_free. The `perm' is the permissions for the root
306    directory of the filesystem (/ dir). */
307
308 void *silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
309 {
310   MemFS fs;
311
312   fs = silc_calloc(1, sizeof(*fs));
313   fs->root = silc_calloc(1, sizeof(*fs->root));
314   fs->root->perm = perm;
315   fs->root_perm = perm;
316   fs->root->directory = TRUE;
317   fs->root->name = strdup(DIR_SEPARATOR);
318
319   return (void *)fs;
320 }
321
322 /* Frees the memory filesystem context. */
323
324 void silc_sftp_fs_memory_free(void *context)
325 {
326   MemFS fs = (MemFS)context;
327
328   silc_free(fs->root);
329   silc_free(fs);
330 }
331
332 /* Adds a new directory to the memory filesystem. Returns the directory
333    context that can be used to add for example files to the directory
334    or new subdirectories under the directory. The `dir' is the parent
335    directory of the directory to be added. If this directory is to be
336    added to the root directory the `dir' is NULL.  The `name' is the name
337    of the directory. If error occurs this returns NULL. The caller must
338    not free the returned context. The `perm' will indicate the permissions
339    for the directory and they work in POSIX style. */
340
341 void *silc_sftp_fs_memory_add_dir(void *context, void *dir,
342                                   SilcSFTPFSMemoryPerm perm,
343                                   const char *name)
344 {
345   MemFS fs = (MemFS)context;
346   MemFSEntry entry;
347
348   entry = silc_calloc(1, sizeof(*entry));
349   entry->perm = perm;
350   entry->name = strdup(name);
351   entry->directory = TRUE;
352   entry->parent = dir ? dir : fs->root;
353
354   if (!mem_add_entry(dir ? dir : fs->root, entry, FALSE))
355     return NULL;
356
357   return entry;
358 }
359
360 /* Deletes a directory indicated by the `dir'. All files and subdirectories
361    in this directory is also removed.  If the `dir' is NULL then all
362    directories and files are removed from the filesystem. Returns TRUE
363    if the removing was success. This is the only way to remove directories
364    in memory file system. The filesystem does not allow removing directories
365    with remote access using the filesystem access function sftp_rmdir. */
366
367 bool silc_sftp_fs_memory_del_dir(void *context, void *dir)
368 {
369   MemFS fs = (MemFS)context;
370   bool ret;
371
372   if (dir)
373     return mem_del_entry(dir, FALSE);
374
375   /* Remove from root */
376   ret = mem_del_entry(fs->root, FALSE);
377
378   fs->root = silc_calloc(1, sizeof(*fs->root));
379   fs->root->perm = fs->root_perm;
380   fs->root->directory = TRUE;
381   fs->root->name = strdup(DIR_SEPARATOR);
382
383   return ret;
384 }
385
386 /* Adds a new file to the directory indicated by the `dir'.  If the `dir'
387    is NULL the file is added to the root directory. The `filename' is the
388    filename in the directory. The `realpath' is the real filepath in the
389    physical filesystem. It is used to actually access the file from the
390    memory filesystem. The `perm' will indicate the permissions for th e
391    file and they work in POSIX style. Returns TRUE if the file was
392    added to the directory. */
393
394 bool silc_sftp_fs_memory_add_file(void *context,
395                                   void *dir,
396                                   SilcSFTPFSMemoryPerm perm,
397                                   const char *filename,
398                                   const char *realpath)
399 {
400   MemFS fs = (MemFS)context;
401   MemFSEntry entry;
402
403   entry = silc_calloc(1, sizeof(*entry));
404   entry->perm = perm;
405   entry->name = strdup(filename);
406   entry->data = strdup(realpath);
407   entry->directory = FALSE;
408
409   return mem_add_entry(dir ? dir : fs->root, entry, FALSE);
410 }
411
412 /* Removes a file indicated by the `filename' from the directory
413    indicated by the `dir'. Returns TRUE if the removing was success. */
414
415 bool silc_sftp_fs_memory_del_file(void *context, void *dir,
416                                   const char *filename)
417 {
418   MemFS fs = (MemFS)context;
419
420   if (!filename)
421     return FALSE;
422
423   return mem_del_entry_name(dir ? dir : fs->root, filename, 
424                             strlen(filename), FALSE);
425 }
426
427 SilcSFTPHandle mem_get_handle(void *context, SilcSFTP sftp,
428                               const unsigned char *data,
429                               uint32 data_len)
430 {
431   MemFS fs = (MemFS)context;
432   uint32 handle;
433
434   if (data_len < 4)
435     return NULL;
436
437   SILC_GET32_MSB(handle, data);
438   return (SilcSFTPHandle)mem_find_handle(fs, handle);
439 }
440
441 unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
442                                  SilcSFTPHandle handle,
443                                  uint32 *handle_len)
444 {
445   unsigned char *data;
446   MemFSFileHandle h = (MemFSFileHandle)handle;
447
448   data = silc_calloc(4, sizeof(*data));
449   SILC_PUT32_MSB(h->handle, data);
450   *handle_len = 4;
451
452   return data;
453 }
454
455 void mem_open(void *context, SilcSFTP sftp, 
456               const char *filename,
457               SilcSFTPFileOperation pflags,
458               SilcSFTPAttributes attrs,
459               SilcSFTPHandleCallback callback,
460               void *callback_context)
461 {
462   MemFS fs = (MemFS)context;
463   MemFSEntry entry;
464   MemFSFileHandle handle;
465   int flags = 0, fd;
466
467   /* CREAT and TRUNC not supported */
468   if ((pflags & SILC_SFTP_FXF_CREAT) || (pflags & SILC_SFTP_FXF_TRUNC)) {
469     (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, callback_context);
470     return;
471   }
472
473   /* Find such file */
474   entry = mem_find_entry_path(fs->root, filename);
475   if (!entry) {
476     (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
477     return;
478   }
479
480   if (entry->directory || !entry->data) {
481     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
482     return;
483   }    
484
485   /* Check for reading */
486   if ((pflags & SILC_SFTP_FXF_READ) && 
487       !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
488     (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
489                 callback_context);
490     return;
491   }    
492
493   /* Check for writing */
494   if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) && 
495       !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
496     (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
497                 callback_context);
498     return;
499   }
500
501   if ((pflags & SILC_SFTP_FXF_READ) && (pflags & SILC_SFTP_FXF_WRITE))
502     flags = O_RDWR;
503   else if (pflags & SILC_SFTP_FXF_READ)
504     flags = O_RDONLY;
505   else if (pflags & SILC_SFTP_FXF_WRITE)
506     flags = O_WRONLY;
507   if (pflags & SILC_SFTP_FXF_APPEND)
508     flags |= O_APPEND;
509
510   /* Attempt to open the file for real. */
511   fd = open(entry->data + 7, flags, 
512             (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
513              attrs->permissions : 0600));
514   if (fd == -1) {
515     (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
516     return;
517   }
518
519   /* File opened, return handle */
520   handle = mem_create_handle(fs, fd, entry);
521   (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle, 
522               callback_context);
523 }
524
525 void mem_close(void *context, SilcSFTP sftp,
526                SilcSFTPHandle handle,
527                SilcSFTPStatusCallback callback,
528                void *callback_context)
529 {
530   MemFS fs = (MemFS)context;
531   MemFSFileHandle h = (MemFSFileHandle)handle;
532   int ret;
533
534   if (h->fd != -1) {
535     ret = close(h->fd);
536     if (ret == -1) {
537       (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL, 
538                   callback_context);
539       return;
540     }
541   }
542
543   mem_del_handle(fs, h);
544   (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
545 }
546
547 void mem_read(void *context, SilcSFTP sftp,
548               SilcSFTPHandle handle,
549               uint64 offset, 
550               uint32 len,
551               SilcSFTPDataCallback callback,
552               void *callback_context)
553 {
554   MemFSFileHandle h = (MemFSFileHandle)handle;
555   unsigned char *data;
556   int ret;
557
558   if (len > 32768)
559     len = 32768;
560
561   data = silc_malloc(len);
562   lseek(h->fd, (off_t)offset, SEEK_SET);
563
564   /* Attempt to read */
565   ret = read(h->fd, data, len);
566   if (ret <= 0) {
567     if (!ret)
568       (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
569     else
570       (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
571     silc_free(data);
572     return;
573   }
574
575   /* Return data */
576   (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data, 
577               ret, callback_context);
578
579   silc_free(data);
580 }
581
582 void mem_write(void *context, SilcSFTP sftp,
583                SilcSFTPHandle handle,
584                uint64 offset,
585                const unsigned char *data,
586                uint32 data_len,
587                SilcSFTPStatusCallback callback,
588                void *callback_context)
589 {
590   MemFSFileHandle h = (MemFSFileHandle)handle;
591   int ret;
592
593   lseek(h->fd, (off_t)offset, SEEK_SET);
594
595   /* Attempt to write */
596   ret = write(h->fd, data, data_len);
597   if (ret <= 0) {
598     (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL, 
599                 callback_context);
600     return;
601   }
602
603   (*callback)(sftp, SILC_SFTP_STATUS_OK, NULL, NULL, callback_context);
604 }
605
606 void mem_remove(void *context, SilcSFTP sftp,
607                 const char *filename,
608                 SilcSFTPStatusCallback callback,
609                 void *callback_context)
610 {
611   /* Remove is not supported */
612   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
613               callback_context);
614 }
615
616 void mem_rename(void *context, SilcSFTP sftp,
617                 const char *oldname,
618                 const char *newname,
619                 SilcSFTPStatusCallback callback,
620                 void *callback_context)
621 {
622   /* Rename is not supported */
623   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
624               callback_context);
625 }
626
627 void mem_mkdir(void *context, SilcSFTP sftp,
628                const char *path,
629                SilcSFTPAttributes attrs,
630                SilcSFTPStatusCallback callback,
631                void *callback_context)
632 {
633   /* Mkdir is not supported */
634   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
635               callback_context);
636 }
637
638 void mem_rmdir(void *context, SilcSFTP sftp,
639                const char *path,
640                SilcSFTPStatusCallback callback,
641                void *callback_context)
642 {
643   /* Rmdir is not supported */
644   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
645               callback_context);
646 }
647
648 void mem_opendir(void *context, SilcSFTP sftp,
649                  const char *path,
650                  SilcSFTPHandleCallback callback,
651                  void *callback_context)
652 {
653   MemFS fs = (MemFS)context;
654   MemFSEntry entry;
655   MemFSFileHandle handle;
656
657   if (!path || !strlen(path))
658     path = (const char *)strdup("/");
659
660   /* Find such directory */
661   entry = mem_find_entry_path(fs->root, path);
662   if (!entry) {
663     (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
664     return;
665   }
666
667   if (!entry->directory) {
668     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
669     return;
670   }    
671
672   /* Must be read permissions to open a directory */
673   if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
674     (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
675                 callback_context);
676     return;
677   }
678
679   /* Directory opened, return handle */
680   handle = mem_create_handle(fs, 0, entry);
681   (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle, 
682               callback_context);
683 }
684
685 void mem_readdir(void *context, SilcSFTP sftp,
686                  SilcSFTPHandle handle,
687                  SilcSFTPNameCallback callback,
688                  void *callback_context)
689 {
690   MemFSFileHandle h = (MemFSFileHandle)handle;
691   MemFSEntry entry;
692   SilcSFTPName name;
693   SilcSFTPAttributes attrs;
694   int i;
695   char long_name[256];
696   unsigned long filesize = 0;
697   char *date;
698   struct stat stats;
699
700   if (!h->entry->directory) {
701     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
702     return;
703   }
704
705   if (h->fd == -1) {
706     (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
707     return;
708   }
709
710   name = silc_calloc(1, sizeof(*name));
711   for (i = h->fd; i < 100 + h->fd; i++) {
712     if (i >= h->entry->entry_count)
713       break;
714
715     entry = h->entry->entry[i];
716     if (!entry)
717       continue;
718
719     filesize = sizeof(*entry);
720     memset(long_name, 0, sizeof(long_name));
721
722     date = ctime(&entry->created);
723     if (strrchr(date, ':'))
724       *strrchr(date, ':') = '\0';
725
726     if (!entry->directory)
727       if (!lstat(entry->data + 7, &stats))
728         filesize = stats.st_size;
729
730     /* Long name format is:
731        drwx------   1   324210 Apr  8 08:40 mail/
732        1234567890 123 12345678 123456789012 */
733     snprintf(long_name, sizeof(long_name) - 1,
734              "%c%c%c%c------ %3d %8lu %12s %s%s",
735              (entry->directory ? 'd' : '-'),
736              ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
737              ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
738              ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
739              (entry->directory ? (int)entry->entry_count : 1),
740              filesize, date, entry->name,
741              (entry->directory ? "/" : 
742               ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
743
744     /* Add attributes */
745     attrs = silc_calloc(1, sizeof(*attrs));
746     attrs->flags = (SILC_SFTP_ATTR_SIZE |
747                     SILC_SFTP_ATTR_UIDGID);
748     attrs->size = filesize;
749     attrs->uid = 0;                 /* We use always 0 UID and GID */
750     attrs->gid = 0;
751     if (!entry->directory) {
752       attrs->flags |= SILC_SFTP_ATTR_ACMODTIME;
753       attrs->atime = stats.st_atime;
754       attrs->mtime = stats.st_mtime;
755     }
756
757     /* Add the name */
758     silc_sftp_name_add(name, entry->name, long_name, attrs);
759   }
760
761   /* If we didn't read all then udpate the index for next read */
762   if (i >= h->entry->entry_count)
763     h->fd = -1;
764   else
765     h->fd = i;
766
767   /* If names was not found then return EOF. */
768   if (name->count == 0) {
769     (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
770     silc_sftp_name_free(name);
771     return;
772   }
773
774   /* Return name(s) */
775   (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
776               callback_context);
777
778   silc_sftp_name_free(name);
779 }
780
781 void mem_stat(void *context, SilcSFTP sftp,
782               const char *path,
783               SilcSFTPAttrCallback callback,
784               void *callback_context)
785 {
786   MemFS fs = (MemFS)context;
787   MemFSEntry entry;
788   SilcSFTPAttributes attrs;
789   int ret;
790   struct stat stats;
791
792   if (!path || !strlen(path))
793     path = (const char *)strdup("/");
794
795   /* Find such directory */
796   entry = mem_find_entry_path(fs->root, path);
797   if (!entry) {
798     (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
799     return;
800   }
801
802   if (entry->directory || !entry->data) {
803     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
804     return;
805   }    
806
807   /* Get real stat */
808   ret = stat(entry->data + 7, &stats);
809   if (ret == -1) {
810     (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
811     return;
812   }
813
814   attrs = silc_calloc(1, sizeof(*attrs));
815   attrs->flags = (SILC_SFTP_ATTR_SIZE |
816                   SILC_SFTP_ATTR_UIDGID |
817                   SILC_SFTP_ATTR_ACMODTIME);
818   attrs->size = stats.st_size;
819   attrs->uid = 0;                   /* We use always 0 UID and GID */
820   attrs->gid = 0;
821   attrs->atime = stats.st_atime;
822   attrs->mtime = stats.st_mtime;
823
824   /* Return attributes */
825   (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
826               callback_context);
827
828   silc_sftp_attr_free(attrs);
829 }
830
831 void mem_lstat(void *context, SilcSFTP sftp,
832                const char *path,
833                SilcSFTPAttrCallback callback,
834                void *callback_context)
835 {
836   MemFS fs = (MemFS)context;
837   MemFSEntry entry;
838   SilcSFTPAttributes attrs;
839   int ret;
840   struct stat stats;
841
842   if (!path || !strlen(path))
843     path = (const char *)strdup("/");
844
845   /* Find such directory */
846   entry = mem_find_entry_path(fs->root, path);
847   if (!entry) {
848     (*callback)(sftp, SILC_SFTP_STATUS_NO_SUCH_FILE, NULL, callback_context);
849     return;
850   }
851
852   if (entry->directory || !entry->data) {
853     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
854     return;
855   }    
856
857   /* Get real stat */
858   ret = lstat(entry->data + 7, &stats);
859   if (ret == -1) {
860     (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
861     return;
862   }
863
864   attrs = silc_calloc(1, sizeof(*attrs));
865   attrs->flags = (SILC_SFTP_ATTR_SIZE |
866                   SILC_SFTP_ATTR_UIDGID |
867                   SILC_SFTP_ATTR_ACMODTIME);
868   attrs->size = stats.st_size;
869   attrs->uid = 0;                   /* We use always 0 UID and GID */
870   attrs->gid = 0;
871   attrs->atime = stats.st_atime;
872   attrs->mtime = stats.st_mtime;
873
874   /* Return attributes */
875   (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
876               callback_context);
877
878   silc_sftp_attr_free(attrs);
879 }
880
881 void mem_fstat(void *context, SilcSFTP sftp,
882                SilcSFTPHandle handle,
883                SilcSFTPAttrCallback callback,
884                void *callback_context)
885 {
886   MemFSFileHandle h = (MemFSFileHandle)handle;
887   SilcSFTPAttributes attrs;
888   int ret;
889   struct stat stats;
890
891   if (h->entry->directory || !h->entry->data) {
892     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
893     return;
894   }    
895
896   /* Get real stat */
897   ret = fstat(h->fd, &stats);
898   if (ret == -1) {
899     (*callback)(sftp, silc_sftp_map_errno(errno), NULL, callback_context);
900     return;
901   }
902
903   attrs = silc_calloc(1, sizeof(*attrs));
904   attrs->flags = (SILC_SFTP_ATTR_SIZE |
905                   SILC_SFTP_ATTR_UIDGID |
906                   SILC_SFTP_ATTR_ACMODTIME);
907   attrs->size = stats.st_size;
908   attrs->uid = 0;                   /* We use always 0 UID and GID */
909   attrs->gid = 0;
910   attrs->atime = stats.st_atime;
911   attrs->mtime = stats.st_mtime;
912
913   /* Return attributes */
914   (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
915               callback_context);
916
917   silc_sftp_attr_free(attrs);
918 }
919      
920 void mem_setstat(void *context, SilcSFTP sftp,
921                  const char *path,
922                  SilcSFTPAttributes attrs,
923                  SilcSFTPStatusCallback callback,
924                  void *callback_context)
925 {
926   /* Setstat is not supported */
927   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
928               callback_context);
929 }
930
931 void mem_fsetstat(void *context, SilcSFTP sftp,
932                   SilcSFTPHandle handle,
933                   SilcSFTPAttributes attrs,
934                   SilcSFTPStatusCallback callback,
935                   void *callback_context)
936 {
937   /* Fsetstat is not supported */
938   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
939               callback_context);
940 }
941
942 void mem_readlink(void *context, SilcSFTP sftp,
943                   const char *path,
944                   SilcSFTPNameCallback callback,
945                   void *callback_context)
946 {
947   /* Readlink is not supported */
948   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL,
949               callback_context);
950 }
951
952 void mem_symlink(void *context, SilcSFTP sftp,
953                  const char *linkpath,
954                  const char *targetpath,
955                  SilcSFTPStatusCallback callback,
956                  void *callback_context)
957 {
958   /* Symlink is not supported */
959   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
960               callback_context);
961 }
962
963 void mem_realpath(void *context, SilcSFTP sftp,
964                   const char *path,
965                   SilcSFTPNameCallback callback,
966                   void *callback_context)
967 {
968   MemFS fs = (MemFS)context;
969   char *realpath;
970   SilcSFTPName name;
971
972   if (!path || !strlen(path))
973     path = (const char *)strdup("/");
974
975   realpath = mem_expand_path(fs->root, path);
976   if (!realpath) {
977     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
978     return;
979   }
980
981   name = silc_calloc(1, sizeof(*name));
982   name->filename = silc_calloc(1, sizeof(*name->filename));
983   name->filename[0] = realpath;
984   name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
985   name->long_filename[0] = realpath;
986   name->attrs = silc_calloc(1, sizeof(*name->attrs));
987   name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
988   name->count = 1;
989
990   (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name, 
991               callback_context);
992
993   silc_sftp_name_free(name);
994 }
995
996 void mem_extended(void *context, SilcSFTP sftp,
997                   const char *request,
998                   const unsigned char *data,
999                   uint32 data_len,
1000                   SilcSFTPExtendedCallback callback,
1001                   void *callback_context)
1002 {
1003   /* Extended is not supported */
1004   (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0, 
1005               callback_context);
1006 }
1007
1008 struct SilcSFTPFilesystemStruct silc_sftp_fs_memory = {
1009   mem_get_handle,
1010   mem_encode_handle,
1011   mem_open,
1012   mem_close,
1013   mem_read,
1014   mem_write,
1015   mem_remove,
1016   mem_rename,
1017   mem_mkdir,
1018   mem_rmdir,
1019   mem_opendir,
1020   mem_readdir,
1021   mem_stat,
1022   mem_lstat,
1023   mem_fstat,
1024   mem_setstat,
1025   mem_fsetstat,
1026   mem_readlink,
1027   mem_symlink,
1028   mem_realpath,
1029   mem_extended
1030 };