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