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