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