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