Added preliminary Symbian support.
[silc.git] / lib / silcsftp / sftp_fs_memory.c
index 5ac53706a16739180c30dcf3fb4c145f09dd030b..66d393ace550649aa2ce95b3d685320db593b928 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  sftp_fs_memory.c 
+  sftp_fs_memory.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2004 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
 /* $Id$ */
 /* XXX TODO Win32 support */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 #include "silcsftp_fs.h"
 #include "sftp_util.h"
@@ -33,7 +33,7 @@ typedef struct MemFSEntryStruct {
   SilcUInt32 entry_count;                  /* Number of files and sub-directories */
   struct MemFSEntryStruct *parent;  /* non-NULL if `directory' is TRUE,
                                       includes parent directory. */
-  unsigned long created;           /* Time of creation */
+  SilcUInt32 created;              /* Time of creation */
   char *name;                       /* Name of the entry */
   char *data;                      /* Data of the entry */
   unsigned int directory : 1;      /* Set if this is directory */
@@ -76,13 +76,15 @@ static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
   int i;
 
   /* Must be both write and exec permissions */
-  if (check_perm && 
-      !((dir->perm & SILC_SFTP_FS_PERM_WRITE) && 
+  if (check_perm &&
+      !((dir->perm & SILC_SFTP_FS_PERM_WRITE) &&
        (dir->perm & SILC_SFTP_FS_PERM_EXEC)))
     return FALSE;
 
   if (!dir->entry) {
     dir->entry = silc_calloc(3, sizeof(*entry));
+    if (!dir->entry)
+      return FALSE;
     dir->entry[0] = entry;
     dir->entry_count = 3;
     entry->created = time(0);
@@ -100,6 +102,8 @@ static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
 
   dir->entry = silc_realloc(dir->entry, sizeof(*dir->entry) *
                            (dir->entry_count + 3));
+  if (!dir->entry)
+    return FALSE;
   for (i = dir->entry_count + 1; i < dir->entry_count + 3; i++)
     dir->entry[i] = NULL;
   dir->entry[dir->entry_count] = entry;
@@ -146,7 +150,7 @@ static bool mem_del_entry(MemFSEntry entry, bool check_perm)
   return TRUE;
 }
 
-/* Finds first occurence of entry named `name' under the directory `dir'. 
+/* Finds first occurence of entry named `name' under the directory `dir'.
    This does not check subdirectories recursively. */
 
 static MemFSEntry mem_find_entry(MemFSEntry dir, const char *name,
@@ -228,11 +232,15 @@ static MemFSFileHandle mem_create_handle(MemFS fs, int fd, MemFSEntry entry)
   int i;
 
   handle = silc_calloc(1, sizeof(*handle));
+  if (!handle)
+    return NULL;
   handle->fd = fd;
   handle->entry = entry;
 
   if (!fs->handles) {
     fs->handles = silc_calloc(5, sizeof(*fs->handles));
+    if (!fs->handles)
+      return NULL;
     fs->handles[0] = handle;
     fs->handles_count = 5;
 
@@ -254,6 +262,8 @@ static MemFSFileHandle mem_create_handle(MemFS fs, int fd, MemFSEntry entry)
 
   fs->handles = silc_realloc(fs->handles, sizeof(*fs->handles) *
                             (fs->handles_count + 5));
+  if (!fs->handles)
+    return NULL;
   for (i = fs->handles_count + 1; i < fs->handles_count + 5; i++)
     fs->handles[i] = NULL;
   fs->handles[fs->handles_count] = handle;
@@ -312,15 +322,28 @@ SilcSFTPFilesystem silc_sftp_fs_memory_alloc(SilcSFTPFSMemoryPerm perm)
   MemFS fs;
 
   fs = silc_calloc(1, sizeof(*fs));
+  if (!fs)
+    return NULL;
+
   fs->root = silc_calloc(1, sizeof(*fs->root));
+  if (!fs->root) {
+    silc_free(fs);
+    return NULL;
+  }
+
   fs->root->perm = perm;
   fs->root_perm = perm;
   fs->root->directory = TRUE;
   fs->root->name = strdup(DIR_SEPARATOR);
 
   filesystem = silc_calloc(1, sizeof(*filesystem));
-  filesystem->fs = 
-    (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
+  if (!filesystem) {
+    silc_free(fs->root);
+    silc_free(fs);
+    return NULL;
+  }
+
+  filesystem->fs = (struct SilcSFTPFilesystemOpsStruct *)&silc_sftp_fs_memory;
   filesystem->fs_context = (void *)fs;
 
   return filesystem;
@@ -353,6 +376,9 @@ void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
   MemFSEntry entry;
 
   entry = silc_calloc(1, sizeof(*entry));
+  if (!entry)
+    return NULL;
+
   entry->perm = perm;
   entry->name = strdup(name);
   entry->directory = TRUE;
@@ -383,6 +409,9 @@ bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
   ret = mem_del_entry(memfs->root, FALSE);
 
   memfs->root = silc_calloc(1, sizeof(*memfs->root));
+  if (!memfs->root)
+    return FALSE;
+
   memfs->root->perm = memfs->root_perm;
   memfs->root->directory = TRUE;
   memfs->root->name = strdup(DIR_SEPARATOR);
@@ -407,6 +436,9 @@ bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
   MemFSEntry entry;
 
   entry = silc_calloc(1, sizeof(*entry));
+  if (!entry)
+    return FALSE;
+
   entry->perm = perm;
   entry->name = strdup(filename);
   entry->data = strdup(realpath);
@@ -426,7 +458,7 @@ bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
   if (!filename)
     return FALSE;
 
-  return mem_del_entry_name(dir ? dir : memfs->root, filename, 
+  return mem_del_entry_name(dir ? dir : memfs->root, filename,
                            strlen(filename), FALSE);
 }
 
@@ -452,13 +484,15 @@ unsigned char *mem_encode_handle(void *context, SilcSFTP sftp,
   MemFSFileHandle h = (MemFSFileHandle)handle;
 
   data = silc_calloc(4, sizeof(*data));
+  if (!data)
+    return NULL;
+
   SILC_PUT32_MSB(h->handle, data);
   *handle_len = 4;
-
   return data;
 }
 
-void mem_open(void *context, SilcSFTP sftp, 
+void mem_open(void *context, SilcSFTP sftp,
              const char *filename,
              SilcSFTPFileOperation pflags,
              SilcSFTPAttributes attrs,
@@ -486,20 +520,20 @@ void mem_open(void *context, SilcSFTP sftp,
   if (entry->directory || !entry->data) {
     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
     return;
-  }    
+  }
 
   /* Check for reading */
-  if ((pflags & SILC_SFTP_FXF_READ) && 
+  if ((pflags & SILC_SFTP_FXF_READ) &&
       !(entry->perm & SILC_SFTP_FS_PERM_READ)) {
-    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
+    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
                callback_context);
     return;
-  }    
+  }
 
   /* Check for writing */
-  if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) && 
+  if (((pflags & SILC_SFTP_FXF_WRITE) || (pflags & SILC_SFTP_FXF_APPEND)) &&
       !(entry->perm & SILC_SFTP_FS_PERM_WRITE)) {
-    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
+    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
                callback_context);
     return;
   }
@@ -514,7 +548,7 @@ void mem_open(void *context, SilcSFTP sftp,
     flags |= O_APPEND;
 
   /* Attempt to open the file for real. */
-  fd = silc_file_open_mode(entry->data + 7, flags, 
+  fd = silc_file_open_mode(entry->data + 7, flags,
                           (attrs->flags & SILC_SFTP_ATTR_PERMISSIONS ?
                            attrs->permissions : 0600));
   if (fd == -1) {
@@ -524,8 +558,12 @@ void mem_open(void *context, SilcSFTP sftp,
 
   /* File opened, return handle */
   handle = mem_create_handle(fs, fd, entry);
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle, 
-             callback_context);
+  if (handle)
+    (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
+               callback_context);
+  else
+    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
+               callback_context);
 }
 
 void mem_close(void *context, SilcSFTP sftp,
@@ -540,7 +578,7 @@ void mem_close(void *context, SilcSFTP sftp,
   if (h->fd != -1) {
     ret = silc_file_close(h->fd);
     if (ret == -1) {
-      (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL, 
+      (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
                  callback_context);
       return;
     }
@@ -552,7 +590,7 @@ void mem_close(void *context, SilcSFTP sftp,
 
 void mem_read(void *context, SilcSFTP sftp,
              SilcSFTPHandle handle,
-             SilcUInt64 offset, 
+             SilcUInt64 offset,
              SilcUInt32 len,
              SilcSFTPDataCallback callback,
              void *callback_context)
@@ -565,6 +603,10 @@ void mem_read(void *context, SilcSFTP sftp,
     len = 32768;
 
   data = silc_malloc(len);
+  if (!data) {
+    (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
+    return;
+  }
   lseek(h->fd, (off_t)offset, SEEK_SET);
 
   /* Attempt to read */
@@ -579,7 +621,7 @@ void mem_read(void *context, SilcSFTP sftp,
   }
 
   /* Return data */
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
              ret, callback_context);
 
   silc_free(data);
@@ -601,7 +643,7 @@ void mem_write(void *context, SilcSFTP sftp,
   /* Attempt to write */
   ret = silc_file_write(h->fd, data, data_len);
   if (ret <= 0) {
-    (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL, 
+    (*callback)(sftp, silc_sftp_map_errno(errno), NULL, NULL,
                callback_context);
     return;
   }
@@ -615,7 +657,7 @@ void mem_remove(void *context, SilcSFTP sftp,
                void *callback_context)
 {
   /* Remove is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -626,7 +668,7 @@ void mem_rename(void *context, SilcSFTP sftp,
                void *callback_context)
 {
   /* Rename is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -637,7 +679,7 @@ void mem_mkdir(void *context, SilcSFTP sftp,
               void *callback_context)
 {
   /* Mkdir is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -647,7 +689,7 @@ void mem_rmdir(void *context, SilcSFTP sftp,
               void *callback_context)
 {
   /* Rmdir is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -673,19 +715,23 @@ void mem_opendir(void *context, SilcSFTP sftp,
   if (!entry->directory) {
     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
     return;
-  }    
+  }
 
   /* Must be read permissions to open a directory */
   if (!(entry->perm & SILC_SFTP_FS_PERM_READ)) {
-    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL, 
+    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
                callback_context);
     return;
   }
 
   /* Directory opened, return handle */
   handle = mem_create_handle(fs, 0, entry);
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle, 
-             callback_context);
+  if (handle)
+    (*callback)(sftp, SILC_SFTP_STATUS_OK, (SilcSFTPHandle)handle,
+               callback_context);
+  else
+    (*callback)(sftp, SILC_SFTP_STATUS_PERMISSION_DENIED, NULL,
+               callback_context);
 }
 
 void mem_readdir(void *context, SilcSFTP sftp,
@@ -714,6 +760,10 @@ void mem_readdir(void *context, SilcSFTP sftp,
   }
 
   name = silc_calloc(1, sizeof(*name));
+  if (!name) {
+    (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
+    return;
+  }
   for (i = h->fd; i < 100 + h->fd; i++) {
     if (i >= h->entry->entry_count)
       break;
@@ -725,29 +775,41 @@ void mem_readdir(void *context, SilcSFTP sftp,
     filesize = sizeof(*entry);
     memset(long_name, 0, sizeof(long_name));
 
-    date = ctime(&entry->created);
+    date = (char *)silc_get_time(entry->created);
     if (strrchr(date, ':'))
       *strrchr(date, ':') = '\0';
 
-    if (!entry->directory)
+    if (!entry->directory) {
       filesize = silc_file_size(entry->data + 7);
+      memset(&stats, 0, sizeof(stats));
+      stat(entry->data + 7, &stats);
+    }
 
     /* Long name format is:
        drwx------   1   324210 Apr  8 08:40 mail/
        1234567890 123 12345678 123456789012 */
-    snprintf(long_name, sizeof(long_name) - 1,
+    silc_snprintf(long_name, sizeof(long_name) - 1,
             "%c%c%c%c------ %3d %8llu %12s %s%s",
             (entry->directory ? 'd' : '-'),
             ((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
             ((entry->perm & SILC_SFTP_FS_PERM_WRITE) ? 'w' : '-'),
             ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? 'x' : '-'),
             (entry->directory ? (int)entry->entry_count : 1),
-            filesize, date, entry->name,
-            (entry->directory ? "/" : 
+#ifndef SILC_WIN32
+            (unsigned long long)filesize,
+#else
+            (unsigned long)filesize,
+#endif
+            date, entry->name,
+            (entry->directory ? "/" :
              ((entry->perm & SILC_SFTP_FS_PERM_EXEC) ? "*" : "")));
 
     /* Add attributes */
     attrs = silc_calloc(1, sizeof(*attrs));
+    if (!attrs) {
+      (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, callback_context);
+      return;
+    }
     attrs->flags = (SILC_SFTP_ATTR_SIZE |
                    SILC_SFTP_ATTR_UIDGID);
     attrs->size = filesize;
@@ -807,7 +869,7 @@ void mem_stat(void *context, SilcSFTP sftp,
   if (entry->directory || !entry->data) {
     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
     return;
-  }    
+  }
 
   /* Get real stat */
   ret = stat(entry->data + 7, &stats);
@@ -817,6 +879,10 @@ void mem_stat(void *context, SilcSFTP sftp,
   }
 
   attrs = silc_calloc(1, sizeof(*attrs));
+  if (!attrs) {
+    (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
+    return;
+  }
   attrs->flags = (SILC_SFTP_ATTR_SIZE |
                  SILC_SFTP_ATTR_UIDGID |
                  SILC_SFTP_ATTR_ACMODTIME);
@@ -827,7 +893,7 @@ void mem_stat(void *context, SilcSFTP sftp,
   attrs->mtime = stats.st_mtime;
 
   /* Return attributes */
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
              callback_context);
 
   silc_sftp_attr_free(attrs);
@@ -857,7 +923,7 @@ void mem_lstat(void *context, SilcSFTP sftp,
   if (entry->directory || !entry->data) {
     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
     return;
-  }    
+  }
 
   /* Get real stat */
 #ifndef SILC_WIN32
@@ -871,6 +937,10 @@ void mem_lstat(void *context, SilcSFTP sftp,
   }
 
   attrs = silc_calloc(1, sizeof(*attrs));
+  if (!attrs) {
+    (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
+    return;
+  }
   attrs->flags = (SILC_SFTP_ATTR_SIZE |
                  SILC_SFTP_ATTR_UIDGID |
                  SILC_SFTP_ATTR_ACMODTIME);
@@ -881,7 +951,7 @@ void mem_lstat(void *context, SilcSFTP sftp,
   attrs->mtime = stats.st_mtime;
 
   /* Return attributes */
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
              callback_context);
 
   silc_sftp_attr_free(attrs);
@@ -900,7 +970,7 @@ void mem_fstat(void *context, SilcSFTP sftp,
   if (h->entry->directory || !h->entry->data) {
     (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
     return;
-  }    
+  }
 
   /* Get real stat */
   ret = fstat(h->fd, &stats);
@@ -910,6 +980,10 @@ void mem_fstat(void *context, SilcSFTP sftp,
   }
 
   attrs = silc_calloc(1, sizeof(*attrs));
+  if (!attrs) {
+    (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
+    return;
+  }
   attrs->flags = (SILC_SFTP_ATTR_SIZE |
                  SILC_SFTP_ATTR_UIDGID |
                  SILC_SFTP_ATTR_ACMODTIME);
@@ -920,12 +994,12 @@ void mem_fstat(void *context, SilcSFTP sftp,
   attrs->mtime = stats.st_mtime;
 
   /* Return attributes */
-  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPAttributes)attrs,
              callback_context);
 
   silc_sftp_attr_free(attrs);
 }
-     
+
 void mem_setstat(void *context, SilcSFTP sftp,
                 const char *path,
                 SilcSFTPAttributes attrs,
@@ -933,7 +1007,7 @@ void mem_setstat(void *context, SilcSFTP sftp,
                 void *callback_context)
 {
   /* Setstat is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -944,7 +1018,7 @@ void mem_fsetstat(void *context, SilcSFTP sftp,
                  void *callback_context)
 {
   /* Fsetstat is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -965,7 +1039,7 @@ void mem_symlink(void *context, SilcSFTP sftp,
                 void *callback_context)
 {
   /* Symlink is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, NULL,
              callback_context);
 }
 
@@ -982,24 +1056,37 @@ void mem_realpath(void *context, SilcSFTP sftp,
     path = (const char *)DIR_SEPARATOR;
 
   realpath = mem_expand_path(fs->root, path);
-  if (!realpath) {
-    (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
-    return;
-  }
+  if (!realpath)
+    goto fail;
 
   name = silc_calloc(1, sizeof(*name));
+  if (!name)
+    goto fail;
+
   name->filename = silc_calloc(1, sizeof(*name->filename));
+  if (!name->filename)
+    goto fail;
   name->filename[0] = realpath;
   name->long_filename = silc_calloc(1, sizeof(*name->long_filename));
+  if (!name->long_filename)
+    goto fail;
   name->long_filename[0] = realpath;
   name->attrs = silc_calloc(1, sizeof(*name->attrs));
+  if (!name->attrs)
+    goto fail;
   name->attrs[0] = silc_calloc(1, sizeof(*name->attrs[0]));
+  if (!name->attrs[0])
+    goto fail;
   name->count = 1;
 
-  (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, (const SilcSFTPName)name, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OK, (const SilcSFTPName)name,
              callback_context);
 
   silc_sftp_name_free(name);
+  return;
+
+ fail:
+  (*callback)(sftp, SILC_SFTP_STATUS_FAILURE, NULL, callback_context);
 }
 
 void mem_extended(void *context, SilcSFTP sftp,
@@ -1010,7 +1097,7 @@ void mem_extended(void *context, SilcSFTP sftp,
                  void *callback_context)
 {
   /* Extended is not supported */
-  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0, 
+  (*callback)(sftp, SILC_SFTP_STATUS_OP_UNSUPPORTED, NULL, 0,
              callback_context);
 }