api work
[oweals/gnunet.git] / src / util / disk.c
index b0d3b18a4765e11016a8e1c5adb8dd993f180e68..078d6ea1564b8f51468277aa7e6a3ac9e216957d 100644 (file)
  */
 
 #include "platform.h"
-#include "io_handle.h"
 #include "gnunet_common.h"
 #include "gnunet_directories.h"
-#include "gnunet_io_lib.h"
 #include "gnunet_disk_lib.h"
 #include "gnunet_scheduler_lib.h"
 #include "gnunet_strings_lib.h"
@@ -76,6 +74,15 @@ typedef struct
   int include_sym_links;
 } GetFileSizeData;
 
+struct GNUNET_DISK_FileHandle
+{
+#if MINGW
+  HANDLE h;
+#else
+  int fd;
+#endif
+};
+
 static int
 getSizeRec (void *ptr, const char *fn)
 {
@@ -111,6 +118,21 @@ getSizeRec (void *ptr, const char *fn)
   return GNUNET_OK;
 }
 
+/**
+ * Checks whether a handle is invalid
+ * @param h handle to check
+ * @return GNUNET_YES if invalid, GNUNET_NO if valid
+ */
+int
+GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
+{
+#ifdef MINGW
+  return !h || h->h == INVALID_HANDLE_VALUE ? GNUNET_YES : GNUNET_NO;
+#else
+  return !h || h->fd == -1 ? GNUNET_YES : GNUNET_NO;
+#endif
+}
+
 
 /**
  * Move the read/write pointer in a file
@@ -120,7 +142,7 @@ getSizeRec (void *ptr, const char *fn)
  * @return the new position on success, GNUNET_SYSERR otherwise
  */
 off_t
-GNUNET_DISK_file_seek (const struct GNUNET_IO_Handle *h, off_t offset,
+GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, off_t offset,
     enum GNUNET_DISK_Seek whence)
 {
   if (h == NULL)
@@ -406,8 +428,9 @@ GNUNET_DISK_directory_create_for_file (const char *dir)
  * @param len the maximum number of bytes to read
  * @return the number of bytes read on success, GNUNET_SYSERR on failure
  */
-int
-GNUNET_DISK_file_read (const struct GNUNET_IO_Handle *h, void *result, int len)
+ssize_t
+GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, void *result, 
+                      size_t len)
 {
   if (h == NULL)
     {
@@ -432,43 +455,30 @@ GNUNET_DISK_file_read (const struct GNUNET_IO_Handle *h, void *result, int len)
 
 /**
  * Read the contents of a binary file into a buffer.
+ *
  * @param fn file name
  * @param result the buffer to write the result to
  * @param len the maximum number of bytes to read
- * @return the number of bytes read on success, GNUNET_SYSERR on failure
+ * @return number of bytes read, GNUNET_SYSERR on failure
  */
-int
-GNUNET_DISK_fn_read (const char * const fn, void *result, int len)
+ssize_t
+GNUNET_DISK_fn_read (const char * const fn, 
+                    void *result,
+                    size_t len)
 {
-  struct GNUNET_IO_Handle *fh;
-  int ret;
+  struct GNUNET_DISK_FileHandle *fh;
+  ssize_t ret;
 
   fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ);
   if (!fh)
     return GNUNET_SYSERR;
   ret = GNUNET_DISK_file_read (fh, result, len);
-  GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(&fh));
+  GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fh));
 
   return ret;
 }
 
 
-/**
- * Convert string to value ('755' for chmod-call)
- */
-static int
-atoo (const char *s)
-{
-  int n = 0;
-
-  while (('0' <= *s) && (*s < '8'))
-    {
-      n <<= 3;
-      n += *s++ - '0';
-    }
-  return n;
-}
-
 /**
  * Write a buffer to a file.
  * @param h handle to open file
@@ -476,9 +486,9 @@ atoo (const char *s)
  * @param n number of bytes to write
  * @return number of bytes written on success, GNUNET_SYSERR on error
  */
-int
-GNUNET_DISK_file_write (const struct GNUNET_IO_Handle *h, const void *buffer,
-    unsigned int n)
+ssize_t
+GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, const void *buffer,
+                       size_t n)
 {
   if (h == NULL)
     {
@@ -501,25 +511,29 @@ GNUNET_DISK_file_write (const struct GNUNET_IO_Handle *h, const void *buffer,
 }
 
 /**
- * Write a buffer to a file.
+ * Write a buffer to a file.  If the file is longer than the
+ * number of bytes that will be written, iit will be truncated.
+ *
  * @param fn file name
  * @param buffer the data to write
  * @param n number of bytes to write
- * @return number of bytes written on success, GNUNET_SYSERR on error
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
-int
+ssize_t
 GNUNET_DISK_fn_write (const char * const fn, const void *buffer,
-    unsigned int n, int mode)
+    size_t n, int mode)
 {
-  struct GNUNET_IO_Handle *fh;
+  struct GNUNET_DISK_FileHandle *fh;
   int ret;
 
-  fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE
-      | GNUNET_DISK_OPEN_CREATE, mode);
+  fh = GNUNET_DISK_file_open (fn, 
+                             GNUNET_DISK_OPEN_WRITE 
+                             | GNUNET_DISK_OPEN_TRUNCATE
+                             | GNUNET_DISK_OPEN_CREATE, mode);
   if (!fh)
     return GNUNET_SYSERR;
-  ret = GNUNET_DISK_file_write (fh, buffer, n);
-  GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(&fh));
+  ret = (n == GNUNET_DISK_file_write (fh, buffer, n)) ? GNUNET_OK : GNUNET_SYSERR;
+  GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(fh));
 
   return ret;
 }
@@ -816,7 +830,7 @@ GNUNET_DISK_file_copy (const char *src, const char *dst)
   unsigned long long pos;
   unsigned long long size;
   unsigned long long len;
-  struct GNUNET_IO_Handle *in, *out;
+  struct GNUNET_DISK_FileHandle *in, *out;
 
   if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES))
     return GNUNET_SYSERR;
@@ -825,12 +839,12 @@ GNUNET_DISK_file_copy (const char *src, const char *dst)
   if (!in)
     return GNUNET_SYSERR;
   out = GNUNET_DISK_file_open (dst, GNUNET_DISK_OPEN_WRITE
-      | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS,
-      GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
-          | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_GROUP_WRITE);
+                              | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS,
+                              GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
+                              | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_GROUP_WRITE);
   if (!out)
     {
-      GNUNET_DISK_file_close (&in);
+      GNUNET_DISK_file_close (in);
       return GNUNET_SYSERR;
     }
   buf = GNUNET_malloc (COPY_BLK_SIZE);
@@ -846,13 +860,13 @@ GNUNET_DISK_file_copy (const char *src, const char *dst)
       pos += len;
     }
   GNUNET_free (buf);
-  GNUNET_DISK_file_close (&in);
-  GNUNET_DISK_file_close (&out);
+  GNUNET_DISK_file_close (in);
+  GNUNET_DISK_file_close (out);
   return GNUNET_OK;
 FAIL:
   GNUNET_free (buf);
-  GNUNET_DISK_file_close (&in);
-  GNUNET_DISK_file_close (&out);
+  GNUNET_DISK_file_close (in);
+  GNUNET_DISK_file_close (out);
   return GNUNET_SYSERR;
 }
 
@@ -916,7 +930,7 @@ GNUNET_DISK_file_change_owner (const char *filename, const char *user)
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
 int
-GNUNET_DISK_file_lock(struct GNUNET_IO_Handle *fh, off_t lockStart,
+GNUNET_DISK_file_lock(struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
     off_t lockEnd)
 {
   if (fh == NULL)
@@ -954,44 +968,75 @@ GNUNET_DISK_file_lock(struct GNUNET_IO_Handle *fh, off_t lockStart,
  * @param perm permissions for the newly created file
  * @return IO handle on success, NULL on error
  */
-struct GNUNET_IO_Handle *
+struct GNUNET_DISK_FileHandle *
 GNUNET_DISK_file_open (const char *fn, int flags, ...)
 {
   char *expfn;
-  struct GNUNET_IO_Handle *ret;
+  struct GNUNET_DISK_FileHandle *ret;
 #ifdef MINGW
-  DWORD access, disp;
+  DWORD access;
+  DWORD disp;
   HANDLE h;
 #else
-  int oflags, mode;
+  int oflags;
+  int mode;
   int fd;
 #endif
 
   expfn = GNUNET_STRINGS_filename_expand (fn);
 
 #ifndef MINGW
+  mode = 0;
   oflags = 0;
-  if (flags & GNUNET_DISK_OPEN_READ)
+  if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
+    oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
+  else if (flags & GNUNET_DISK_OPEN_READ)
     oflags = O_RDONLY;
-  if (flags & GNUNET_DISK_OPEN_WRITE)
-    oflags |= O_WRONLY;
+  else if (flags & GNUNET_DISK_OPEN_WRITE)
+    oflags = O_WRONLY;
+  else
+    {
+      GNUNET_break (0);
+      return NULL;
+    }
   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
     oflags |= (O_CREAT & O_EXCL);
   if (flags & GNUNET_DISK_OPEN_TRUNCATE)
     oflags |= O_TRUNC;
+  if (flags & GNUNET_DISK_OPEN_APPEND)
+    oflags |= O_APPEND;
   if (flags & GNUNET_DISK_OPEN_CREATE)
     {
+      int perm;
+
       oflags |= O_CREAT;
 
       va_list arg;
-      va_start (arg, oflag);
-      mode = va_arg (arg, int);
+      va_start (arg, flags);
+      perm = va_arg (arg, int);
       va_end (arg);
+
+      if (perm & GNUNET_DISK_PERM_USER_READ)
+        mode |= S_IRUSR;
+      if (perm & GNUNET_DISK_PERM_USER_WRITE)
+        mode |= S_IWUSR;
+      if (perm & GNUNET_DISK_PERM_USER_EXEC)
+        mode |= S_IXUSR;
+      if (perm & GNUNET_DISK_PERM_GROUP_READ)
+        mode |= S_IRGRP;
+      if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
+        mode |= S_IWGRP;
+      if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
+        mode |= S_IXGRP;
+      if (perm & GNUNET_DISK_PERM_OTHER_READ)
+        mode |= S_IROTH;
+      if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
+        mode |= S_IWOTH;
+      if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
+        mode |= S_IXOTH;
     }
-  if (flags & GNUNET_DISK_OPEN_APPEND)
-    oflags = O_APPEND;
 
-  fd = open (expfn, oflag | O_LARGEFILE, perm, mode);
+  fd = open (expfn, oflags | O_LARGEFILE, mode);
   if (fd == -1)
   {
     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", fn);
@@ -1033,7 +1078,7 @@ GNUNET_DISK_file_open (const char *fn, int flags, ...)
     }
 #endif
 
-  ret = (struct GNUNET_IO_Handle *) GNUNET_malloc(sizeof(struct GNUNET_IO_Handle));
+  ret = GNUNET_malloc(sizeof(struct GNUNET_DISK_FileHandle));
 #ifdef MINGW
   ret->h = h;
 #else
@@ -1049,33 +1094,31 @@ GNUNET_DISK_file_open (const char *fn, int flags, ...)
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
 int
-GNUNET_DISK_file_close (struct GNUNET_IO_Handle **h)
+GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
 {
-  if (*h == NULL)
+  if (h == NULL)
     {
       errno = EINVAL;
       return GNUNET_SYSERR;
     }
 
 #if MINGW
-  if (!CloseHandle ((*h)->h))
+  if (!CloseHandle (h->h))
   {
     SetErrnoFromWinError (GetLastError ());
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
+    GNUNET_free (h);
     return GNUNET_SYSERR;
   }
 #else
-  if (close ((*h)->fd) != 0)
+  if (close (h->fd) != 0)
   {
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
+    GNUNET_free (h);
     return GNUNET_SYSERR;
   }
 #endif
-
-  GNUNET_IO_handle_invalidate (*h);
-  free(*h);
-  *h = NULL;
-
+  GNUNET_free (h);
   return GNUNET_OK;
 }
 
@@ -1148,6 +1191,17 @@ GNUNET_DISK_get_home_filename (struct GNUNET_CONFIGURATION_Handle *cfg,
   return ret;
 }
 
+struct GNUNET_DISK_MapHandle
+{
+#ifdef MINGW
+  HANDLE h;
+#else
+  void *addr;
+  size_t len;
+#endif
+};
+
+
 /**
  * Map a file into memory
  * @param h open file handle
@@ -1157,7 +1211,7 @@ GNUNET_DISK_get_home_filename (struct GNUNET_CONFIGURATION_Handle *cfg,
  * @return pointer to the mapped memory region, NULL on failure
  */
 void *
-GNUNET_DISK_file_map (const struct GNUNET_IO_Handle *h, struct GNUNET_IO_Handle **m,
+GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, struct GNUNET_DISK_MapHandle **m,
     int access, size_t len)
 {
   if (h == NULL)
@@ -1191,7 +1245,7 @@ GNUNET_DISK_file_map (const struct GNUNET_IO_Handle *h, struct GNUNET_IO_Handle
       return NULL;
     }
 
-  *m = (struct GNUNET_IO_Handle *) GNUNET_malloc (sizeof (struct GNUNET_IO_Handle));
+  *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
   (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
   if ((*m)->h == INVALID_HANDLE_VALUE)
     {
@@ -1212,64 +1266,57 @@ GNUNET_DISK_file_map (const struct GNUNET_IO_Handle *h, struct GNUNET_IO_Handle
 #else
   int prot;
 
-  prot = flags = 0;
+  prot = 0;
   if (access & GNUNET_DISK_MAP_READ)
     prot = PROT_READ;
   if (access & GNUNET_DISK_MAP_WRITE)
     prot |= PROT_WRITE;
-
-  return mmap (NULL, len, prot, MAP_SHARED, h->h, 0);
+  *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
+  (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
+  (*m)->len = len;
+  return (*m)->addr;
 #endif
 }
 
 /**
  * Unmap a file
  * @param h mapping handle
- * @param addr pointer to the mapped memory region
- * @param len size of the mapping
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
 int
-GNUNET_DISK_file_unmap (struct GNUNET_IO_Handle **h, void *addr, size_t len)
+GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
 {
-#ifdef MINGW
   int ret;
-
-  if (h == NULL || *h == NULL)
+  if (h == NULL)
     {
       errno = EINVAL;
       return GNUNET_SYSERR;
     }
 
+#ifdef MINGW
   ret = UnmapViewOfFile (addr) ? GNUNET_OK : GNUNET_SYSERR;
   if (ret != GNUNET_OK)
     SetErrnoFromWinError (GetLastError ());
-  if (!CloseHandle ((*h)->h) && ret == GNUNET_OK)
+  if (!CloseHandle (h->h) && (ret == GNUNET_OK))
     {
       ret = GNUNET_SYSERR;
       SetErrnoFromWinError (GetLastError ());
     }
-
-  GNUNET_IO_handle_invalidate (*h);
-  GNUNET_free (*h);
-  h = NULL;
-
-  return ret;
 #else
-  int ret;
-  ret = munmap (addr, len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
-  GNUNET_IO_handle_invalidate (h);
-  return ret;
+  ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
 #endif
+  GNUNET_free (h);
+  return ret;
 }
 
+
 /**
  * Write file changes to disk
  * @param h handle to an open file
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
 int
-GNUNET_DISK_file_sync (const struct GNUNET_IO_Handle *h)
+GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
 {
   if (h == NULL)
     {