3705e1be2e53ac31cf2dda1cce0f540c1ee37bd7
[oweals/gnunet.git] / src / util / disk.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001--2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/disk.c
23  * @brief disk IO convenience methods
24  * @author Christian Grothoff
25  * @author Nils Durner
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_directories.h"
31 #include "gnunet_disk_lib.h"
32 #include "gnunet_scheduler_lib.h"
33 #include "gnunet_strings_lib.h"
34 #include "gnunet_crypto_lib.h"
35 #include "disk.h"
36
37 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
38
39 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
40
41 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
42
43 /**
44  * Block size for IO for copying files.
45  */
46 #define COPY_BLK_SIZE 65536
47
48
49
50 #if defined(LINUX) || defined(CYGWIN) || defined(GNU)
51 #include <sys/vfs.h>
52 #else
53 #if defined(SOMEBSD) || defined(DARWIN)
54 #include <sys/param.h>
55 #include <sys/mount.h>
56 #else
57 #ifdef SOLARIS
58 #include <sys/types.h>
59 #include <sys/statvfs.h>
60 #else
61 #ifdef MINGW
62 #ifndef PIPE_BUF
63 #define PIPE_BUF        512
64 ULONG PipeSerialNumber;
65 #endif
66 #define         _IFMT           0170000 /* type of file */
67 #define         _IFLNK          0120000 /* symbolic link */
68 #define  S_ISLNK(m)     (((m)&_IFMT) == _IFLNK)
69 #else
70 #error PORT-ME: need to port statfs (how much space is left on the drive?)
71 #endif
72 #endif
73 #endif
74 #endif
75
76 #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS)
77 #include <wordexp.h>
78 #endif
79 #if LINUX
80 #include <sys/statvfs.h>
81 #endif
82
83
84 /**
85  * Handle used to manage a pipe.
86  */
87 struct GNUNET_DISK_PipeHandle
88 {
89   /**
90    * File descriptors for the pipe.
91    */
92   struct GNUNET_DISK_FileHandle *fd[2];
93 };
94
95
96 /**
97  * Closure for the recursion to determine the file size
98  * of a directory.
99  */
100 struct GetFileSizeData
101 {
102   /**
103    * Set to the total file size.
104    */
105   uint64_t total;
106
107   /**
108    * GNUNET_YES if symbolic links should be included.
109    */
110   int include_sym_links;
111
112   /**
113    * GNUNET_YES if mode is file-only (return total == -1 for directories).
114    */
115   int single_file_mode;
116 };
117
118
119 #ifndef MINGW
120 /**
121  * Translate GNUnet-internal permission bitmap to UNIX file
122  * access permission bitmap.
123  *
124  * @param perm file permissions, GNUnet style
125  * @return file permissions, UNIX style
126  */
127 static int
128 translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
129 {
130   int mode;
131
132   mode = 0;
133   if (perm & GNUNET_DISK_PERM_USER_READ)
134     mode |= S_IRUSR;
135   if (perm & GNUNET_DISK_PERM_USER_WRITE)
136     mode |= S_IWUSR;
137   if (perm & GNUNET_DISK_PERM_USER_EXEC)
138     mode |= S_IXUSR;
139   if (perm & GNUNET_DISK_PERM_GROUP_READ)
140     mode |= S_IRGRP;
141   if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
142     mode |= S_IWGRP;
143   if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
144     mode |= S_IXGRP;
145   if (perm & GNUNET_DISK_PERM_OTHER_READ)
146     mode |= S_IROTH;
147   if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
148     mode |= S_IWOTH;
149   if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
150     mode |= S_IXOTH;
151
152   return mode;
153 }
154 #endif
155
156
157 /**
158  * Iterate over all files in the given directory and
159  * accumulate their size.
160  *
161  * @param cls closure of type "struct GetFileSizeData"
162  * @param fn current filename we are looking at
163  * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
164  */
165 static int
166 getSizeRec (void *cls, const char *fn)
167 {
168   struct GetFileSizeData *gfsd = cls;
169
170 #ifdef HAVE_STAT64
171   struct stat64 buf;
172 #else
173   struct stat buf;
174 #endif
175
176 #ifdef HAVE_STAT64
177   if (0 != STAT64 (fn, &buf))
178   {
179     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
180     return GNUNET_SYSERR;
181   }
182 #else
183   if (0 != STAT (fn, &buf))
184   {
185     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
186     return GNUNET_SYSERR;
187   }
188 #endif
189   if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
190   {
191     errno = EISDIR;
192     return GNUNET_SYSERR;
193   }
194   if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
195     gfsd->total += buf.st_size;
196   if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
197       ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
198   {
199     if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
200       return GNUNET_SYSERR;
201   }
202   return GNUNET_OK;
203 }
204
205
206 /**
207  * Checks whether a handle is invalid
208  *
209  * @param h handle to check
210  * @return GNUNET_YES if invalid, GNUNET_NO if valid
211  */
212 int
213 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
214 {
215 #ifdef MINGW
216   return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
217 #else
218   return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
219 #endif
220 }
221
222 /**
223  * Get the size of an open file.
224  *
225  * @param fh open file handle
226  * @param size where to write size of the file
227  * @return GNUNET_OK on success, GNUNET_SYSERR on error
228  */
229 int
230 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
231                               OFF_T *size)
232 {
233 #if WINDOWS
234   BOOL b;
235   LARGE_INTEGER li;
236   b = GetFileSizeEx (fh->h, &li);
237   if (!b)
238   {
239     SetErrnoFromWinError (GetLastError ());
240     return GNUNET_SYSERR;
241   }
242   *size = (OFF_T) li.QuadPart;
243 #else
244   struct stat sbuf;
245
246   if (0 != FSTAT (fh->fd, &sbuf))
247     return GNUNET_SYSERR;
248   *size = sbuf.st_size;
249 #endif
250   return GNUNET_OK;
251 }
252
253
254 /**
255  * Move the read/write pointer in a file
256  *
257  * @param h handle of an open file
258  * @param offset position to move to
259  * @param whence specification to which position the offset parameter relates to
260  * @return the new position on success, GNUNET_SYSERR otherwise
261  */
262 OFF_T
263 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
264                        enum GNUNET_DISK_Seek whence)
265 {
266   if (h == NULL)
267   {
268     errno = EINVAL;
269     return GNUNET_SYSERR;
270   }
271
272 #ifdef MINGW
273   LARGE_INTEGER li;
274   LARGE_INTEGER new_pos;
275   BOOL b;
276
277   static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
278     [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
279   };
280   li.QuadPart = offset;
281
282   b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
283   if (b == 0)
284   {
285     SetErrnoFromWinError (GetLastError ());
286     return GNUNET_SYSERR;
287   }
288   return (OFF_T) new_pos.QuadPart;
289 #else
290   static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
291     [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
292   };
293
294   return lseek (h->fd, offset, t[whence]);
295 #endif
296 }
297
298
299 /**
300  * Get the size of the file (or directory) of the given file (in
301  * bytes).
302  *
303  * @param filename name of the file or directory
304  * @param size set to the size of the file (or,
305  *             in the case of directories, the sum
306  *             of all sizes of files in the directory)
307  * @param includeSymLinks should symbolic links be
308  *        included?
309  * @param singleFileMode GNUNET_YES to only get size of one file
310  *        and return GNUNET_SYSERR for directories.
311  * @return GNUNET_SYSERR on error, GNUNET_OK on success
312  */
313 int
314 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
315                        int includeSymLinks, int singleFileMode)
316 {
317   struct GetFileSizeData gfsd;
318   int ret;
319
320   GNUNET_assert (size != NULL);
321   gfsd.total = 0;
322   gfsd.include_sym_links = includeSymLinks;
323   gfsd.single_file_mode = singleFileMode;
324   ret = getSizeRec (&gfsd, filename);
325   *size = gfsd.total;
326   return ret;
327 }
328
329
330 /**
331  * Obtain some unique identifiers for the given file
332  * that can be used to identify it in the local system.
333  * This function is used between GNUnet processes to
334  * quickly check if two files with the same absolute path
335  * are actually identical.  The two processes represent
336  * the same peer but may communicate over the network
337  * (and the file may be on an NFS volume).  This function
338  * may not be supported on all operating systems.
339  *
340  * @param filename name of the file
341  * @param dev set to the device ID
342  * @param ino set to the inode ID
343  * @return GNUNET_OK on success
344  */
345 int
346 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
347                                   uint64_t * ino)
348 {
349 #if LINUX
350   struct stat sbuf;
351   struct statvfs fbuf;
352
353   if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
354   {
355     *dev = (uint64_t) fbuf.f_fsid;
356     *ino = (uint64_t) sbuf.st_ino;
357     return GNUNET_OK;
358   }
359 #elif SOMEBSD
360   struct stat sbuf;
361   struct statfs fbuf;
362
363   if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
364   {
365     *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
366         ((uint64_t) fbuf.f_fsid.val[1]);
367     *ino = (uint64_t) sbuf.st_ino;
368     return GNUNET_OK;
369   }
370 #elif WINDOWS
371   // FIXME NILS: test this
372   struct GNUNET_DISK_FileHandle *fh;
373   BY_HANDLE_FILE_INFORMATION info;
374   int succ;
375
376   fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
377   if (fh == NULL)
378     return GNUNET_SYSERR;
379   succ = GetFileInformationByHandle (fh->h, &info);
380   GNUNET_DISK_file_close (fh);
381   if (succ)
382   {
383     *dev = info.dwVolumeSerialNumber;
384     *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
385     return GNUNET_OK;
386   }
387   else
388     return GNUNET_SYSERR;
389
390 #endif
391   return GNUNET_SYSERR;
392 }
393
394
395 /**
396  * Create the name for a temporary file or directory from a template.
397  *
398  * @param t template (without XXXXX or "/tmp/")
399  * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
400  */
401 static char *
402 mktemp_name (const char *t)
403 {
404   const char *tmpdir;
405   char *tmpl;
406   char *fn;
407
408   if ((t[0] != '/') && (t[0] != '\\')
409 #if WINDOWS
410       && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
411 #endif
412       )
413   {
414     /* FIXME: This uses system codepage on W32, not UTF-8 */
415     tmpdir = getenv ("TMPDIR");
416     if (NULL == tmpdir)
417       tmpdir = getenv ("TMP");
418     if (NULL == tmpdir)
419       tmpdir = getenv ("TEMP");  
420     if (NULL == tmpdir)
421       tmpdir = "/tmp";
422     GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
423   }
424   else
425   {
426     GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
427   }
428 #ifdef MINGW
429   fn = (char *) GNUNET_malloc (MAX_PATH + 1);
430   if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
431   {
432     GNUNET_free (fn);
433     GNUNET_free (tmpl);
434     return NULL;
435   }
436   GNUNET_free (tmpl);
437 #else
438   fn = tmpl;
439 #endif
440   return fn;
441 }
442
443
444 /**
445  * Create an (empty) temporary directory on disk.  If the given name is not
446  * an absolute path, the current 'TMPDIR' will be prepended.  In any case,
447  * 6 random characters will be appended to the name to create a unique
448  * filename.
449  *
450  * @param t component to use for the name;
451  *        does NOT contain "XXXXXX" or "/tmp/".
452  * @return NULL on error, otherwise name of fresh
453  *         file on disk in directory for temporary files
454  */
455 char *
456 GNUNET_DISK_mkdtemp (const char *t)
457 {
458   char *fn;
459
460   fn = mktemp_name (t);
461   if (fn != mkdtemp (fn))
462   {
463     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
464     GNUNET_free (fn);
465     return NULL;
466   }
467   return fn;
468 }
469
470
471 /**
472  * Create an (empty) temporary file on disk.  If the given name is not
473  * an absolute path, the current 'TMPDIR' will be prepended.  In any case,
474  * 6 random characters will be appended to the name to create a unique
475  * filename.
476  *
477  * @param t component to use for the name;
478  *        does NOT contain "XXXXXX" or "/tmp/".
479  * @return NULL on error, otherwise name of fresh
480  *         file on disk in directory for temporary files
481  */
482 char *
483 GNUNET_DISK_mktemp (const char *t)
484 {
485   int fd;
486   char *fn;
487
488   fn = mktemp_name (t);
489   if (-1 == (fd = mkstemp (fn)))
490   {
491     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
492     GNUNET_free (fn);
493     return NULL;
494   }
495   if (0 != CLOSE (fd))
496     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
497   return fn;
498 }
499
500
501 /**
502  * Get the number of blocks that are left on the partition that
503  * contains the given file (for normal users).
504  *
505  * @param part a file on the partition to check
506  * @return -1 on errors, otherwise the number of free blocks
507  */
508 long
509 GNUNET_DISK_get_blocks_available (const char *part)
510 {
511 #ifdef SOLARIS
512   struct statvfs buf;
513
514   if (0 != statvfs (part, &buf))
515   {
516     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
517     return -1;
518   }
519   return buf.f_bavail;
520 #elif MINGW
521   DWORD dwDummy;
522   DWORD dwBlocks;
523   wchar_t szDrive[4];
524   wchar_t wpath[MAX_PATH + 1];
525   char *path;
526
527   path = GNUNET_STRINGS_filename_expand (part);
528   if (path == NULL)
529     return -1;
530   /* "part" was in UTF-8, and so is "path" */
531   if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
532   {
533     GNUNET_free (path);
534     return -1;
535   }
536   GNUNET_free (path);
537   wcsncpy (szDrive, wpath, 3);
538   szDrive[3] = 0;
539   if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
540   {
541     LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
542          "GetDiskFreeSpace", szDrive, GetLastError ());
543
544     return -1;
545   }
546   return dwBlocks;
547 #else
548   struct statfs s;
549
550   if (0 != statfs (part, &s))
551   {
552     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
553     return -1;
554   }
555   return s.f_bavail;
556 #endif
557 }
558
559
560 /**
561  * Test if "fil" is a directory.
562  * Will not print an error message if the directory
563  * does not exist.  Will log errors if GNUNET_SYSERR is
564  * returned (i.e., a file exists with the same name).
565  *
566  * @param fil filename to test
567  * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
568  *   does not exist
569  */
570 int
571 GNUNET_DISK_directory_test (const char *fil)
572 {
573   struct stat filestat;
574   int ret;
575
576   ret = STAT (fil, &filestat);
577   if (ret != 0)
578   {
579     if (errno != ENOENT)
580     {
581       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
582       return GNUNET_SYSERR;
583     }
584     return GNUNET_NO;
585   }
586   if (!S_ISDIR (filestat.st_mode))
587     return GNUNET_NO;
588   if (ACCESS (fil, R_OK | X_OK) < 0)
589   {
590     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
591     return GNUNET_SYSERR;
592   }
593   return GNUNET_YES;
594 }
595
596
597 /**
598  * Check that fil corresponds to a filename
599  * (of a file that exists and that is not a directory).
600  *
601  * @param fil filename to check
602  * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
603  * else (will print an error message in that case, too).
604  */
605 int
606 GNUNET_DISK_file_test (const char *fil)
607 {
608   struct stat filestat;
609   int ret;
610   char *rdir;
611
612   rdir = GNUNET_STRINGS_filename_expand (fil);
613   if (rdir == NULL)
614     return GNUNET_SYSERR;
615
616   ret = STAT (rdir, &filestat);
617   if (ret != 0)
618   {
619     if (errno != ENOENT)
620     {
621       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
622       GNUNET_free (rdir);
623       return GNUNET_SYSERR;
624     }
625     GNUNET_free (rdir);
626     return GNUNET_NO;
627   }
628   if (!S_ISREG (filestat.st_mode))
629   {
630     GNUNET_free (rdir);
631     return GNUNET_NO;
632   }
633   if (ACCESS (rdir, R_OK) < 0)
634   {
635     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
636     GNUNET_free (rdir);
637     return GNUNET_SYSERR;
638   }
639   GNUNET_free (rdir);
640   return GNUNET_YES;
641 }
642
643
644 /**
645  * Implementation of "mkdir -p"
646  * @param dir the directory to create
647  * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
648  */
649 int
650 GNUNET_DISK_directory_create (const char *dir)
651 {
652   char *rdir;
653   int len;
654   int pos;
655   int ret = GNUNET_OK;
656
657   rdir = GNUNET_STRINGS_filename_expand (dir);
658   if (rdir == NULL)
659     return GNUNET_SYSERR;
660
661   len = strlen (rdir);
662 #ifndef MINGW
663   pos = 1;                      /* skip heading '/' */
664 #else
665   /* Local or Network path? */
666   if (strncmp (rdir, "\\\\", 2) == 0)
667   {
668     pos = 2;
669     while (rdir[pos])
670     {
671       if (rdir[pos] == '\\')
672       {
673         pos++;
674         break;
675       }
676       pos++;
677     }
678   }
679   else
680   {
681     pos = 3;                    /* strlen("C:\\") */
682   }
683 #endif
684   while (pos <= len)
685   {
686     if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
687     {
688       rdir[pos] = '\0';
689       ret = GNUNET_DISK_directory_test (rdir);
690       if (ret == GNUNET_SYSERR)
691       {
692         GNUNET_free (rdir);
693         return GNUNET_SYSERR;
694       }
695       if (ret == GNUNET_NO)
696       {
697 #ifndef MINGW
698         ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);        /* 755 */
699 #else
700         wchar_t wrdir[MAX_PATH + 1];
701         if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
702           ret = !CreateDirectoryW (wrdir, NULL);
703         else
704           ret = 1;
705 #endif
706         if ((ret != 0) && (errno != EEXIST))
707         {
708           LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
709           GNUNET_free (rdir);
710           return GNUNET_SYSERR;
711         }
712       }
713       rdir[pos] = DIR_SEPARATOR;
714     }
715     pos++;
716   }
717   GNUNET_free (rdir);
718   return GNUNET_OK;
719 }
720
721
722 /**
723  * Create the directory structure for storing
724  * a file.
725  *
726  * @param filename name of a file in the directory
727  * @returns GNUNET_OK on success,
728  *          GNUNET_SYSERR on failure,
729  *          GNUNET_NO if the directory
730  *          exists but is not writeable for us
731  */
732 int
733 GNUNET_DISK_directory_create_for_file (const char *filename)
734 {
735   char *rdir;
736   int len;
737   int ret;
738
739   rdir = GNUNET_STRINGS_filename_expand (filename);
740   if (rdir == NULL)
741     return GNUNET_SYSERR;
742   len = strlen (rdir);
743   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
744     len--;
745   rdir[len] = '\0';
746   ret = GNUNET_DISK_directory_create (rdir);
747   if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
748     ret = GNUNET_NO;
749   GNUNET_free (rdir);
750   return ret;
751 }
752
753
754 /**
755  * Read the contents of a binary file into a buffer.
756  * @param h handle to an open file
757  * @param result the buffer to write the result to
758  * @param len the maximum number of bytes to read
759  * @return the number of bytes read on success, GNUNET_SYSERR on failure
760  */
761 ssize_t
762 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
763                        size_t len)
764 {
765   if (h == NULL)
766   {
767     errno = EINVAL;
768     return GNUNET_SYSERR;
769   }
770
771 #ifdef MINGW
772   DWORD bytesRead;
773
774   if (h->type != GNUNET_PIPE)
775   {
776     if (!ReadFile (h->h, result, len, &bytesRead, NULL))
777     {
778       SetErrnoFromWinError (GetLastError ());
779       return GNUNET_SYSERR;
780     }
781   }
782   else
783   {
784     if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
785     {
786       if (GetLastError () != ERROR_IO_PENDING)
787       {
788         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
789         SetErrnoFromWinError (GetLastError ());
790         return GNUNET_SYSERR;
791       }
792       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
793       GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
794     }
795     LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
796   }
797   return bytesRead;
798 #else
799   return read (h->fd, result, len);
800 #endif
801 }
802
803
804 /**
805  * Read the contents of a binary file into a buffer.
806  * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
807  * when no data can be read).
808  *
809  * @param h handle to an open file
810  * @param result the buffer to write the result to
811  * @param len the maximum number of bytes to read
812  * @return the number of bytes read on success, GNUNET_SYSERR on failure
813  */
814 ssize_t
815 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
816     void *result, size_t len)
817 {
818   if (h == NULL)
819   {
820     errno = EINVAL;
821     return GNUNET_SYSERR;
822   }
823
824 #ifdef MINGW
825   DWORD bytesRead;
826
827   if (h->type != GNUNET_PIPE)
828   {
829     if (!ReadFile (h->h, result, len, &bytesRead, NULL))
830     {
831       SetErrnoFromWinError (GetLastError ());
832       return GNUNET_SYSERR;
833     }
834   }
835   else
836   {
837     if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
838     {
839       if (GetLastError () != ERROR_IO_PENDING)
840       {
841         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
842         SetErrnoFromWinError (GetLastError ());
843         return GNUNET_SYSERR;
844       }
845       else
846       {
847         LOG (GNUNET_ERROR_TYPE_DEBUG,
848             "ReadFile() queued a read, cancelling\n");
849         CancelIo (h->h);
850         errno = EAGAIN;
851         return GNUNET_SYSERR;
852       }
853     }
854     LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
855   }
856   return bytesRead;
857 #else
858   int flags;
859   ssize_t ret;
860
861   /* set to non-blocking, read, then set back */
862   flags = fcntl (h->fd, F_GETFL);
863   if (0 == (flags & O_NONBLOCK))
864     fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
865   ret = read (h->fd, result, len);
866   if (0 == (flags & O_NONBLOCK))
867     fcntl (h->fd, F_SETFL, flags);
868   return ret;
869 #endif
870 }
871
872
873 /**
874  * Read the contents of a binary file into a buffer.
875  *
876  * @param fn file name
877  * @param result the buffer to write the result to
878  * @param len the maximum number of bytes to read
879  * @return number of bytes read, GNUNET_SYSERR on failure
880  */
881 ssize_t
882 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
883 {
884   struct GNUNET_DISK_FileHandle *fh;
885   ssize_t ret;
886
887   fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
888   if (!fh)
889     return GNUNET_SYSERR;
890   ret = GNUNET_DISK_file_read (fh, result, len);
891   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
892
893   return ret;
894 }
895
896
897 /**
898  * Write a buffer to a file.
899  * @param h handle to open file
900  * @param buffer the data to write
901  * @param n number of bytes to write
902  * @return number of bytes written on success, GNUNET_SYSERR on error
903  */
904 ssize_t
905 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
906                         const void *buffer, size_t n)
907 {
908   if (h == NULL)
909   {
910     errno = EINVAL;
911     return GNUNET_SYSERR;
912   }
913
914 #ifdef MINGW
915   DWORD bytesWritten;
916
917   if (h->type != GNUNET_PIPE)
918   {
919     if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
920     {
921       SetErrnoFromWinError (GetLastError ());
922       return GNUNET_SYSERR;
923     }
924   }
925   else
926   {
927     LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
928     if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
929     {
930       if (GetLastError () != ERROR_IO_PENDING)
931       {
932         SetErrnoFromWinError (GetLastError ());
933         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
934             GetLastError ());
935         return GNUNET_SYSERR;
936       }
937       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
938       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
939       {
940         SetErrnoFromWinError (GetLastError ());
941         LOG (GNUNET_ERROR_TYPE_DEBUG,
942             "Error getting overlapped result while writing to pipe: %u\n",
943             GetLastError ());
944         return GNUNET_SYSERR;
945       }
946     }
947     else
948     {
949       DWORD ovr;
950       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
951       {
952         LOG (GNUNET_ERROR_TYPE_DEBUG,
953             "Error getting control overlapped result while writing to pipe: %u\n",
954             GetLastError ());
955       }
956       else
957       {
958         LOG (GNUNET_ERROR_TYPE_DEBUG,
959             "Wrote %u bytes (ovr says %u), picking the greatest\n",
960             bytesWritten, ovr);
961       }
962     }
963     if (bytesWritten == 0)
964     {
965       if (n > 0)
966       {
967         LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
968         errno = EAGAIN;
969         return GNUNET_SYSERR;
970       }
971     }
972     LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
973   }
974   return bytesWritten;
975 #else
976   return write (h->fd, buffer, n);
977 #endif
978 }
979
980
981 /**
982  * Write a buffer to a file, blocking, if necessary.
983  * @param h handle to open file
984  * @param buffer the data to write
985  * @param n number of bytes to write
986  * @return number of bytes written on success, GNUNET_SYSERR on error
987  */
988 ssize_t
989 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
990     const void *buffer, size_t n)
991 {
992   if (h == NULL)
993   {
994     errno = EINVAL;
995     return GNUNET_SYSERR;
996   }
997
998 #ifdef MINGW
999   DWORD bytesWritten;
1000   /* We do a non-overlapped write, which is as blocking as it gets */
1001   LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1002   if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1003   {
1004     SetErrnoFromWinError (GetLastError ());
1005     LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1006         GetLastError ());
1007     return GNUNET_SYSERR;
1008   }
1009   if (bytesWritten == 0 && n > 0)
1010   {
1011     LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1012     WaitForSingleObject (h->h, INFINITE);
1013     if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1014     {
1015       SetErrnoFromWinError (GetLastError ());
1016       LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1017           GetLastError ());
1018       return GNUNET_SYSERR;
1019     }
1020   }
1021   LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1022   return bytesWritten;
1023 #else
1024   int flags;
1025   ssize_t ret;
1026
1027   /* set to blocking, write, then set back */
1028   flags = fcntl (h->fd, F_GETFL);
1029   if (0 != (flags & O_NONBLOCK))
1030     fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1031   ret = write (h->fd, buffer, n);
1032   if (0 == (flags & O_NONBLOCK))
1033     fcntl (h->fd, F_SETFL, flags);
1034   return ret;
1035 #endif
1036 }
1037
1038
1039 /**
1040  * Write a buffer to a file.  If the file is longer than the
1041  * number of bytes that will be written, it will be truncated.
1042  *
1043  * @param fn file name
1044  * @param buffer the data to write
1045  * @param n number of bytes to write
1046  * @param mode file permissions
1047  * @return number of bytes written on success, GNUNET_SYSERR on error
1048  */
1049 ssize_t
1050 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1051                       enum GNUNET_DISK_AccessPermissions mode)
1052 {
1053   struct GNUNET_DISK_FileHandle *fh;
1054   ssize_t ret;
1055
1056   fh = GNUNET_DISK_file_open (fn,
1057                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1058                               | GNUNET_DISK_OPEN_CREATE, mode);
1059   if (!fh)
1060     return GNUNET_SYSERR;
1061   ret = GNUNET_DISK_file_write (fh, buffer, n);
1062   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1063   return ret;
1064 }
1065
1066
1067 /**
1068  * Scan a directory for files.
1069  *
1070  * @param dirName the name of the directory
1071  * @param callback the method to call for each file,
1072  *        can be NULL, in that case, we only count
1073  * @param callback_cls closure for callback
1074  * @return the number of files found, GNUNET_SYSERR on error or
1075  *         ieration aborted by callback returning GNUNET_SYSERR
1076  */
1077 int
1078 GNUNET_DISK_directory_scan (const char *dirName,
1079                             GNUNET_FileNameCallback callback,
1080                             void *callback_cls)
1081 {
1082   DIR *dinfo;
1083   struct dirent *finfo;
1084   struct stat istat;
1085   int count = 0;
1086   char *name;
1087   char *dname;
1088   unsigned int name_len;
1089   unsigned int n_size;
1090
1091   GNUNET_assert (dirName != NULL);
1092   dname = GNUNET_STRINGS_filename_expand (dirName);
1093   if (dname == NULL)
1094     return GNUNET_SYSERR;
1095   while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1096     dname[strlen (dname) - 1] = '\0';
1097   if (0 != STAT (dname, &istat))
1098   {
1099     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1100     GNUNET_free (dname);
1101     return GNUNET_SYSERR;
1102   }
1103   if (!S_ISDIR (istat.st_mode))
1104   {
1105     LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1106          dirName);
1107     GNUNET_free (dname);
1108     return GNUNET_SYSERR;
1109   }
1110   errno = 0;
1111   dinfo = OPENDIR (dname);
1112   if ((errno == EACCES) || (dinfo == NULL))
1113   {
1114     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1115     if (dinfo != NULL)
1116       CLOSEDIR (dinfo);
1117     GNUNET_free (dname);
1118     return GNUNET_SYSERR;
1119   }
1120   name_len = 256;
1121   n_size = strlen (dname) + name_len + 2;
1122   name = GNUNET_malloc (n_size);
1123   while ((finfo = READDIR (dinfo)) != NULL)
1124   {
1125     if ((0 == strcmp (finfo->d_name, ".")) ||
1126         (0 == strcmp (finfo->d_name, "..")))
1127       continue;
1128     if (callback != NULL)
1129     {
1130       if (name_len < strlen (finfo->d_name))
1131       {
1132         GNUNET_free (name);
1133         name_len = strlen (finfo->d_name);
1134         n_size = strlen (dname) + name_len + 2;
1135         name = GNUNET_malloc (n_size);
1136       }
1137       /* dname can end in "/" only if dname == "/";
1138        * if dname does not end in "/", we need to add
1139        * a "/" (otherwise, we must not!) */
1140       GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1141                        (strcmp (dname, DIR_SEPARATOR_STR) ==
1142                         0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1143       if (GNUNET_OK != callback (callback_cls, name))
1144       {
1145         CLOSEDIR (dinfo);
1146         GNUNET_free (name);
1147         GNUNET_free (dname);
1148         return GNUNET_SYSERR;
1149       }
1150     }
1151     count++;
1152   }
1153   CLOSEDIR (dinfo);
1154   GNUNET_free (name);
1155   GNUNET_free (dname);
1156   return count;
1157 }
1158
1159
1160 /**
1161  * Opaque handle used for iterating over a directory.
1162  */
1163 struct GNUNET_DISK_DirectoryIterator
1164 {
1165
1166   /**
1167    * Function to call on directory entries.
1168    */
1169   GNUNET_DISK_DirectoryIteratorCallback callback;
1170
1171   /**
1172    * Closure for callback.
1173    */
1174   void *callback_cls;
1175
1176   /**
1177    * Reference to directory.
1178    */
1179   DIR *directory;
1180
1181   /**
1182    * Directory name.
1183    */
1184   char *dirname;
1185
1186   /**
1187    * Next filename to process.
1188    */
1189   char *next_name;
1190
1191   /**
1192    * Our priority.
1193    */
1194   enum GNUNET_SCHEDULER_Priority priority;
1195
1196 };
1197
1198
1199 /**
1200  * Task used by the directory iterator.
1201  */
1202 static void
1203 directory_iterator_task (void *cls,
1204                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1205 {
1206   struct GNUNET_DISK_DirectoryIterator *iter = cls;
1207   char *name;
1208
1209   name = iter->next_name;
1210   GNUNET_assert (name != NULL);
1211   iter->next_name = NULL;
1212   iter->callback (iter->callback_cls, iter, name, iter->dirname);
1213   GNUNET_free (name);
1214 }
1215
1216
1217 /**
1218  * This function must be called during the DiskIteratorCallback
1219  * (exactly once) to schedule the task to process the next
1220  * filename in the directory (if there is one).
1221  *
1222  * @param iter opaque handle for the iterator
1223  * @param can set to GNUNET_YES to terminate the iteration early
1224  * @return GNUNET_YES if iteration will continue,
1225  *         GNUNET_NO if this was the last entry (and iteration is complete),
1226  *         GNUNET_SYSERR if abort was YES
1227  */
1228 int
1229 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1230                                      int can)
1231 {
1232   struct dirent *finfo;
1233
1234   GNUNET_assert (iter->next_name == NULL);
1235   if (can == GNUNET_YES)
1236   {
1237     CLOSEDIR (iter->directory);
1238     GNUNET_free (iter->dirname);
1239     GNUNET_free (iter);
1240     return GNUNET_SYSERR;
1241   }
1242   while (NULL != (finfo = READDIR (iter->directory)))
1243   {
1244     if ((0 == strcmp (finfo->d_name, ".")) ||
1245         (0 == strcmp (finfo->d_name, "..")))
1246       continue;
1247     GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1248                      DIR_SEPARATOR_STR, finfo->d_name);
1249     break;
1250   }
1251   if (finfo == NULL)
1252   {
1253     GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1254     return GNUNET_NO;
1255   }
1256   GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1257                                       iter);
1258   return GNUNET_YES;
1259 }
1260
1261
1262 /**
1263  * Scan a directory for files using the scheduler to run a task for
1264  * each entry.  The name of the directory must be expanded first (!).
1265  * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1266  * may provide a simpler API.
1267  *
1268  * @param prio priority to use
1269  * @param dirName the name of the directory
1270  * @param callback the method to call for each file
1271  * @param callback_cls closure for callback
1272  * @return GNUNET_YES if directory is not empty and 'callback'
1273  *         will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1274  */
1275 int
1276 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1277                                       const char *dirName,
1278                                       GNUNET_DISK_DirectoryIteratorCallback
1279                                       callback, void *callback_cls)
1280 {
1281   struct GNUNET_DISK_DirectoryIterator *di;
1282
1283   di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1284   di->callback = callback;
1285   di->callback_cls = callback_cls;
1286   di->directory = OPENDIR (dirName);
1287   if (di->directory == NULL)
1288   {
1289     GNUNET_free (di);
1290     callback (callback_cls, NULL, NULL, NULL);
1291     return GNUNET_SYSERR;
1292   }
1293   di->dirname = GNUNET_strdup (dirName);
1294   di->priority = prio;
1295   return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1296 }
1297
1298
1299 /**
1300  * Function that removes the given directory by calling
1301  * "GNUNET_DISK_directory_remove".
1302  *
1303  * @param unused not used
1304  * @param fn directory to remove
1305  * @return GNUNET_OK
1306  */
1307 static int
1308 remove_helper (void *unused, const char *fn)
1309 {
1310   (void) GNUNET_DISK_directory_remove (fn);
1311   return GNUNET_OK;
1312 }
1313
1314
1315 /**
1316  * Remove all files in a directory (rm -rf). Call with
1317  * caution.
1318  *
1319  *
1320  * @param fileName the file to remove
1321  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1322  */
1323 int
1324 GNUNET_DISK_directory_remove (const char *fileName)
1325 {
1326   struct stat istat;
1327
1328   if (0 != LSTAT (fileName, &istat))
1329     return GNUNET_NO;           /* file may not exist... */
1330   CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR);
1331   if (UNLINK (fileName) == 0)
1332     return GNUNET_OK;
1333   if ((errno != EISDIR) &&
1334       /* EISDIR is not sufficient in all cases, e.g.
1335        * sticky /tmp directory may result in EPERM on BSD.
1336        * So we also explicitly check "isDirectory" */
1337       (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
1338   {
1339     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1340     return GNUNET_SYSERR;
1341   }
1342   if (GNUNET_SYSERR ==
1343       GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL))
1344     return GNUNET_SYSERR;
1345   if (0 != RMDIR (fileName))
1346   {
1347     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1348     return GNUNET_SYSERR;
1349   }
1350   return GNUNET_OK;
1351 }
1352
1353
1354 /**
1355  * Copy a file.
1356  *
1357  * @param src file to copy
1358  * @param dst destination file name
1359  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1360  */
1361 int
1362 GNUNET_DISK_file_copy (const char *src, const char *dst)
1363 {
1364   char *buf;
1365   uint64_t pos;
1366   uint64_t size;
1367   size_t len;
1368   struct GNUNET_DISK_FileHandle *in;
1369   struct GNUNET_DISK_FileHandle *out;
1370
1371   if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1372     return GNUNET_SYSERR;
1373   pos = 0;
1374   in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1375                               GNUNET_DISK_PERM_NONE);
1376   if (!in)
1377     return GNUNET_SYSERR;
1378   out =
1379       GNUNET_DISK_file_open (dst,
1380                              GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1381                              GNUNET_DISK_OPEN_FAILIFEXISTS,
1382                              GNUNET_DISK_PERM_USER_READ |
1383                              GNUNET_DISK_PERM_USER_WRITE |
1384                              GNUNET_DISK_PERM_GROUP_READ |
1385                              GNUNET_DISK_PERM_GROUP_WRITE);
1386   if (!out)
1387   {
1388     GNUNET_DISK_file_close (in);
1389     return GNUNET_SYSERR;
1390   }
1391   buf = GNUNET_malloc (COPY_BLK_SIZE);
1392   while (pos < size)
1393   {
1394     len = COPY_BLK_SIZE;
1395     if (len > size - pos)
1396       len = size - pos;
1397     if (len != GNUNET_DISK_file_read (in, buf, len))
1398       goto FAIL;
1399     if (len != GNUNET_DISK_file_write (out, buf, len))
1400       goto FAIL;
1401     pos += len;
1402   }
1403   GNUNET_free (buf);
1404   GNUNET_DISK_file_close (in);
1405   GNUNET_DISK_file_close (out);
1406   return GNUNET_OK;
1407 FAIL:
1408   GNUNET_free (buf);
1409   GNUNET_DISK_file_close (in);
1410   GNUNET_DISK_file_close (out);
1411   return GNUNET_SYSERR;
1412 }
1413
1414
1415 /**
1416  * @brief Removes special characters as ':' from a filename.
1417  * @param fn the filename to canonicalize
1418  */
1419 void
1420 GNUNET_DISK_filename_canonicalize (char *fn)
1421 {
1422   char *idx;
1423   char c;
1424
1425   idx = fn;
1426   while (*idx)
1427   {
1428     c = *idx;
1429
1430     if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1431         c == '<' || c == '>' || c == '|')
1432     {
1433       *idx = '_';
1434     }
1435
1436     idx++;
1437   }
1438 }
1439
1440
1441
1442 /**
1443  * @brief Change owner of a file
1444  *
1445  * @param filename name of file to change the owner of
1446  * @param user name of the new owner
1447  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1448  */
1449 int
1450 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1451 {
1452 #ifndef MINGW
1453   struct passwd *pws;
1454
1455   pws = getpwnam (user);
1456   if (pws == NULL)
1457   {
1458     LOG (GNUNET_ERROR_TYPE_ERROR,
1459          _("Cannot obtain information about user `%s': %s\n"), user,
1460          STRERROR (errno));
1461     return GNUNET_SYSERR;
1462   }
1463   if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1464     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1465 #endif
1466   return GNUNET_OK;
1467 }
1468
1469
1470 /**
1471  * Lock a part of a file
1472  * @param fh file handle
1473  * @param lockStart absolute position from where to lock
1474  * @param lockEnd absolute position until where to lock
1475  * @param excl GNUNET_YES for an exclusive lock
1476  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1477  */
1478 int
1479 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1480                        OFF_T lockEnd, int excl)
1481 {
1482   if (fh == NULL)
1483   {
1484     errno = EINVAL;
1485     return GNUNET_SYSERR;
1486   }
1487
1488 #ifndef MINGW
1489   struct flock fl;
1490
1491   memset (&fl, 0, sizeof (struct flock));
1492   fl.l_type = excl ? F_WRLCK : F_RDLCK;
1493   fl.l_whence = SEEK_SET;
1494   fl.l_start = lockStart;
1495   fl.l_len = lockEnd;
1496
1497   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1498 #else
1499   OVERLAPPED o;
1500   OFF_T diff = lockEnd - lockStart;
1501   DWORD diff_low, diff_high;
1502   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1503   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1504
1505   memset (&o, 0, sizeof (OVERLAPPED));
1506   o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1507   o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1508
1509   if (!LockFileEx
1510       (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1511        0, diff_low, diff_high, &o))
1512   {
1513     SetErrnoFromWinError (GetLastError ());
1514     return GNUNET_SYSERR;
1515   }
1516
1517   return GNUNET_OK;
1518 #endif
1519 }
1520
1521
1522 /**
1523  * Unlock a part of a file
1524  * @param fh file handle
1525  * @param unlockStart absolute position from where to unlock
1526  * @param unlockEnd absolute position until where to unlock
1527  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1528  */
1529 int
1530 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1531                          OFF_T unlockEnd)
1532 {
1533   if (fh == NULL)
1534   {
1535     errno = EINVAL;
1536     return GNUNET_SYSERR;
1537   }
1538
1539 #ifndef MINGW
1540   struct flock fl;
1541
1542   memset (&fl, 0, sizeof (struct flock));
1543   fl.l_type = F_UNLCK;
1544   fl.l_whence = SEEK_SET;
1545   fl.l_start = unlockStart;
1546   fl.l_len = unlockEnd;
1547
1548   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1549 #else
1550   OVERLAPPED o;
1551   OFF_T diff = unlockEnd - unlockStart;
1552   DWORD diff_low, diff_high;
1553   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1554   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1555
1556   memset (&o, 0, sizeof (OVERLAPPED));
1557   o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1558   o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1559
1560   if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1561   {
1562     SetErrnoFromWinError (GetLastError ());
1563     return GNUNET_SYSERR;
1564   }
1565
1566   return GNUNET_OK;
1567 #endif
1568 }
1569
1570
1571 /**
1572  * Open a file.  Note that the access permissions will only be
1573  * used if a new file is created and if the underlying operating
1574  * system supports the given permissions.
1575  *
1576  * @param fn file name to be opened
1577  * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1578  * @param perm permissions for the newly created file, use
1579  *             GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1580  *             call (because of flags)
1581  * @return IO handle on success, NULL on error
1582  */
1583 struct GNUNET_DISK_FileHandle *
1584 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1585                        enum GNUNET_DISK_AccessPermissions perm)
1586 {
1587   char *expfn;
1588   struct GNUNET_DISK_FileHandle *ret;
1589
1590 #ifdef MINGW
1591   DWORD access;
1592   DWORD disp;
1593   HANDLE h;
1594   wchar_t wexpfn[MAX_PATH + 1];
1595 #else
1596   int oflags;
1597   int mode;
1598   int fd;
1599 #endif
1600
1601   expfn = GNUNET_STRINGS_filename_expand (fn);
1602   if (NULL == expfn)
1603     return NULL;
1604 #ifndef MINGW
1605   mode = 0;
1606   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1607     oflags = O_RDWR;            /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1608   else if (flags & GNUNET_DISK_OPEN_READ)
1609     oflags = O_RDONLY;
1610   else if (flags & GNUNET_DISK_OPEN_WRITE)
1611     oflags = O_WRONLY;
1612   else
1613   {
1614     GNUNET_break (0);
1615     GNUNET_free (expfn);
1616     return NULL;
1617   }
1618   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1619     oflags |= (O_CREAT | O_EXCL);
1620   if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1621     oflags |= O_TRUNC;
1622   if (flags & GNUNET_DISK_OPEN_APPEND)
1623     oflags |= O_APPEND;
1624   if (flags & GNUNET_DISK_OPEN_CREATE)
1625   {
1626     (void) GNUNET_DISK_directory_create_for_file (expfn);
1627     oflags |= O_CREAT;
1628     mode = translate_unix_perms (perm);
1629   }
1630
1631   fd = open (expfn, oflags | O_LARGEFILE, mode);
1632   if (fd == -1)
1633   {
1634     if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1635       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1636     else
1637       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1638     GNUNET_free (expfn);
1639     return NULL;
1640   }
1641 #else
1642   access = 0;
1643   disp = OPEN_ALWAYS;
1644
1645   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1646     access = FILE_READ_DATA | FILE_WRITE_DATA;
1647   else if (flags & GNUNET_DISK_OPEN_READ)
1648     access = FILE_READ_DATA;
1649   else if (flags & GNUNET_DISK_OPEN_WRITE)
1650     access = FILE_WRITE_DATA;
1651
1652   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1653   {
1654     disp = CREATE_NEW;
1655   }
1656   else if (flags & GNUNET_DISK_OPEN_CREATE)
1657   {
1658     (void) GNUNET_DISK_directory_create_for_file (expfn);
1659     if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1660       disp = CREATE_ALWAYS;
1661     else
1662       disp = OPEN_ALWAYS;
1663   }
1664   else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1665   {
1666     disp = TRUNCATE_EXISTING;
1667   }
1668   else
1669   {
1670     disp = OPEN_EXISTING;
1671   }
1672
1673   if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1674     h = CreateFileW (wexpfn, access,
1675                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1676                     disp, FILE_ATTRIBUTE_NORMAL, NULL);
1677   else
1678     h = INVALID_HANDLE_VALUE;
1679   if (h == INVALID_HANDLE_VALUE)
1680   {
1681     SetErrnoFromWinError (GetLastError ());
1682     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1683     GNUNET_free (expfn);
1684     return NULL;
1685   }
1686
1687   if (flags & GNUNET_DISK_OPEN_APPEND)
1688     if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1689     {
1690       SetErrnoFromWinError (GetLastError ());
1691       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1692       CloseHandle (h);
1693       GNUNET_free (expfn);
1694       return NULL;
1695     }
1696 #endif
1697
1698   ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1699 #ifdef MINGW
1700   ret->h = h;
1701   ret->type = GNUNET_DISK_FILE;
1702 #else
1703   ret->fd = fd;
1704 #endif
1705   GNUNET_free (expfn);
1706   return ret;
1707 }
1708
1709
1710 /**
1711  * Close an open file
1712  * @param h file handle
1713  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1714  */
1715 int
1716 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1717 {
1718   if (h == NULL)
1719   {
1720     errno = EINVAL;
1721     return GNUNET_SYSERR;
1722   }
1723
1724 #if MINGW
1725   if (!CloseHandle (h->h))
1726   {
1727     SetErrnoFromWinError (GetLastError ());
1728     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1729     GNUNET_free (h->oOverlapRead);
1730     GNUNET_free (h->oOverlapWrite);
1731     GNUNET_free (h);
1732     return GNUNET_SYSERR;
1733   }
1734 #else
1735   if (close (h->fd) != 0)
1736   {
1737     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1738     GNUNET_free (h);
1739     return GNUNET_SYSERR;
1740   }
1741 #endif
1742   GNUNET_free (h);
1743   return GNUNET_OK;
1744 }
1745
1746
1747 /**
1748  * Construct full path to a file inside of the private
1749  * directory used by GNUnet.  Also creates the corresponding
1750  * directory.  If the resulting name is supposed to be
1751  * a directory, end the last argument in '/' (or pass
1752  * DIR_SEPARATOR_STR as the last argument before NULL).
1753  *
1754  * @param cfg configuration to use (determines HOME)
1755  * @param serviceName name of the service
1756  * @param ... is NULL-terminated list of
1757  *                path components to append to the
1758  *                private directory name.
1759  * @return the constructed filename
1760  */
1761 char *
1762 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1763                                const char *serviceName, ...)
1764 {
1765   const char *c;
1766   char *pfx;
1767   char *ret;
1768   va_list ap;
1769   unsigned int needed;
1770
1771   if (GNUNET_OK !=
1772       GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1773     return NULL;
1774   if (pfx == NULL)
1775   {
1776     LOG (GNUNET_ERROR_TYPE_WARNING,
1777          _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1778          serviceName);
1779     return NULL;
1780   }
1781   needed = strlen (pfx) + 2;
1782   if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1783     needed++;
1784   va_start (ap, serviceName);
1785   while (1)
1786   {
1787     c = va_arg (ap, const char *);
1788
1789     if (c == NULL)
1790       break;
1791     needed += strlen (c);
1792     if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1793       needed++;
1794   }
1795   va_end (ap);
1796   ret = GNUNET_malloc (needed);
1797   strcpy (ret, pfx);
1798   GNUNET_free (pfx);
1799   va_start (ap, serviceName);
1800   while (1)
1801   {
1802     c = va_arg (ap, const char *);
1803
1804     if (c == NULL)
1805       break;
1806     if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1807       strcat (ret, DIR_SEPARATOR_STR);
1808     strcat (ret, c);
1809   }
1810   va_end (ap);
1811   if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1812     (void) GNUNET_DISK_directory_create_for_file (ret);
1813   else
1814     (void) GNUNET_DISK_directory_create (ret);
1815   return ret;
1816 }
1817
1818
1819 /**
1820  * Handle for a memory-mapping operation.
1821  */
1822 struct GNUNET_DISK_MapHandle
1823 {
1824   /**
1825    * Address where the map is in memory.
1826    */
1827   void *addr;
1828
1829 #ifdef MINGW
1830   /**
1831    * Underlying OS handle.
1832    */
1833   HANDLE h;
1834 #else
1835   /**
1836    * Number of bytes mapped.
1837    */
1838   size_t len;
1839 #endif
1840 };
1841
1842
1843 #ifndef MAP_FAILED
1844 #define MAP_FAILED ((void *) -1)
1845 #endif
1846
1847 /**
1848  * Map a file into memory
1849  *
1850  * @param h open file handle
1851  * @param m handle to the new mapping
1852  * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1853  * @param len size of the mapping
1854  * @return pointer to the mapped memory region, NULL on failure
1855  */
1856 void *
1857 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1858                       struct GNUNET_DISK_MapHandle **m,
1859                       enum GNUNET_DISK_MapType access, size_t len)
1860 {
1861   if (h == NULL)
1862   {
1863     errno = EINVAL;
1864     return NULL;
1865   }
1866
1867 #ifdef MINGW
1868   DWORD mapAccess, protect;
1869
1870   if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1871       (access & GNUNET_DISK_MAP_TYPE_WRITE))
1872   {
1873     protect = PAGE_READWRITE;
1874     mapAccess = FILE_MAP_ALL_ACCESS;
1875   }
1876   else if (access & GNUNET_DISK_MAP_TYPE_READ)
1877   {
1878     protect = PAGE_READONLY;
1879     mapAccess = FILE_MAP_READ;
1880   }
1881   else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1882   {
1883     protect = PAGE_READWRITE;
1884     mapAccess = FILE_MAP_WRITE;
1885   }
1886   else
1887   {
1888     GNUNET_break (0);
1889     return NULL;
1890   }
1891
1892   *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1893   (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1894   if ((*m)->h == INVALID_HANDLE_VALUE)
1895   {
1896     SetErrnoFromWinError (GetLastError ());
1897     GNUNET_free (*m);
1898     return NULL;
1899   }
1900
1901   (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1902   if (!(*m)->addr)
1903   {
1904     SetErrnoFromWinError (GetLastError ());
1905     CloseHandle ((*m)->h);
1906     GNUNET_free (*m);
1907   }
1908
1909   return (*m)->addr;
1910 #else
1911   int prot;
1912
1913   prot = 0;
1914   if (access & GNUNET_DISK_MAP_TYPE_READ)
1915     prot = PROT_READ;
1916   if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1917     prot |= PROT_WRITE;
1918   *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1919   (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1920   GNUNET_assert (NULL != (*m)->addr);
1921   if (MAP_FAILED == (*m)->addr)
1922   {
1923     GNUNET_free (*m);
1924     return NULL;
1925   }
1926   (*m)->len = len;
1927   return (*m)->addr;
1928 #endif
1929 }
1930
1931 /**
1932  * Unmap a file
1933  * @param h mapping handle
1934  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1935  */
1936 int
1937 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1938 {
1939   int ret;
1940
1941   if (h == NULL)
1942   {
1943     errno = EINVAL;
1944     return GNUNET_SYSERR;
1945   }
1946
1947 #ifdef MINGW
1948   ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
1949   if (ret != GNUNET_OK)
1950     SetErrnoFromWinError (GetLastError ());
1951   if (!CloseHandle (h->h) && (ret == GNUNET_OK))
1952   {
1953     ret = GNUNET_SYSERR;
1954     SetErrnoFromWinError (GetLastError ());
1955   }
1956 #else
1957   ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1958 #endif
1959   GNUNET_free (h);
1960   return ret;
1961 }
1962
1963
1964 /**
1965  * Write file changes to disk
1966  * @param h handle to an open file
1967  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1968  */
1969 int
1970 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1971 {
1972   if (h == NULL)
1973   {
1974     errno = EINVAL;
1975     return GNUNET_SYSERR;
1976   }
1977
1978 #ifdef MINGW
1979   int ret;
1980
1981   ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1982   if (ret != GNUNET_OK)
1983     SetErrnoFromWinError (GetLastError ());
1984   return ret;
1985 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
1986   return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1987 #else
1988   return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1989 #endif
1990 }
1991
1992
1993 #if WINDOWS
1994 /* Copyright Bob Byrnes  <byrnes <at> curl.com>
1995    http://permalink.gmane.org/gmane.os.cygwin.patches/2121
1996 */
1997 /* Create a pipe, and return handles to the read and write ends,
1998    just like CreatePipe, but ensure that the write end permits
1999    FILE_READ_ATTRIBUTES access, on later versions of win32 where
2000    this is supported.  This access is needed by NtQueryInformationFile,
2001    which is used to implement select and nonblocking writes.
2002    Note that the return value is either NO_ERROR or GetLastError,
2003    unlike CreatePipe, which returns a bool for success or failure.  */
2004 static int
2005 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2006                         LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2007                         DWORD dwReadMode, DWORD dwWriteMode)
2008 {
2009   /* Default to error. */
2010   *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2011
2012   HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
2013
2014   /* Ensure that there is enough pipe buffer space for atomic writes.  */
2015   if (psize < PIPE_BUF)
2016     psize = PIPE_BUF;
2017
2018   char pipename[MAX_PATH];
2019
2020   /* Retry CreateNamedPipe as long as the pipe name is in use.
2021    * Retrying will probably never be necessary, but we want
2022    * to be as robust as possible.  */
2023   while (1)
2024   {
2025     static volatile LONG pipe_unique_id;
2026
2027     snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2028               getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2029     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2030          pipename, psize);
2031     /* Use CreateNamedPipe instead of CreatePipe, because the latter
2032      * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2033      * access, on versions of win32 earlier than WinXP SP2.
2034      * CreatePipe also stupidly creates a full duplex pipe, which is
2035      * a waste, since only a single direction is actually used.
2036      * It's important to only allow a single instance, to ensure that
2037      * the pipe was not created earlier by some other process, even if
2038      * the pid has been reused.  We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
2039      * because that is only available for Win2k SP2 and WinXP.  */
2040     read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,   /* max instances */
2041                                   psize,        /* output buffer size */
2042                                   psize,        /* input buffer size */
2043                                   NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2044
2045     if (read_pipe != INVALID_HANDLE_VALUE)
2046     {
2047       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2048       break;
2049     }
2050
2051     DWORD err = GetLastError ();
2052
2053     switch (err)
2054     {
2055     case ERROR_PIPE_BUSY:
2056       /* The pipe is already open with compatible parameters.
2057        * Pick a new name and retry.  */
2058       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2059       continue;
2060     case ERROR_ACCESS_DENIED:
2061       /* The pipe is already open with incompatible parameters.
2062        * Pick a new name and retry.  */
2063       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2064       continue;
2065     case ERROR_CALL_NOT_IMPLEMENTED:
2066       /* We are on an older Win9x platform without named pipes.
2067        * Return an anonymous pipe as the best approximation.  */
2068       LOG (GNUNET_ERROR_TYPE_DEBUG,
2069            "CreateNamedPipe not implemented, resorting to "
2070            "CreatePipe: size = %lu\n", psize);
2071       if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2072       {
2073         LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2074              *read_pipe_ptr,
2075              *write_pipe_ptr);
2076         return GNUNET_OK;
2077       }
2078       err = GetLastError ();
2079       LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2080       return err;
2081     default:
2082       LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2083       return err;
2084     }
2085     /* NOTREACHED */
2086   }
2087   LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2088
2089   /* Open the named pipe for writing.
2090    * Be sure to permit FILE_READ_ATTRIBUTES access.  */
2091   write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0,  /* share mode */
2092                             sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2093                             0); /* handle to template file */
2094
2095   if (write_pipe == INVALID_HANDLE_VALUE)
2096   {
2097     /* Failure. */
2098     DWORD err = GetLastError ();
2099
2100     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2101     CloseHandle (read_pipe);
2102     return err;
2103   }
2104   LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2105   /* Success. */
2106   *read_pipe_ptr = read_pipe;
2107   *write_pipe_ptr = write_pipe;
2108   return GNUNET_OK;
2109 }
2110 #endif
2111
2112
2113 /**
2114  * Creates an interprocess channel
2115  *
2116  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2117  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2118  * @param inherit_read inherit the parent processes stdin (only for windows)
2119  * @param inherit_write inherit the parent processes stdout (only for windows)
2120  * @return handle to the new pipe, NULL on error
2121  */
2122 struct GNUNET_DISK_PipeHandle *
2123 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2124 {
2125 #ifndef MINGW
2126   int fd[2];
2127   int ret;
2128   int eno;
2129
2130   ret = pipe (fd);
2131   if (ret == -1)
2132   {
2133     eno = errno;
2134     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2135     errno = eno;
2136     return NULL;
2137   }
2138   return GNUNET_DISK_pipe_from_fd (blocking_read,
2139                                    blocking_write,
2140                                    fd);
2141 #else
2142   struct GNUNET_DISK_PipeHandle *p;
2143   struct GNUNET_DISK_FileHandle *fds;
2144   BOOL ret;
2145   HANDLE tmp_handle;
2146   
2147
2148   p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2149                      2 * sizeof (struct GNUNET_DISK_FileHandle));
2150   fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2151   p->fd[0] = &fds[0];
2152   p->fd[1] = &fds[1];
2153
2154   /* All pipes are overlapped. If you want them to block - just
2155    * call WriteFile() and ReadFile() with NULL overlapped pointer.
2156    */
2157   ret =
2158       create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2159                               FILE_FLAG_OVERLAPPED,
2160                               FILE_FLAG_OVERLAPPED);
2161   if (!ret)
2162   {
2163     GNUNET_free (p);
2164     SetErrnoFromWinError (GetLastError ());
2165     return NULL;
2166   }
2167   if (!DuplicateHandle
2168       (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2169        inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2170   {
2171     SetErrnoFromWinError (GetLastError ());
2172     CloseHandle (p->fd[0]->h);
2173     CloseHandle (p->fd[1]->h);
2174     GNUNET_free (p);
2175     return NULL;
2176   }
2177   CloseHandle (p->fd[0]->h);
2178   p->fd[0]->h = tmp_handle;
2179
2180   if (!DuplicateHandle
2181       (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2182        inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2183   {
2184     SetErrnoFromWinError (GetLastError ());
2185     CloseHandle (p->fd[0]->h);
2186     CloseHandle (p->fd[1]->h);
2187     GNUNET_free (p);
2188     return NULL;
2189   }
2190   CloseHandle (p->fd[1]->h);
2191   p->fd[1]->h = tmp_handle;
2192
2193   p->fd[0]->type = GNUNET_PIPE;
2194   p->fd[1]->type = GNUNET_PIPE;
2195
2196   p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2197   p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2198   p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2199   p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2200
2201   p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2202   p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2203
2204   p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2205   p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2206
2207   return p;
2208 #endif
2209 }
2210
2211
2212 /**
2213  * Creates a pipe object from a couple of file descriptors.
2214  * Useful for wrapping existing pipe FDs.
2215  *
2216  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2217  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2218  * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2219  *
2220  * @return handle to the new pipe, NULL on error
2221  */
2222 struct GNUNET_DISK_PipeHandle *
2223 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2224 {
2225   struct GNUNET_DISK_PipeHandle *p;
2226   struct GNUNET_DISK_FileHandle *fds;
2227
2228   p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2229                      2 * sizeof (struct GNUNET_DISK_FileHandle));
2230   fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2231   p->fd[0] = &fds[0];
2232   p->fd[1] = &fds[1];
2233 #ifndef MINGW
2234   int ret;
2235   int flags;
2236   int eno = 0; /* make gcc happy */
2237
2238   p->fd[0]->fd = fd[0];
2239   p->fd[1]->fd = fd[1];
2240   ret = 0;
2241   if (fd[0] >= 0)
2242   {
2243     if (!blocking_read)
2244     {
2245       flags = fcntl (fd[0], F_GETFL);
2246       flags |= O_NONBLOCK;
2247       if (0 > fcntl (fd[0], F_SETFL, flags))
2248       {
2249         ret = -1;
2250         eno = errno;
2251       }
2252     }
2253     flags = fcntl (fd[0], F_GETFD);
2254     flags |= FD_CLOEXEC;
2255     if (0 > fcntl (fd[0], F_SETFD, flags))
2256     {
2257       ret = -1;
2258       eno = errno;
2259     }
2260   }
2261
2262   if (fd[1] >= 0)
2263   {
2264     if (!blocking_write)
2265     {
2266       flags = fcntl (fd[1], F_GETFL);
2267       flags |= O_NONBLOCK;
2268       if (0 > fcntl (fd[1], F_SETFL, flags))
2269       {
2270         ret = -1;
2271         eno = errno;
2272       }
2273     }
2274     flags = fcntl (fd[1], F_GETFD);
2275     flags |= FD_CLOEXEC;
2276     if (0 > fcntl (fd[1], F_SETFD, flags))
2277     {
2278       ret = -1;
2279       eno = errno;
2280     }
2281   }
2282   if (ret == -1)
2283   {
2284     errno = eno;
2285     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2286     if (p->fd[0]->fd >= 0)
2287       GNUNET_break (0 == close (p->fd[0]->fd));
2288     if (p->fd[1]->fd >= 0)
2289       GNUNET_break (0 == close (p->fd[1]->fd));
2290     GNUNET_free (p);
2291     errno = eno;
2292     return NULL;
2293   }
2294 #else
2295   if (fd[0] >= 0)
2296     p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2297   else
2298     p->fd[0]->h = INVALID_HANDLE_VALUE;
2299   if (fd[1] >= 0)
2300     p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2301   else
2302     p->fd[1]->h = INVALID_HANDLE_VALUE;
2303
2304   if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2305   {
2306     p->fd[0]->type = GNUNET_PIPE;
2307     p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2308     p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2309     p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2310     p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2311   }
2312
2313   if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2314   {
2315     p->fd[1]->type = GNUNET_PIPE;
2316     p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2317     p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2318     p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2319     p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2320   }
2321 #endif
2322   return p;
2323 }
2324
2325
2326 /**
2327  * Closes an interprocess channel
2328  *
2329  * @param p pipe to close
2330  * @param end which end of the pipe to close
2331  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2332  */
2333 int
2334 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2335                             enum GNUNET_DISK_PipeEnd end)
2336 {
2337   int ret = GNUNET_OK;
2338   int save;
2339
2340 #ifdef MINGW
2341   if (end == GNUNET_DISK_PIPE_END_READ)
2342   {
2343     if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2344     {
2345       if (!CloseHandle (p->fd[0]->h))
2346       {
2347         SetErrnoFromWinError (GetLastError ());
2348         ret = GNUNET_SYSERR;
2349       }
2350       GNUNET_free (p->fd[0]->oOverlapRead);
2351       GNUNET_free (p->fd[0]->oOverlapWrite);
2352       p->fd[0]->h = INVALID_HANDLE_VALUE;
2353     }
2354   }
2355   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2356   {
2357     if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2358     {
2359       if (!CloseHandle (p->fd[1]->h))
2360       {
2361         SetErrnoFromWinError (GetLastError ());
2362         ret = GNUNET_SYSERR;
2363       }
2364       GNUNET_free (p->fd[1]->oOverlapRead);
2365       GNUNET_free (p->fd[1]->oOverlapWrite);
2366       p->fd[1]->h = INVALID_HANDLE_VALUE;
2367     }
2368   }
2369   save = errno;
2370 #else
2371   save = 0;
2372   if (end == GNUNET_DISK_PIPE_END_READ)
2373   {
2374     if (0 != close (p->fd[0]->fd))
2375     {
2376       ret = GNUNET_SYSERR;
2377       save = errno;
2378     }
2379     p->fd[0]->fd = -1;
2380   }
2381   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2382   {
2383     if (0 != close (p->fd[1]->fd))
2384     {
2385       ret = GNUNET_SYSERR;
2386       save = errno;
2387     }
2388     p->fd[1]->fd = -1;
2389   }
2390 #endif
2391   errno = save;
2392   return ret;
2393 }
2394
2395
2396 /**
2397  * Closes an interprocess channel
2398  *
2399  * @param p pipe to close
2400  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2401  */
2402 int
2403 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2404 {
2405   int ret = GNUNET_OK;
2406   int save;
2407
2408 #ifdef MINGW
2409   if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2410   {
2411     if (!CloseHandle (p->fd[0]->h))
2412     {
2413       SetErrnoFromWinError (GetLastError ());
2414       ret = GNUNET_SYSERR;
2415     }
2416     GNUNET_free (p->fd[0]->oOverlapRead);
2417     GNUNET_free (p->fd[0]->oOverlapWrite);
2418   }
2419   if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2420   {
2421     if (!CloseHandle (p->fd[1]->h))
2422     {
2423       SetErrnoFromWinError (GetLastError ());
2424       ret = GNUNET_SYSERR;
2425     }
2426     GNUNET_free (p->fd[1]->oOverlapRead);
2427     GNUNET_free (p->fd[1]->oOverlapWrite);
2428   }
2429   save = errno;
2430 #else
2431   save = 0;
2432   if (p->fd[0]->fd != -1)
2433   {
2434     if (0 != close (p->fd[0]->fd))
2435     {
2436       ret = GNUNET_SYSERR;
2437       save = errno;
2438     }
2439   }
2440
2441   if (p->fd[1]->fd != -1)
2442   {
2443     if (0 != close (p->fd[1]->fd))
2444     {
2445       ret = GNUNET_SYSERR;
2446       save = errno;
2447     }
2448   }
2449 #endif
2450   GNUNET_free (p);
2451   errno = save;
2452   return ret;
2453 }
2454
2455
2456 /**
2457  * Get the handle to a particular pipe end
2458  *
2459  * @param p pipe
2460  * @param n end to access
2461  * @return handle for the respective end
2462  */
2463 const struct GNUNET_DISK_FileHandle *
2464 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2465                          enum GNUNET_DISK_PipeEnd n)
2466 {
2467   switch (n)
2468   {
2469   case GNUNET_DISK_PIPE_END_READ:
2470   case GNUNET_DISK_PIPE_END_WRITE:
2471     return p->fd[n];
2472   default:
2473     GNUNET_break (0);
2474     return NULL;
2475   }
2476 }
2477
2478
2479 /**
2480  * Retrieve OS file handle
2481  * @internal
2482  * @param fh GNUnet file descriptor
2483  * @param dst destination buffer
2484  * @param dst_len length of dst
2485  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2486  */
2487 int
2488 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2489                                    void *dst, size_t dst_len)
2490 {
2491 #ifdef MINGW
2492   if (dst_len < sizeof (HANDLE))
2493     return GNUNET_SYSERR;
2494   *((HANDLE *) dst) = fh->h;
2495 #else
2496   if (dst_len < sizeof (int))
2497     return GNUNET_SYSERR;
2498   *((int *) dst) = fh->fd;
2499 #endif
2500
2501   return GNUNET_OK;
2502 }
2503
2504 /* end of disk.c */