add GNUNET_CONFIGURATION_get_data from Taler
[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,
943          "Read %u bytes\n",
944          bytes_read);
945   }
946   else
947   {
948     bytes_read = 0;
949   }
950   return bytes_read;
951 #else
952   int flags;
953   ssize_t ret;
954
955   /* set to non-blocking, read, then set back */
956   flags = fcntl (h->fd, F_GETFL);
957   if (0 == (flags & O_NONBLOCK))
958     (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
959   ret = read (h->fd, result, len);
960   if (0 == (flags & O_NONBLOCK))
961     {
962       int eno = errno;
963       (void) fcntl (h->fd, F_SETFL, flags);
964       errno = eno;
965     }
966   return ret;
967 #endif
968 }
969
970
971 /**
972  * Read the contents of a binary file into a buffer.
973  *
974  * @param fn file name
975  * @param result the buffer to write the result to
976  * @param len the maximum number of bytes to read
977  * @return number of bytes read, #GNUNET_SYSERR on failure
978  */
979 ssize_t
980 GNUNET_DISK_fn_read (const char *fn,
981                      void *result,
982                      size_t len)
983 {
984   struct GNUNET_DISK_FileHandle *fh;
985   ssize_t ret;
986
987   fh = GNUNET_DISK_file_open (fn,
988                               GNUNET_DISK_OPEN_READ,
989                               GNUNET_DISK_PERM_NONE);
990   if (NULL == fh)
991     return GNUNET_SYSERR;
992   ret = GNUNET_DISK_file_read (fh, result, len);
993   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
994
995   return ret;
996 }
997
998
999 /**
1000  * Write a buffer to a file.
1001  *
1002  * @param h handle to open file
1003  * @param buffer the data to write
1004  * @param n number of bytes to write
1005  * @return number of bytes written on success, #GNUNET_SYSERR on error
1006  */
1007 ssize_t
1008 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
1009                         const void *buffer, size_t n)
1010 {
1011   if (NULL == h)
1012   {
1013     errno = EINVAL;
1014     return GNUNET_SYSERR;
1015   }
1016
1017 #ifdef MINGW
1018   DWORD bytes_written;
1019
1020   if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
1021   {
1022     if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1023     {
1024       SetErrnoFromWinError (GetLastError ());
1025       return GNUNET_SYSERR;
1026     }
1027   }
1028   else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1029   {
1030     LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
1031     if (!WriteFile (h->h, buffer, n, &bytes_written, h->oOverlapWrite))
1032     {
1033       if (GetLastError () != ERROR_IO_PENDING)
1034       {
1035         SetErrnoFromWinError (GetLastError ());
1036         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1037             GetLastError ());
1038         return GNUNET_SYSERR;
1039       }
1040       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
1041       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytes_written, TRUE))
1042       {
1043         SetErrnoFromWinError (GetLastError ());
1044         LOG (GNUNET_ERROR_TYPE_DEBUG,
1045             "Error getting overlapped result while writing to pipe: %u\n",
1046             GetLastError ());
1047         return GNUNET_SYSERR;
1048       }
1049     }
1050     else
1051     {
1052       DWORD ovr;
1053       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1054       {
1055         LOG (GNUNET_ERROR_TYPE_DEBUG,
1056             "Error getting control overlapped result while writing to pipe: %u\n",
1057             GetLastError ());
1058       }
1059       else
1060       {
1061         LOG (GNUNET_ERROR_TYPE_DEBUG,
1062             "Wrote %u bytes (ovr says %u), picking the greatest\n",
1063             bytes_written, ovr);
1064       }
1065     }
1066     if (bytes_written == 0)
1067     {
1068       if (n > 0)
1069       {
1070         LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytes_written);
1071         errno = EAGAIN;
1072         return GNUNET_SYSERR;
1073       }
1074     }
1075     LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytes_written);
1076   }
1077   else
1078   {
1079     bytes_written = 0;
1080   }
1081   return bytes_written;
1082 #else
1083   return write (h->fd, buffer, n);
1084 #endif
1085 }
1086
1087
1088 /**
1089  * Write a buffer to a file, blocking, if necessary.
1090  *
1091  * @param h handle to open file
1092  * @param buffer the data to write
1093  * @param n number of bytes to write
1094  * @return number of bytes written on success, #GNUNET_SYSERR on error
1095  */
1096 ssize_t
1097 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1098                                  const void *buffer,
1099                                  size_t n)
1100 {
1101   if (NULL == h)
1102   {
1103     errno = EINVAL;
1104     return GNUNET_SYSERR;
1105   }
1106
1107 #ifdef MINGW
1108   DWORD bytes_written;
1109   /* We do a non-overlapped write, which is as blocking as it gets */
1110   LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1111   if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1112   {
1113     SetErrnoFromWinError (GetLastError ());
1114     LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1115         GetLastError ());
1116     return GNUNET_SYSERR;
1117   }
1118   if (bytes_written == 0 && n > 0)
1119   {
1120     LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1121     WaitForSingleObject (h->h, INFINITE);
1122     if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1123     {
1124       SetErrnoFromWinError (GetLastError ());
1125       LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1126           GetLastError ());
1127       return GNUNET_SYSERR;
1128     }
1129   }
1130   LOG (GNUNET_ERROR_TYPE_DEBUG,
1131        "Wrote %u bytes\n",
1132        bytes_written);
1133   return bytes_written;
1134 #else
1135   int flags;
1136   ssize_t ret;
1137
1138   /* set to blocking, write, then set back */
1139   flags = fcntl (h->fd, F_GETFL);
1140   if (0 != (flags & O_NONBLOCK))
1141     (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1142   ret = write (h->fd, buffer, n);
1143   if (0 == (flags & O_NONBLOCK))
1144     (void) fcntl (h->fd, F_SETFL, flags);
1145   return ret;
1146 #endif
1147 }
1148
1149
1150 /**
1151  * Write a buffer to a file.  If the file is longer than the
1152  * number of bytes that will be written, it will be truncated.
1153  *
1154  * @param fn file name
1155  * @param buffer the data to write
1156  * @param n number of bytes to write
1157  * @param mode file permissions
1158  * @return number of bytes written on success, #GNUNET_SYSERR on error
1159  */
1160 ssize_t
1161 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1162                       enum GNUNET_DISK_AccessPermissions mode)
1163 {
1164   struct GNUNET_DISK_FileHandle *fh;
1165   ssize_t ret;
1166
1167   fh = GNUNET_DISK_file_open (fn,
1168                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1169                               | GNUNET_DISK_OPEN_CREATE, mode);
1170   if (!fh)
1171     return GNUNET_SYSERR;
1172   ret = GNUNET_DISK_file_write (fh, buffer, n);
1173   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1174   return ret;
1175 }
1176
1177
1178 /**
1179  * Scan a directory for files.
1180  *
1181  * @param dir_name the name of the directory
1182  * @param callback the method to call for each file,
1183  *        can be NULL, in that case, we only count
1184  * @param callback_cls closure for @a callback
1185  * @return the number of files found, #GNUNET_SYSERR on error or
1186  *         ieration aborted by callback returning #GNUNET_SYSERR
1187  */
1188 int
1189 GNUNET_DISK_directory_scan (const char *dir_name,
1190                             GNUNET_FileNameCallback callback,
1191                             void *callback_cls)
1192 {
1193   DIR *dinfo;
1194   struct dirent *finfo;
1195   struct stat istat;
1196   int count = 0;
1197   int ret;
1198   char *name;
1199   char *dname;
1200   unsigned int name_len;
1201   unsigned int n_size;
1202
1203   GNUNET_assert (NULL != dir_name);
1204   dname = GNUNET_STRINGS_filename_expand (dir_name);
1205   if (dname == NULL)
1206     return GNUNET_SYSERR;
1207   while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1208     dname[strlen (dname) - 1] = '\0';
1209   if (0 != STAT (dname, &istat))
1210   {
1211     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1212     GNUNET_free (dname);
1213     return GNUNET_SYSERR;
1214   }
1215   if (! S_ISDIR (istat.st_mode))
1216   {
1217     LOG (GNUNET_ERROR_TYPE_WARNING,
1218          _("Expected `%s' to be a directory!\n"),
1219          dir_name);
1220     GNUNET_free (dname);
1221     return GNUNET_SYSERR;
1222   }
1223   errno = 0;
1224   dinfo = OPENDIR (dname);
1225   if ((errno == EACCES) || (NULL == dinfo))
1226   {
1227     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1228     if (dinfo != NULL)
1229       CLOSEDIR (dinfo);
1230     GNUNET_free (dname);
1231     return GNUNET_SYSERR;
1232   }
1233   name_len = 256;
1234   n_size = strlen (dname) + name_len + 2;
1235   name = GNUNET_malloc (n_size);
1236   while (NULL != (finfo = READDIR (dinfo)))
1237   {
1238     if ((0 == strcmp (finfo->d_name, ".")) ||
1239         (0 == strcmp (finfo->d_name, "..")))
1240       continue;
1241     if (NULL != callback)
1242     {
1243       if (name_len < strlen (finfo->d_name))
1244       {
1245         GNUNET_free (name);
1246         name_len = strlen (finfo->d_name);
1247         n_size = strlen (dname) + name_len + 2;
1248         name = GNUNET_malloc (n_size);
1249       }
1250       /* dname can end in "/" only if dname == "/";
1251        * if dname does not end in "/", we need to add
1252        * a "/" (otherwise, we must not!) */
1253       GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1254                        (strcmp (dname, DIR_SEPARATOR_STR) ==
1255                         0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1256       ret = callback (callback_cls, name);
1257       if (GNUNET_OK != ret)
1258       {
1259         CLOSEDIR (dinfo);
1260         GNUNET_free (name);
1261         GNUNET_free (dname);
1262         if (GNUNET_NO == ret)
1263           return count;
1264         return GNUNET_SYSERR;
1265       }
1266     }
1267     count++;
1268   }
1269   CLOSEDIR (dinfo);
1270   GNUNET_free (name);
1271   GNUNET_free (dname);
1272   return count;
1273 }
1274
1275
1276 /**
1277  * Opaque handle used for iterating over a directory.
1278  */
1279 struct GNUNET_DISK_DirectoryIterator
1280 {
1281
1282   /**
1283    * Function to call on directory entries.
1284    */
1285   GNUNET_DISK_DirectoryIteratorCallback callback;
1286
1287   /**
1288    * Closure for callback.
1289    */
1290   void *callback_cls;
1291
1292   /**
1293    * Reference to directory.
1294    */
1295   DIR *directory;
1296
1297   /**
1298    * Directory name.
1299    */
1300   char *dirname;
1301
1302   /**
1303    * Next filename to process.
1304    */
1305   char *next_name;
1306
1307   /**
1308    * Our priority.
1309    */
1310   enum GNUNET_SCHEDULER_Priority priority;
1311
1312 };
1313
1314
1315 /**
1316  * Task used by the directory iterator.
1317  */
1318 static void
1319 directory_iterator_task (void *cls,
1320                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1321 {
1322   struct GNUNET_DISK_DirectoryIterator *iter = cls;
1323   char *name;
1324
1325   name = iter->next_name;
1326   GNUNET_assert (name != NULL);
1327   iter->next_name = NULL;
1328   iter->callback (iter->callback_cls, iter, name, iter->dirname);
1329   GNUNET_free (name);
1330 }
1331
1332
1333 /**
1334  * This function must be called during the DiskIteratorCallback
1335  * (exactly once) to schedule the task to process the next
1336  * filename in the directory (if there is one).
1337  *
1338  * @param iter opaque handle for the iterator
1339  * @param can set to GNUNET_YES to terminate the iteration early
1340  * @return GNUNET_YES if iteration will continue,
1341  *         GNUNET_NO if this was the last entry (and iteration is complete),
1342  *         GNUNET_SYSERR if abort was YES
1343  */
1344 int
1345 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1346                                      int can)
1347 {
1348   struct dirent *finfo;
1349
1350   GNUNET_assert (iter->next_name == NULL);
1351   if (can == GNUNET_YES)
1352   {
1353     CLOSEDIR (iter->directory);
1354     GNUNET_free (iter->dirname);
1355     GNUNET_free (iter);
1356     return GNUNET_SYSERR;
1357   }
1358   while (NULL != (finfo = READDIR (iter->directory)))
1359   {
1360     if ((0 == strcmp (finfo->d_name, ".")) ||
1361         (0 == strcmp (finfo->d_name, "..")))
1362       continue;
1363     GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1364                      DIR_SEPARATOR_STR, finfo->d_name);
1365     break;
1366   }
1367   if (finfo == NULL)
1368   {
1369     GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1370     return GNUNET_NO;
1371   }
1372   GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1373                                       iter);
1374   return GNUNET_YES;
1375 }
1376
1377
1378 /**
1379  * Scan a directory for files using the scheduler to run a task for
1380  * each entry.  The name of the directory must be expanded first (!).
1381  * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1382  * may provide a simpler API.
1383  *
1384  * @param prio priority to use
1385  * @param dir_name the name of the directory
1386  * @param callback the method to call for each file
1387  * @param callback_cls closure for callback
1388  * @return GNUNET_YES if directory is not empty and 'callback'
1389  *         will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1390  */
1391 int
1392 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1393                                       const char *dir_name,
1394                                       GNUNET_DISK_DirectoryIteratorCallback
1395                                       callback, void *callback_cls)
1396 {
1397   struct GNUNET_DISK_DirectoryIterator *di;
1398
1399   di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
1400   di->callback = callback;
1401   di->callback_cls = callback_cls;
1402   di->directory = OPENDIR (dir_name);
1403   if (di->directory == NULL)
1404   {
1405     GNUNET_free (di);
1406     callback (callback_cls, NULL, NULL, NULL);
1407     return GNUNET_SYSERR;
1408   }
1409   di->dirname = GNUNET_strdup (dir_name);
1410   di->priority = prio;
1411   return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1412 }
1413
1414
1415 /**
1416  * Function that removes the given directory by calling
1417  * "GNUNET_DISK_directory_remove".
1418  *
1419  * @param unused not used
1420  * @param fn directory to remove
1421  * @return #GNUNET_OK
1422  */
1423 static int
1424 remove_helper (void *unused, const char *fn)
1425 {
1426   (void) GNUNET_DISK_directory_remove (fn);
1427   return GNUNET_OK;
1428 }
1429
1430
1431 /**
1432  * Remove all files in a directory (rm -rf). Call with
1433  * caution.
1434  *
1435  * @param filename the file to remove
1436  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1437  */
1438 int
1439 GNUNET_DISK_directory_remove (const char *filename)
1440 {
1441   struct stat istat;
1442
1443   if (NULL == filename)
1444   {
1445     GNUNET_break (0);
1446     return GNUNET_SYSERR;
1447   }
1448   if (0 != LSTAT (filename, &istat))
1449     return GNUNET_NO;           /* file may not exist... */
1450   (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1451   if (UNLINK (filename) == 0)
1452     return GNUNET_OK;
1453   if ((errno != EISDIR) &&
1454       /* EISDIR is not sufficient in all cases, e.g.
1455        * sticky /tmp directory may result in EPERM on BSD.
1456        * So we also explicitly check "isDirectory" */
1457       (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1458   {
1459     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1460     return GNUNET_SYSERR;
1461   }
1462   if (GNUNET_SYSERR ==
1463       GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1464     return GNUNET_SYSERR;
1465   if (0 != RMDIR (filename))
1466   {
1467     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1468     return GNUNET_SYSERR;
1469   }
1470   return GNUNET_OK;
1471 }
1472
1473
1474 /**
1475  * Copy a file.
1476  *
1477  * @param src file to copy
1478  * @param dst destination file name
1479  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1480  */
1481 int
1482 GNUNET_DISK_file_copy (const char *src,
1483                        const char *dst)
1484 {
1485   char *buf;
1486   uint64_t pos;
1487   uint64_t size;
1488   size_t len;
1489   struct GNUNET_DISK_FileHandle *in;
1490   struct GNUNET_DISK_FileHandle *out;
1491
1492   if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1493     return GNUNET_SYSERR;
1494   pos = 0;
1495   in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1496                               GNUNET_DISK_PERM_NONE);
1497   if (!in)
1498     return GNUNET_SYSERR;
1499   out =
1500       GNUNET_DISK_file_open (dst,
1501                              GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1502                              GNUNET_DISK_OPEN_FAILIFEXISTS,
1503                              GNUNET_DISK_PERM_USER_READ |
1504                              GNUNET_DISK_PERM_USER_WRITE |
1505                              GNUNET_DISK_PERM_GROUP_READ |
1506                              GNUNET_DISK_PERM_GROUP_WRITE);
1507   if (!out)
1508   {
1509     GNUNET_DISK_file_close (in);
1510     return GNUNET_SYSERR;
1511   }
1512   buf = GNUNET_malloc (COPY_BLK_SIZE);
1513   while (pos < size)
1514   {
1515     len = COPY_BLK_SIZE;
1516     if (len > size - pos)
1517       len = size - pos;
1518     if (len != GNUNET_DISK_file_read (in, buf, len))
1519       goto FAIL;
1520     if (len != GNUNET_DISK_file_write (out, buf, len))
1521       goto FAIL;
1522     pos += len;
1523   }
1524   GNUNET_free (buf);
1525   GNUNET_DISK_file_close (in);
1526   GNUNET_DISK_file_close (out);
1527   return GNUNET_OK;
1528 FAIL:
1529   GNUNET_free (buf);
1530   GNUNET_DISK_file_close (in);
1531   GNUNET_DISK_file_close (out);
1532   return GNUNET_SYSERR;
1533 }
1534
1535
1536 /**
1537  * @brief Removes special characters as ':' from a filename.
1538  * @param fn the filename to canonicalize
1539  */
1540 void
1541 GNUNET_DISK_filename_canonicalize (char *fn)
1542 {
1543   char *idx;
1544   char c;
1545
1546   idx = fn;
1547   while (*idx)
1548   {
1549     c = *idx;
1550
1551     if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1552         c == '<' || c == '>' || c == '|')
1553     {
1554       *idx = '_';
1555     }
1556
1557     idx++;
1558   }
1559 }
1560
1561
1562
1563 /**
1564  * @brief Change owner of a file
1565  *
1566  * @param filename name of file to change the owner of
1567  * @param user name of the new owner
1568  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1569  */
1570 int
1571 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1572 {
1573 #ifndef MINGW
1574   struct passwd *pws;
1575
1576   pws = getpwnam (user);
1577   if (pws == NULL)
1578   {
1579     LOG (GNUNET_ERROR_TYPE_ERROR,
1580          _("Cannot obtain information about user `%s': %s\n"), user,
1581          STRERROR (errno));
1582     return GNUNET_SYSERR;
1583   }
1584   if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1585     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1586 #endif
1587   return GNUNET_OK;
1588 }
1589
1590
1591 /**
1592  * Lock a part of a file
1593  * @param fh file handle
1594  * @param lock_start absolute position from where to lock
1595  * @param lock_end absolute position until where to lock
1596  * @param excl GNUNET_YES for an exclusive lock
1597  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1598  */
1599 int
1600 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lock_start,
1601                        off_t lock_end, int excl)
1602 {
1603   if (fh == NULL)
1604   {
1605     errno = EINVAL;
1606     return GNUNET_SYSERR;
1607   }
1608
1609 #ifndef MINGW
1610   struct flock fl;
1611
1612   memset (&fl, 0, sizeof (struct flock));
1613   fl.l_type = excl ? F_WRLCK : F_RDLCK;
1614   fl.l_whence = SEEK_SET;
1615   fl.l_start = lock_start;
1616   fl.l_len = lock_end;
1617
1618   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1619 #else
1620   OVERLAPPED o;
1621   off_t diff = lock_end - lock_start;
1622   DWORD diff_low, diff_high;
1623   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1624   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1625
1626   memset (&o, 0, sizeof (OVERLAPPED));
1627   o.Offset = (DWORD) (lock_start & 0xFFFFFFFF);;
1628   o.OffsetHigh = (DWORD) (((lock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1629
1630   if (!LockFileEx
1631       (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1632        0, diff_low, diff_high, &o))
1633   {
1634     SetErrnoFromWinError (GetLastError ());
1635     return GNUNET_SYSERR;
1636   }
1637
1638   return GNUNET_OK;
1639 #endif
1640 }
1641
1642
1643 /**
1644  * Unlock a part of a file
1645  * @param fh file handle
1646  * @param unlock_start absolute position from where to unlock
1647  * @param unlock_end absolute position until where to unlock
1648  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1649  */
1650 int
1651 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlock_start,
1652                          off_t unlock_end)
1653 {
1654   if (fh == NULL)
1655   {
1656     errno = EINVAL;
1657     return GNUNET_SYSERR;
1658   }
1659
1660 #ifndef MINGW
1661   struct flock fl;
1662
1663   memset (&fl, 0, sizeof (struct flock));
1664   fl.l_type = F_UNLCK;
1665   fl.l_whence = SEEK_SET;
1666   fl.l_start = unlock_start;
1667   fl.l_len = unlock_end;
1668
1669   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1670 #else
1671   OVERLAPPED o;
1672   off_t diff = unlock_end - unlock_start;
1673   DWORD diff_low, diff_high;
1674   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1675   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1676
1677   memset (&o, 0, sizeof (OVERLAPPED));
1678   o.Offset = (DWORD) (unlock_start & 0xFFFFFFFF);;
1679   o.OffsetHigh = (DWORD) (((unlock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1680
1681   if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1682   {
1683     SetErrnoFromWinError (GetLastError ());
1684     return GNUNET_SYSERR;
1685   }
1686
1687   return GNUNET_OK;
1688 #endif
1689 }
1690
1691
1692 /**
1693  * Open a file.  Note that the access permissions will only be
1694  * used if a new file is created and if the underlying operating
1695  * system supports the given permissions.
1696  *
1697  * @param fn file name to be opened
1698  * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1699  * @param perm permissions for the newly created file, use
1700  *             #GNUNET_DISK_PERM_NONE if a file could not be created by this
1701  *             call (because of flags)
1702  * @return IO handle on success, NULL on error
1703  */
1704 struct GNUNET_DISK_FileHandle *
1705 GNUNET_DISK_file_open (const char *fn,
1706                        enum GNUNET_DISK_OpenFlags flags,
1707                        enum GNUNET_DISK_AccessPermissions perm)
1708 {
1709   char *expfn;
1710   struct GNUNET_DISK_FileHandle *ret;
1711
1712 #ifdef MINGW
1713   DWORD access;
1714   DWORD disp;
1715   HANDLE h;
1716   wchar_t wexpfn[MAX_PATH + 1];
1717 #else
1718   int oflags;
1719   int mode;
1720   int fd;
1721 #endif
1722
1723   expfn = GNUNET_STRINGS_filename_expand (fn);
1724   if (NULL == expfn)
1725     return NULL;
1726 #ifndef MINGW
1727   mode = 0;
1728   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1729     oflags = O_RDWR;            /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1730   else if (flags & GNUNET_DISK_OPEN_READ)
1731     oflags = O_RDONLY;
1732   else if (flags & GNUNET_DISK_OPEN_WRITE)
1733     oflags = O_WRONLY;
1734   else
1735   {
1736     GNUNET_break (0);
1737     GNUNET_free (expfn);
1738     return NULL;
1739   }
1740   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1741     oflags |= (O_CREAT | O_EXCL);
1742   if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1743     oflags |= O_TRUNC;
1744   if (flags & GNUNET_DISK_OPEN_APPEND)
1745     oflags |= O_APPEND;
1746   if (flags & GNUNET_DISK_OPEN_CREATE)
1747   {
1748     (void) GNUNET_DISK_directory_create_for_file (expfn);
1749     oflags |= O_CREAT;
1750     mode = translate_unix_perms (perm);
1751   }
1752
1753   fd = open (expfn, oflags
1754 #if O_CLOEXEC
1755              | O_CLOEXEC
1756 #endif
1757              | O_LARGEFILE, mode);
1758   if (fd == -1)
1759   {
1760     if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1761       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1762     else
1763       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1764     GNUNET_free (expfn);
1765     return NULL;
1766   }
1767 #else
1768   access = 0;
1769   disp = OPEN_ALWAYS;
1770
1771   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1772     access = FILE_READ_DATA | FILE_WRITE_DATA;
1773   else if (flags & GNUNET_DISK_OPEN_READ)
1774     access = FILE_READ_DATA;
1775   else if (flags & GNUNET_DISK_OPEN_WRITE)
1776     access = FILE_WRITE_DATA;
1777
1778   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1779   {
1780     disp = CREATE_NEW;
1781   }
1782   else if (flags & GNUNET_DISK_OPEN_CREATE)
1783   {
1784     (void) GNUNET_DISK_directory_create_for_file (expfn);
1785     if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1786       disp = CREATE_ALWAYS;
1787     else
1788       disp = OPEN_ALWAYS;
1789   }
1790   else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1791   {
1792     disp = TRUNCATE_EXISTING;
1793   }
1794   else
1795   {
1796     disp = OPEN_EXISTING;
1797   }
1798
1799   if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1800     h = CreateFileW (wexpfn, access,
1801                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1802                     disp, FILE_ATTRIBUTE_NORMAL, NULL);
1803   else
1804     h = INVALID_HANDLE_VALUE;
1805   if (h == INVALID_HANDLE_VALUE)
1806   {
1807     int err;
1808     SetErrnoFromWinError (GetLastError ());
1809     err = errno;
1810     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1811     GNUNET_free (expfn);
1812     errno = err;
1813     return NULL;
1814   }
1815
1816   if (flags & GNUNET_DISK_OPEN_APPEND)
1817     if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1818     {
1819       SetErrnoFromWinError (GetLastError ());
1820       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1821       CloseHandle (h);
1822       GNUNET_free (expfn);
1823       return NULL;
1824     }
1825 #endif
1826
1827   ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1828 #ifdef MINGW
1829   ret->h = h;
1830   ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1831 #else
1832   ret->fd = fd;
1833 #endif
1834   GNUNET_free (expfn);
1835   return ret;
1836 }
1837
1838
1839 /**
1840  * Close an open file
1841  * @param h file handle
1842  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1843  */
1844 int
1845 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1846 {
1847   int ret;
1848   if (h == NULL)
1849   {
1850     errno = EINVAL;
1851     return GNUNET_SYSERR;
1852   }
1853
1854   ret = GNUNET_OK;
1855
1856 #if MINGW
1857   if (!CloseHandle (h->h))
1858   {
1859     SetErrnoFromWinError (GetLastError ());
1860     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1861     ret = GNUNET_SYSERR;
1862   }
1863   if (h->oOverlapRead)
1864   {
1865     if (!CloseHandle (h->oOverlapRead->hEvent))
1866     {
1867       SetErrnoFromWinError (GetLastError ());
1868       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1869       ret = GNUNET_SYSERR;
1870     }
1871     GNUNET_free (h->oOverlapRead);
1872   }
1873   if (h->oOverlapWrite)
1874   {
1875     if (!CloseHandle (h->oOverlapWrite->hEvent))
1876     {
1877       SetErrnoFromWinError (GetLastError ());
1878       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1879       ret = GNUNET_SYSERR;
1880     }
1881     GNUNET_free (h->oOverlapWrite);
1882   }
1883 #else
1884   if (close (h->fd) != 0)
1885   {
1886     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1887     ret = GNUNET_SYSERR;
1888   }
1889 #endif
1890   GNUNET_free (h);
1891   return ret;
1892 }
1893
1894 #ifdef WINDOWS
1895 /**
1896  * Get a GNUnet file handle from a W32 handle.
1897  *
1898  * @param handle native handle
1899  * @return GNUnet file handle corresponding to the W32 handle
1900  */
1901 struct GNUNET_DISK_FileHandle *
1902 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1903 {
1904   struct GNUNET_DISK_FileHandle *fh;
1905
1906   DWORD dwret;
1907   enum GNUNET_FILE_Type ftype;
1908
1909   dwret = GetFileType (osfh);
1910   switch (dwret)
1911   {
1912   case FILE_TYPE_DISK:
1913     ftype = GNUNET_DISK_HANLDE_TYPE_FILE;
1914     break;
1915   case FILE_TYPE_PIPE:
1916     ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1917     break;
1918   case FILE_TYPE_UNKNOWN:
1919     if (GetLastError () == NO_ERROR || GetLastError () == ERROR_INVALID_HANDLE)
1920     {
1921       if (0 != ResetEvent (osfh))
1922         ftype = GNUNET_DISK_HANLDE_TYPE_EVENT;
1923     }
1924     else
1925       return NULL;
1926     break;
1927   default:
1928     return NULL;
1929   }
1930
1931   fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1932
1933   fh->h = osfh;
1934   fh->type = ftype;
1935   if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1936   {
1937     /**
1938      * Note that we can't make it overlapped if it isn't already.
1939      * (ReOpenFile() is only available in 2003/Vista).
1940      * The process that opened this file in the first place (usually a parent
1941      * process, if this is stdin/stdout/stderr) must make it overlapped,
1942      * otherwise we're screwed, as selecting on non-overlapped handle
1943      * will block.
1944      */
1945     fh->oOverlapRead = GNUNET_new (OVERLAPPED);
1946     fh->oOverlapWrite = GNUNET_new (OVERLAPPED);
1947     fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1948     fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1949   }
1950
1951   return fh;
1952 }
1953 #endif
1954
1955 /**
1956  * Get a handle from a native integer FD.
1957  *
1958  * @param fno native integer file descriptor
1959  * @return file handle corresponding to the descriptor, NULL on error
1960  */
1961 struct GNUNET_DISK_FileHandle *
1962 GNUNET_DISK_get_handle_from_int_fd (int fno)
1963 {
1964   struct GNUNET_DISK_FileHandle *fh;
1965
1966   if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1967        (EBADF == errno) )
1968     return NULL; /* invalid FD */
1969
1970 #ifndef WINDOWS
1971   fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1972
1973   fh->fd = fno;
1974 #else
1975   intptr_t osfh;
1976
1977   osfh = _get_osfhandle (fno);
1978   if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1979     return NULL;
1980
1981   fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1982 #endif
1983
1984   return fh;
1985 }
1986
1987
1988 /**
1989  * Get a handle from a native streaming FD.
1990  *
1991  * @param fd native streaming file descriptor
1992  * @return file handle corresponding to the descriptor
1993  */
1994 struct GNUNET_DISK_FileHandle *
1995 GNUNET_DISK_get_handle_from_native (FILE *fd)
1996 {
1997   int fno;
1998
1999   fno = fileno (fd);
2000   if (-1 == fno)
2001     return NULL;
2002
2003   return GNUNET_DISK_get_handle_from_int_fd (fno);
2004 }
2005
2006
2007 /**
2008  * Handle for a memory-mapping operation.
2009  */
2010 struct GNUNET_DISK_MapHandle
2011 {
2012   /**
2013    * Address where the map is in memory.
2014    */
2015   void *addr;
2016
2017 #ifdef MINGW
2018   /**
2019    * Underlying OS handle.
2020    */
2021   HANDLE h;
2022 #else
2023   /**
2024    * Number of bytes mapped.
2025    */
2026   size_t len;
2027 #endif
2028 };
2029
2030
2031 #ifndef MAP_FAILED
2032 #define MAP_FAILED ((void *) -1)
2033 #endif
2034
2035 /**
2036  * Map a file into memory
2037  *
2038  * @param h open file handle
2039  * @param m handle to the new mapping
2040  * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
2041  * @param len size of the mapping
2042  * @return pointer to the mapped memory region, NULL on failure
2043  */
2044 void *
2045 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
2046                       struct GNUNET_DISK_MapHandle **m,
2047                       enum GNUNET_DISK_MapType access, size_t len)
2048 {
2049   if (h == NULL)
2050   {
2051     errno = EINVAL;
2052     return NULL;
2053   }
2054
2055 #ifdef MINGW
2056   DWORD mapAccess, protect;
2057
2058   if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2059       (access & GNUNET_DISK_MAP_TYPE_WRITE))
2060   {
2061     protect = PAGE_READWRITE;
2062     mapAccess = FILE_MAP_ALL_ACCESS;
2063   }
2064   else if (access & GNUNET_DISK_MAP_TYPE_READ)
2065   {
2066     protect = PAGE_READONLY;
2067     mapAccess = FILE_MAP_READ;
2068   }
2069   else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2070   {
2071     protect = PAGE_READWRITE;
2072     mapAccess = FILE_MAP_WRITE;
2073   }
2074   else
2075   {
2076     GNUNET_break (0);
2077     return NULL;
2078   }
2079
2080   *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2081   (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2082   if ((*m)->h == INVALID_HANDLE_VALUE)
2083   {
2084     SetErrnoFromWinError (GetLastError ());
2085     GNUNET_free (*m);
2086     return NULL;
2087   }
2088
2089   (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2090   if (!(*m)->addr)
2091   {
2092     SetErrnoFromWinError (GetLastError ());
2093     CloseHandle ((*m)->h);
2094     GNUNET_free (*m);
2095   }
2096
2097   return (*m)->addr;
2098 #else
2099   int prot;
2100
2101   prot = 0;
2102   if (access & GNUNET_DISK_MAP_TYPE_READ)
2103     prot = PROT_READ;
2104   if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2105     prot |= PROT_WRITE;
2106   *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2107   (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2108   GNUNET_assert (NULL != (*m)->addr);
2109   if (MAP_FAILED == (*m)->addr)
2110   {
2111     GNUNET_free (*m);
2112     return NULL;
2113   }
2114   (*m)->len = len;
2115   return (*m)->addr;
2116 #endif
2117 }
2118
2119 /**
2120  * Unmap a file
2121  * @param h mapping handle
2122  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2123  */
2124 int
2125 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2126 {
2127   int ret;
2128
2129   if (h == NULL)
2130   {
2131     errno = EINVAL;
2132     return GNUNET_SYSERR;
2133   }
2134
2135 #ifdef MINGW
2136   ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2137   if (ret != GNUNET_OK)
2138     SetErrnoFromWinError (GetLastError ());
2139   if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2140   {
2141     ret = GNUNET_SYSERR;
2142     SetErrnoFromWinError (GetLastError ());
2143   }
2144 #else
2145   ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2146 #endif
2147   GNUNET_free (h);
2148   return ret;
2149 }
2150
2151
2152 /**
2153  * Write file changes to disk
2154  * @param h handle to an open file
2155  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2156  */
2157 int
2158 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2159 {
2160   if (h == NULL)
2161   {
2162     errno = EINVAL;
2163     return GNUNET_SYSERR;
2164   }
2165
2166 #ifdef MINGW
2167   int ret;
2168
2169   ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2170   if (ret != GNUNET_OK)
2171     SetErrnoFromWinError (GetLastError ());
2172   return ret;
2173 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2174   return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2175 #else
2176   return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2177 #endif
2178 }
2179
2180
2181 #if WINDOWS
2182 #ifndef PIPE_BUF
2183 #define PIPE_BUF        512
2184 #endif
2185 /* Copyright Bob Byrnes  <byrnes <at> curl.com>
2186    http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2187 */
2188 /* Create a pipe, and return handles to the read and write ends,
2189    just like CreatePipe, but ensure that the write end permits
2190    FILE_READ_ATTRIBUTES access, on later versions of win32 where
2191    this is supported.  This access is needed by NtQueryInformationFile,
2192    which is used to implement select and nonblocking writes.
2193    Note that the return value is either NO_ERROR or GetLastError,
2194    unlike CreatePipe, which returns a bool for success or failure.  */
2195 static int
2196 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2197                         LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2198                         DWORD dwReadMode, DWORD dwWriteMode)
2199 {
2200   /* Default to error. */
2201   *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2202
2203   HANDLE read_pipe;
2204   HANDLE write_pipe;
2205
2206   /* Ensure that there is enough pipe buffer space for atomic writes.  */
2207   if (psize < PIPE_BUF)
2208     psize = PIPE_BUF;
2209
2210   char pipename[MAX_PATH];
2211
2212   /* Retry CreateNamedPipe as long as the pipe name is in use.
2213    * Retrying will probably never be necessary, but we want
2214    * to be as robust as possible.  */
2215   while (1)
2216   {
2217     static volatile LONG pipe_unique_id;
2218
2219     snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2220               getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2221     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2222          pipename, psize);
2223     /* Use CreateNamedPipe instead of CreatePipe, because the latter
2224      * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2225      * access, on versions of win32 earlier than WinXP SP2.
2226      * CreatePipe also stupidly creates a full duplex pipe, which is
2227      * a waste, since only a single direction is actually used.
2228      * It's important to only allow a single instance, to ensure that
2229      * the pipe was not created earlier by some other process, even if
2230      * the pid has been reused.  */
2231     read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,   /* max instances */
2232                                   psize,        /* output buffer size */
2233                                   psize,        /* input buffer size */
2234                                   NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2235
2236     if (read_pipe != INVALID_HANDLE_VALUE)
2237     {
2238       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2239       break;
2240     }
2241
2242     DWORD err = GetLastError ();
2243
2244     switch (err)
2245     {
2246     case ERROR_PIPE_BUSY:
2247       /* The pipe is already open with compatible parameters.
2248        * Pick a new name and retry.  */
2249       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2250       continue;
2251     case ERROR_ACCESS_DENIED:
2252       /* The pipe is already open with incompatible parameters.
2253        * Pick a new name and retry.  */
2254       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2255       continue;
2256     case ERROR_CALL_NOT_IMPLEMENTED:
2257       /* We are on an older Win9x platform without named pipes.
2258        * Return an anonymous pipe as the best approximation.  */
2259       LOG (GNUNET_ERROR_TYPE_DEBUG,
2260            "CreateNamedPipe not implemented, resorting to "
2261            "CreatePipe: size = %lu\n", psize);
2262       if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2263       {
2264         LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2265              *read_pipe_ptr,
2266              *write_pipe_ptr);
2267         return GNUNET_OK;
2268       }
2269       err = GetLastError ();
2270       LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2271       return err;
2272     default:
2273       LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2274       return err;
2275     }
2276     /* NOTREACHED */
2277   }
2278   LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2279
2280   /* Open the named pipe for writing.
2281    * Be sure to permit FILE_READ_ATTRIBUTES access.  */
2282   write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0,  /* share mode */
2283                             sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2284                             0); /* handle to template file */
2285
2286   if (write_pipe == INVALID_HANDLE_VALUE)
2287   {
2288     /* Failure. */
2289     DWORD err = GetLastError ();
2290
2291     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2292     CloseHandle (read_pipe);
2293     return err;
2294   }
2295   LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2296   /* Success. */
2297   *read_pipe_ptr = read_pipe;
2298   *write_pipe_ptr = write_pipe;
2299   return GNUNET_OK;
2300 }
2301 #endif
2302
2303
2304 /**
2305  * Creates an interprocess channel
2306  *
2307  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2308  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2309  * @param inherit_read inherit the parent processes stdin (only for windows)
2310  * @param inherit_write inherit the parent processes stdout (only for windows)
2311  * @return handle to the new pipe, NULL on error
2312  */
2313 struct GNUNET_DISK_PipeHandle *
2314 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2315 {
2316 #ifndef MINGW
2317   int fd[2];
2318   int ret;
2319   int eno;
2320
2321   ret = pipe (fd);
2322   if (ret == -1)
2323   {
2324     eno = errno;
2325     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2326     errno = eno;
2327     return NULL;
2328   }
2329   return GNUNET_DISK_pipe_from_fd (blocking_read,
2330                                    blocking_write,
2331                                    fd);
2332 #else
2333   struct GNUNET_DISK_PipeHandle *p;
2334   BOOL ret;
2335   HANDLE tmp_handle;
2336   int save_errno;
2337
2338   p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2339   p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2340   p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2341
2342   /* All pipes are overlapped. If you want them to block - just
2343    * call WriteFile() and ReadFile() with NULL overlapped pointer.
2344    * NOTE: calling with NULL overlapped pointer works only
2345    * for pipes, and doesn't seem to be a documented feature.
2346    * It will NOT work for files, because overlapped files need
2347    * to read offsets from the overlapped structure, regardless.
2348    * Pipes are not seekable, and need no offsets, which is
2349    * probably why it works for them.
2350    */
2351   ret =
2352       create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2353                               FILE_FLAG_OVERLAPPED,
2354                               FILE_FLAG_OVERLAPPED);
2355   if (!ret)
2356   {
2357     SetErrnoFromWinError (GetLastError ());
2358     save_errno = errno;
2359     GNUNET_free (p->fd[0]);
2360     GNUNET_free (p->fd[1]);
2361     GNUNET_free (p);
2362     errno = save_errno;
2363     return NULL;
2364   }
2365   if (!DuplicateHandle
2366       (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2367        inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2368   {
2369     SetErrnoFromWinError (GetLastError ());
2370     save_errno = errno;
2371     CloseHandle (p->fd[0]->h);
2372     CloseHandle (p->fd[1]->h);
2373     GNUNET_free (p->fd[0]);
2374     GNUNET_free (p->fd[1]);
2375     GNUNET_free (p);
2376     errno = save_errno;
2377     return NULL;
2378   }
2379   CloseHandle (p->fd[0]->h);
2380   p->fd[0]->h = tmp_handle;
2381
2382   if (!DuplicateHandle
2383       (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2384        inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2385   {
2386     SetErrnoFromWinError (GetLastError ());
2387     save_errno = errno;
2388     CloseHandle (p->fd[0]->h);
2389     CloseHandle (p->fd[1]->h);
2390     GNUNET_free (p->fd[0]);
2391     GNUNET_free (p->fd[1]);
2392     GNUNET_free (p);
2393     errno = save_errno;
2394     return NULL;
2395   }
2396   CloseHandle (p->fd[1]->h);
2397   p->fd[1]->h = tmp_handle;
2398
2399   p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2400   p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2401
2402   p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2403   p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2404   p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2405   p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2406
2407   p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2408   p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2409
2410   p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2411   p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2412
2413   return p;
2414 #endif
2415 }
2416
2417
2418 /**
2419  * Creates a pipe object from a couple of file descriptors.
2420  * Useful for wrapping existing pipe FDs.
2421  *
2422  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2423  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2424  * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2425  *
2426  * @return handle to the new pipe, NULL on error
2427  */
2428 struct GNUNET_DISK_PipeHandle *
2429 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2430 {
2431   struct GNUNET_DISK_PipeHandle *p;
2432
2433   p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2434
2435 #ifndef MINGW
2436   int ret;
2437   int flags;
2438   int eno = 0; /* make gcc happy */
2439
2440   ret = 0;
2441   if (fd[0] >= 0)
2442   {
2443     p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2444     p->fd[0]->fd = fd[0];
2445     if (!blocking_read)
2446     {
2447       flags = fcntl (fd[0], F_GETFL);
2448       flags |= O_NONBLOCK;
2449       if (0 > fcntl (fd[0], F_SETFL, flags))
2450       {
2451         ret = -1;
2452         eno = errno;
2453       }
2454     }
2455     flags = fcntl (fd[0], F_GETFD);
2456     flags |= FD_CLOEXEC;
2457     if (0 > fcntl (fd[0], F_SETFD, flags))
2458     {
2459       ret = -1;
2460       eno = errno;
2461     }
2462   }
2463
2464   if (fd[1] >= 0)
2465   {
2466     p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2467     p->fd[1]->fd = fd[1];
2468     if (!blocking_write)
2469     {
2470       flags = fcntl (fd[1], F_GETFL);
2471       flags |= O_NONBLOCK;
2472       if (0 > fcntl (fd[1], F_SETFL, flags))
2473       {
2474         ret = -1;
2475         eno = errno;
2476       }
2477     }
2478     flags = fcntl (fd[1], F_GETFD);
2479     flags |= FD_CLOEXEC;
2480     if (0 > fcntl (fd[1], F_SETFD, flags))
2481     {
2482       ret = -1;
2483       eno = errno;
2484     }
2485   }
2486   if (ret == -1)
2487   {
2488     errno = eno;
2489     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2490     if (p->fd[0]->fd >= 0)
2491       GNUNET_break (0 == close (p->fd[0]->fd));
2492     if (p->fd[1]->fd >= 0)
2493       GNUNET_break (0 == close (p->fd[1]->fd));
2494     GNUNET_free_non_null (p->fd[0]);
2495     GNUNET_free_non_null (p->fd[1]);
2496     GNUNET_free (p);
2497     errno = eno;
2498     return NULL;
2499   }
2500 #else
2501   if (fd[0] >= 0)
2502   {
2503     p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2504     p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2505     if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2506     {
2507       p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2508       p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2509       p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2510       p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2511       p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2512     }
2513     else
2514     {
2515       GNUNET_free (p->fd[0]);
2516       p->fd[0] = NULL;
2517     }
2518   }
2519   if (fd[1] >= 0)
2520   {
2521     p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2522     p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2523     if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2524     {
2525       p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2526       p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2527       p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2528       p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2529       p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2530     }
2531     else
2532     {
2533       GNUNET_free (p->fd[1]);
2534       p->fd[1] = NULL;
2535     }
2536   }
2537
2538 #endif
2539   return p;
2540 }
2541
2542
2543 /**
2544  * Closes an interprocess channel
2545  *
2546  * @param p pipe to close
2547  * @param end which end of the pipe to close
2548  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2549  */
2550 int
2551 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2552                             enum GNUNET_DISK_PipeEnd end)
2553 {
2554   int ret = GNUNET_OK;
2555
2556   if (end == GNUNET_DISK_PIPE_END_READ)
2557   {
2558     if (p->fd[0])
2559     {
2560       ret = GNUNET_DISK_file_close (p->fd[0]);
2561       p->fd[0] = NULL;
2562     }
2563   }
2564   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2565   {
2566     if (p->fd[1])
2567     {
2568       ret = GNUNET_DISK_file_close (p->fd[1]);
2569       p->fd[1] = NULL;
2570     }
2571   }
2572
2573   return ret;
2574 }
2575
2576 /**
2577  * Detaches one of the ends from the pipe.
2578  * Detached end is a fully-functional FileHandle, it will
2579  * not be affected by anything you do with the pipe afterwards.
2580  * Each end of a pipe can only be detched from it once (i.e.
2581  * it is not duplicated).
2582  *
2583  * @param p pipe to detach an end from
2584  * @param end which end of the pipe to detach
2585  * @return Detached end on success, NULL on failure
2586  * (or if that end is not present or is closed).
2587  */
2588 struct GNUNET_DISK_FileHandle *
2589 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2590                              enum GNUNET_DISK_PipeEnd end)
2591 {
2592   struct GNUNET_DISK_FileHandle *ret = NULL;
2593
2594   if (end == GNUNET_DISK_PIPE_END_READ)
2595   {
2596     if (p->fd[0])
2597     {
2598       ret = p->fd[0];
2599       p->fd[0] = NULL;
2600     }
2601   }
2602   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2603   {
2604     if (p->fd[1])
2605     {
2606       ret = p->fd[1];
2607       p->fd[1] = NULL;
2608     }
2609   }
2610
2611   return ret;
2612 }
2613
2614
2615 /**
2616  * Closes an interprocess channel
2617  *
2618  * @param p pipe to close
2619  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2620  */
2621 int
2622 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2623 {
2624   int ret = GNUNET_OK;
2625
2626   int read_end_close;
2627   int write_end_close;
2628   int read_end_close_errno;
2629   int write_end_close_errno;
2630
2631   read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2632   read_end_close_errno = errno;
2633   write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2634   write_end_close_errno = errno;
2635   GNUNET_free (p);
2636
2637   if (GNUNET_OK != read_end_close)
2638   {
2639     errno = read_end_close_errno;
2640     ret = read_end_close;
2641   }
2642   else if (GNUNET_OK != write_end_close)
2643   {
2644     errno = write_end_close_errno;
2645     ret = write_end_close;
2646   }
2647
2648   return ret;
2649 }
2650
2651
2652 /**
2653  * Get the handle to a particular pipe end
2654  *
2655  * @param p pipe
2656  * @param n end to access
2657  * @return handle for the respective end
2658  */
2659 const struct GNUNET_DISK_FileHandle *
2660 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2661                          enum GNUNET_DISK_PipeEnd n)
2662 {
2663   switch (n)
2664   {
2665   case GNUNET_DISK_PIPE_END_READ:
2666   case GNUNET_DISK_PIPE_END_WRITE:
2667     return p->fd[n];
2668   default:
2669     GNUNET_break (0);
2670     return NULL;
2671   }
2672 }
2673
2674
2675 /**
2676  * Retrieve OS file handle
2677  * @internal
2678  * @param fh GNUnet file descriptor
2679  * @param dst destination buffer
2680  * @param dst_len length of dst
2681  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
2682  */
2683 int
2684 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2685                                    void *dst, size_t dst_len)
2686 {
2687   if (NULL == fh)
2688     return GNUNET_SYSERR;
2689 #ifdef MINGW
2690   if (dst_len < sizeof (HANDLE))
2691     return GNUNET_SYSERR;
2692   *((HANDLE *) dst) = fh->h;
2693 #else
2694   if (dst_len < sizeof (int))
2695     return GNUNET_SYSERR;
2696   *((int *) dst) = fh->fd;
2697 #endif
2698
2699   return GNUNET_OK;
2700 }
2701
2702 /* end of disk.c */