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