adding new GNUNET_HELPER_ API for communication with (SUID) helper binaries via stdin...
[oweals/gnunet.git] / src / util / disk.c
index ba5d159e410391e5c57ed428814c5f9ea8f66641..e6b542adfeaa608e27e0456243b34142fa8518d8 100644 (file)
@@ -204,7 +204,6 @@ GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
 #endif
 }
 
-
 /**
  * Get the size of an open file.
  *
@@ -214,13 +213,25 @@ GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
  */
 int
 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
-                             off_t *size)
+                             OFF_T *size)
 {
+#if WINDOWS
+  BOOL b;
+  LARGE_INTEGER li;
+  b = GetFileSizeEx (fh->h, &li);
+  if (!b)
+  {
+    SetErrnoFromWinError (GetLastError ());
+    return GNUNET_SYSERR;
+  }
+  *size = (OFF_T) li.QuadPart;
+#else
   struct stat sbuf;
 
   if (0 != FSTAT (fh->fd, &sbuf))
     return GNUNET_SYSERR;
   *size = sbuf.st_size;
+#endif
   return GNUNET_OK;
 }
 
@@ -233,8 +244,8 @@ GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
  * @param whence specification to which position the offset parameter relates to
  * @return the new position on success, GNUNET_SYSERR otherwise
  */
-off_t
-GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, off_t offset,
+OFF_T
+GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
                        enum GNUNET_DISK_Seek whence)
 {
   if (h == NULL)
@@ -244,19 +255,21 @@ GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, off_t offset,
   }
 
 #ifdef MINGW
-  DWORD ret;
+  LARGE_INTEGER li, new_pos;
+  BOOL b;
 
   static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
     [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
   };
+  li.QuadPart = offset;
 
-  ret = SetFilePointer (h->h, offset, NULL, t[whence]);
-  if (ret == INVALID_SET_FILE_POINTER)
+  b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
+  if (b == 0)
   {
     SetErrnoFromWinError (GetLastError ());
     return GNUNET_SYSERR;
   }
-  return ret;
+  return (OFF_T) new_pos.QuadPart;
 #else
   static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
     [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
@@ -349,7 +362,7 @@ GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
   if (succ)
   {
     *dev = info.dwVolumeSerialNumber;
-    *ino = ((info.nFileIndexHigh << sizeof (DWORD)) | info.nFileIndexLow);
+    *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
     return GNUNET_OK;
   }
   else
@@ -385,6 +398,7 @@ GNUNET_DISK_mktemp (const char *t)
 #endif
       )
   {
+    /* FIXME: This uses system codepage on W32, not UTF-8 */
     tmpdir = getenv ("TMPDIR");
     tmpdir = tmpdir ? tmpdir : "/tmp";
     GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
@@ -405,6 +419,9 @@ GNUNET_DISK_mktemp (const char *t)
 #else
   fn = tmpl;
 #endif
+  /* FIXME: why is this not MKSTEMP()? This function is implemented in plibc.
+   * It will assume that fn is UTF-8-encoded, if compiled with UTF-8 support.
+   */
   fd = mkstemp (fn);
   if (fd == -1)
   {
@@ -440,18 +457,26 @@ GNUNET_DISK_get_blocks_available (const char *part)
 #elif MINGW
   DWORD dwDummy;
   DWORD dwBlocks;
-  char szDrive[4];
+  wchar_t szDrive[4];
+  wchar_t wpath[MAX_PATH + 1];
   char *path;
 
   path = GNUNET_STRINGS_filename_expand (part);
   if (path == NULL)
     return -1;
-  memcpy (szDrive, path, 3);
+  /* "part" was in UTF-8, and so is "path" */
+  if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
+  {
+    GNUNET_free (path);
+    return -1;
+  }
   GNUNET_free (path);
+  wcsncpy (szDrive, wpath, 3);
+  GNUNET_free (wpath);
   szDrive[3] = 0;
-  if (!GetDiskFreeSpace (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
+  if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%s': %u\n"),
+    LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
          "GetDiskFreeSpace", szDrive, GetLastError ());
 
     return -1;
@@ -609,7 +634,11 @@ GNUNET_DISK_directory_create (const char *dir)
 #ifndef MINGW
         ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);        /* 755 */
 #else
-        ret = mkdir (rdir);
+        wchar_t wrdir[MAX_PATH + 1];
+        if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
+          ret = !CreateDirectoryW (wrdir, NULL);
+        else
+          ret = 1;
 #endif
         if ((ret != 0) && (errno != EEXIST))
         {
@@ -862,14 +891,14 @@ GNUNET_DISK_directory_scan (const char *dirName,
   {
     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
     if (dinfo != NULL)
-      closedir (dinfo);
+      CLOSEDIR (dinfo);
     GNUNET_free (dname);
     return GNUNET_SYSERR;
   }
   name_len = 256;
   n_size = strlen (dname) + name_len + 2;
   name = GNUNET_malloc (n_size);
-  while ((finfo = readdir (dinfo)) != NULL)
+  while ((finfo = READDIR (dinfo)) != NULL)
   {
     if ((0 == strcmp (finfo->d_name, ".")) ||
         (0 == strcmp (finfo->d_name, "..")))
@@ -891,7 +920,7 @@ GNUNET_DISK_directory_scan (const char *dirName,
                         0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
       if (GNUNET_OK != callback (callback_cls, name))
       {
-        closedir (dinfo);
+        CLOSEDIR (dinfo);
         GNUNET_free (name);
         GNUNET_free (dname);
         return GNUNET_SYSERR;
@@ -899,7 +928,7 @@ GNUNET_DISK_directory_scan (const char *dirName,
     }
     count++;
   }
-  closedir (dinfo);
+  CLOSEDIR (dinfo);
   GNUNET_free (name);
   GNUNET_free (dname);
   return count;
@@ -983,12 +1012,12 @@ GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
   GNUNET_assert (iter->next_name == NULL);
   if (can == GNUNET_YES)
   {
-    closedir (iter->directory);
+    CLOSEDIR (iter->directory);
     GNUNET_free (iter->dirname);
     GNUNET_free (iter);
     return GNUNET_SYSERR;
   }
-  while (NULL != (finfo = readdir (iter->directory)))
+  while (NULL != (finfo = READDIR (iter->directory)))
   {
     if ((0 == strcmp (finfo->d_name, ".")) ||
         (0 == strcmp (finfo->d_name, "..")))
@@ -1223,8 +1252,8 @@ 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_DISK_FileHandle *fh, off_t lockStart,
-                       off_t lockEnd, int excl)
+GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
+                       OFF_T lockEnd, int excl)
 {
   if (fh == NULL)
   {
@@ -1244,13 +1273,18 @@ GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
 #else
   OVERLAPPED o;
+  OFF_T diff = lockEnd - lockStart;
+  DWORD diff_low, diff_high;
+  diff_low = (DWORD) (diff & 0xFFFFFFFF);
+  diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
 
   memset (&o, 0, sizeof (OVERLAPPED));
-  o.Offset = lockStart;
+  o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
+  o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
 
   if (!LockFileEx
       (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
-       0, lockEnd - lockStart, 0, &o))
+       0, diff_low, diff_high, &o))
   {
     SetErrnoFromWinError (GetLastError ());
     return GNUNET_SYSERR;
@@ -1269,8 +1303,8 @@ GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
 int
-GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlockStart,
-                         off_t unlockEnd)
+GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
+                         OFF_T unlockEnd)
 {
   if (fh == NULL)
   {
@@ -1290,11 +1324,16 @@ GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlockStart,
   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
 #else
   OVERLAPPED o;
+  OFF_T diff = unlockEnd - unlockStart;
+  DWORD diff_low, diff_high;
+  diff_low = (DWORD) (diff & 0xFFFFFFFF);
+  diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
 
   memset (&o, 0, sizeof (OVERLAPPED));
-  o.Offset = unlockStart;
+  o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
+  o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
 
-  if (!UnlockFileEx (fh->h, 0, unlockEnd - unlockStart, 0, &o))
+  if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
   {
     SetErrnoFromWinError (GetLastError ());
     return GNUNET_SYSERR;
@@ -1328,6 +1367,7 @@ GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
   DWORD access;
   DWORD disp;
   HANDLE h;
+  wchar_t wexpfn[MAX_PATH + 1];
 #else
   int oflags;
   int mode;
@@ -1406,10 +1446,12 @@ GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
     disp = OPEN_EXISTING;
   }
 
-  /* TODO: access priviledges? */
-  h = CreateFile (expfn, access,
-                  FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
-                  disp, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
+    h = CreateFileW (wexpfn, access,
+                    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                    disp, FILE_ATTRIBUTE_NORMAL, NULL);
+  else
+    h = INVALID_HANDLE_VALUE;
   if (h == INVALID_HANDLE_VALUE)
   {
     SetErrnoFromWinError (GetLastError ());
@@ -2143,6 +2185,9 @@ GNUNET_DISK_npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
       LOG (GNUNET_ERROR_TYPE_DEBUG,
            "Trying to create an instance of named pipe `%s'\n", name);
 #endif
+      /* 1) This might work just fine with UTF-8 strings as it is.
+       * 2) This is only used by GNUnet itself, and only with latin names.
+       */
       h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
                            NULL);