Removed GNUNET_DISK_get_blocks_available since it's not used and it would
[oweals/gnunet.git] / src / util / disk.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001--2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/disk.c
23  * @brief disk IO convenience methods
24  * @author Christian Grothoff
25  * @author Nils Durner
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_directories.h"
31 #include "gnunet_disk_lib.h"
32 #include "gnunet_scheduler_lib.h"
33 #include "gnunet_strings_lib.h"
34 #include "gnunet_crypto_lib.h"
35 #include "disk.h"
36
37 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
38
39 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
40
41 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
42
43 /**
44  * Block size for IO for copying files.
45  */
46 #define COPY_BLK_SIZE 65536
47
48
49
50 #if defined(LINUX) || defined(CYGWIN) || defined(GNU)
51 #include <sys/vfs.h>
52 #else
53 #if defined(SOMEBSD) || defined(DARWIN)
54 #include <sys/param.h>
55 #include <sys/mount.h>
56 #else
57 #ifdef SOLARIS
58 #include <sys/types.h>
59 #include <sys/statvfs.h>
60 #else
61 #ifdef MINGW
62 #ifndef PIPE_BUF
63 #define PIPE_BUF        512
64 ULONG PipeSerialNumber;
65 #endif
66 #define         _IFMT           0170000 /* type of file */
67 #define         _IFLNK          0120000 /* symbolic link */
68 #define  S_ISLNK(m)     (((m)&_IFMT) == _IFLNK)
69 #else
70 #error PORT-ME: need to port statfs (how much space is left on the drive?)
71 #endif
72 #endif
73 #endif
74 #endif
75
76 #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS)
77 #include <wordexp.h>
78 #endif
79 #if LINUX
80 #include <sys/statvfs.h>
81 #endif
82
83
84 /**
85  * Handle used to manage a pipe.
86  */
87 struct GNUNET_DISK_PipeHandle
88 {
89   /**
90    * File descriptors for the pipe.
91    * One or both of them could be NULL.
92    */
93   struct GNUNET_DISK_FileHandle *fd[2];
94 };
95
96
97 /**
98  * Closure for the recursion to determine the file size
99  * of a directory.
100  */
101 struct GetFileSizeData
102 {
103   /**
104    * Set to the total file size.
105    */
106   uint64_t total;
107
108   /**
109    * GNUNET_YES if symbolic links should be included.
110    */
111   int include_sym_links;
112
113   /**
114    * GNUNET_YES if mode is file-only (return total == -1 for directories).
115    */
116   int single_file_mode;
117 };
118
119
120 #ifndef MINGW
121 /**
122  * Translate GNUnet-internal permission bitmap to UNIX file
123  * access permission bitmap.
124  *
125  * @param perm file permissions, GNUnet style
126  * @return file permissions, UNIX style
127  */
128 static int
129 translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
130 {
131   int mode;
132
133   mode = 0;
134   if (perm & GNUNET_DISK_PERM_USER_READ)
135     mode |= S_IRUSR;
136   if (perm & GNUNET_DISK_PERM_USER_WRITE)
137     mode |= S_IWUSR;
138   if (perm & GNUNET_DISK_PERM_USER_EXEC)
139     mode |= S_IXUSR;
140   if (perm & GNUNET_DISK_PERM_GROUP_READ)
141     mode |= S_IRGRP;
142   if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
143     mode |= S_IWGRP;
144   if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
145     mode |= S_IXGRP;
146   if (perm & GNUNET_DISK_PERM_OTHER_READ)
147     mode |= S_IROTH;
148   if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
149     mode |= S_IWOTH;
150   if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
151     mode |= S_IXOTH;
152
153   return mode;
154 }
155 #endif
156
157
158 /**
159  * Iterate over all files in the given directory and
160  * accumulate their size.
161  *
162  * @param cls closure of type "struct GetFileSizeData"
163  * @param fn current filename we are looking at
164  * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
165  */
166 static int
167 getSizeRec (void *cls, const char *fn)
168 {
169   struct GetFileSizeData *gfsd = cls;
170
171 #ifdef HAVE_STAT64
172   struct stat64 buf;
173 #else
174   struct stat buf;
175 #endif
176
177 #ifdef HAVE_STAT64
178   if (0 != STAT64 (fn, &buf))
179   {
180     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
181     return GNUNET_SYSERR;
182   }
183 #else
184   if (0 != STAT (fn, &buf))
185   {
186     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
187     return GNUNET_SYSERR;
188   }
189 #endif
190   if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
191   {
192     errno = EISDIR;
193     return GNUNET_SYSERR;
194   }
195   if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
196     gfsd->total += buf.st_size;
197   if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
198       ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
199   {
200     if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
201       return GNUNET_SYSERR;
202   }
203   return GNUNET_OK;
204 }
205
206
207 /**
208  * Checks whether a handle is invalid
209  *
210  * @param h handle to check
211  * @return GNUNET_YES if invalid, GNUNET_NO if valid
212  */
213 int
214 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
215 {
216 #ifdef MINGW
217   return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
218 #else
219   return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
220 #endif
221 }
222
223 /**
224  * Get the size of an open file.
225  *
226  * @param fh open file handle
227  * @param size where to write size of the file
228  * @return GNUNET_OK on success, GNUNET_SYSERR on error
229  */
230 int
231 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
232                               OFF_T *size)
233 {
234 #if WINDOWS
235   BOOL b;
236   LARGE_INTEGER li;
237   b = GetFileSizeEx (fh->h, &li);
238   if (!b)
239   {
240     SetErrnoFromWinError (GetLastError ());
241     return GNUNET_SYSERR;
242   }
243   *size = (OFF_T) li.QuadPart;
244 #else
245   struct stat sbuf;
246
247   if (0 != FSTAT (fh->fd, &sbuf))
248     return GNUNET_SYSERR;
249   *size = sbuf.st_size;
250 #endif
251   return GNUNET_OK;
252 }
253
254
255 /**
256  * Move the read/write pointer in a file
257  *
258  * @param h handle of an open file
259  * @param offset position to move to
260  * @param whence specification to which position the offset parameter relates to
261  * @return the new position on success, GNUNET_SYSERR otherwise
262  */
263 OFF_T
264 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
265                        enum GNUNET_DISK_Seek whence)
266 {
267   if (h == NULL)
268   {
269     errno = EINVAL;
270     return GNUNET_SYSERR;
271   }
272
273 #ifdef MINGW
274   LARGE_INTEGER li;
275   LARGE_INTEGER new_pos;
276   BOOL b;
277
278   static DWORD t[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
279   li.QuadPart = offset;
280
281   b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
282   if (b == 0)
283   {
284     SetErrnoFromWinError (GetLastError ());
285     return GNUNET_SYSERR;
286   }
287   return (OFF_T) new_pos.QuadPart;
288 #else
289   static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
290
291   return lseek (h->fd, offset, t[whence]);
292 #endif
293 }
294
295
296 /**
297  * Get the size of the file (or directory) of the given file (in
298  * bytes).
299  *
300  * @param filename name of the file or directory
301  * @param size set to the size of the file (or,
302  *             in the case of directories, the sum
303  *             of all sizes of files in the directory)
304  * @param includeSymLinks should symbolic links be
305  *        included?
306  * @param singleFileMode GNUNET_YES to only get size of one file
307  *        and return GNUNET_SYSERR for directories.
308  * @return GNUNET_SYSERR on error, GNUNET_OK on success
309  */
310 int
311 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
312                        int includeSymLinks, int singleFileMode)
313 {
314   struct GetFileSizeData gfsd;
315   int ret;
316
317   GNUNET_assert (size != NULL);
318   gfsd.total = 0;
319   gfsd.include_sym_links = includeSymLinks;
320   gfsd.single_file_mode = singleFileMode;
321   ret = getSizeRec (&gfsd, filename);
322   *size = gfsd.total;
323   return ret;
324 }
325
326
327 /**
328  * Obtain some unique identifiers for the given file
329  * that can be used to identify it in the local system.
330  * This function is used between GNUnet processes to
331  * quickly check if two files with the same absolute path
332  * are actually identical.  The two processes represent
333  * the same peer but may communicate over the network
334  * (and the file may be on an NFS volume).  This function
335  * may not be supported on all operating systems.
336  *
337  * @param filename name of the file
338  * @param dev set to the device ID
339  * @param ino set to the inode ID
340  * @return GNUNET_OK on success
341  */
342 int
343 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
344                                   uint64_t * ino)
345 {
346 #if LINUX
347   struct stat sbuf;
348   struct statvfs fbuf;
349
350   if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
351   {
352     *dev = (uint64_t) fbuf.f_fsid;
353     *ino = (uint64_t) sbuf.st_ino;
354     return GNUNET_OK;
355   }
356 #elif SOMEBSD
357   struct stat sbuf;
358   struct statfs fbuf;
359
360   if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
361   {
362     *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
363         ((uint64_t) fbuf.f_fsid.val[1]);
364     *ino = (uint64_t) sbuf.st_ino;
365     return GNUNET_OK;
366   }
367 #elif WINDOWS
368   // FIXME NILS: test this
369   struct GNUNET_DISK_FileHandle *fh;
370   BY_HANDLE_FILE_INFORMATION info;
371   int succ;
372
373   fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
374   if (fh == NULL)
375     return GNUNET_SYSERR;
376   succ = GetFileInformationByHandle (fh->h, &info);
377   GNUNET_DISK_file_close (fh);
378   if (succ)
379   {
380     *dev = info.dwVolumeSerialNumber;
381     *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
382     return GNUNET_OK;
383   }
384   else
385     return GNUNET_SYSERR;
386
387 #endif
388   return GNUNET_SYSERR;
389 }
390
391
392 /**
393  * Create the name for a temporary file or directory from a template.
394  *
395  * @param t template (without XXXXX or "/tmp/")
396  * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
397  */
398 static char *
399 mktemp_name (const char *t)
400 {
401   const char *tmpdir;
402   char *tmpl;
403   char *fn;
404
405   if ((t[0] != '/') && (t[0] != '\\')
406 #if WINDOWS
407       && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
408 #endif
409       )
410   {
411     /* FIXME: This uses system codepage on W32, not UTF-8 */
412     tmpdir = getenv ("TMPDIR");
413     if (NULL == tmpdir)
414       tmpdir = getenv ("TMP");
415     if (NULL == tmpdir)
416       tmpdir = getenv ("TEMP");  
417     if (NULL == tmpdir)
418       tmpdir = "/tmp";
419     GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
420   }
421   else
422   {
423     GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
424   }
425 #ifdef MINGW
426   fn = (char *) GNUNET_malloc (MAX_PATH + 1);
427   if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
428   {
429     GNUNET_free (fn);
430     GNUNET_free (tmpl);
431     return NULL;
432   }
433   GNUNET_free (tmpl);
434 #else
435   fn = tmpl;
436 #endif
437   return fn;
438 }
439
440
441 #if WINDOWS
442 static char *
443 mkdtemp (char *fn)
444 {
445   char *random_fn;
446   char *tfn;
447
448   while (1)
449   {
450     tfn = GNUNET_strdup (fn);
451     random_fn = _mktemp (tfn);
452     if (NULL == random_fn)
453     {
454       GNUNET_free (tfn);
455       return NULL;
456     }
457     /* FIXME: assume fn to be UTF-8-encoded and do the right thing */
458     if (0 == CreateDirectoryA (tfn, NULL))
459     {
460       DWORD error = GetLastError ();
461       GNUNET_free (tfn);
462       if (ERROR_ALREADY_EXISTS == error)
463         continue;
464       return NULL;
465     }
466     break;
467   }
468   strcpy (fn, tfn);
469   return fn;
470 }
471 #endif
472
473 /**
474  * Create an (empty) temporary directory on disk.  If the given name is not
475  * an absolute path, the current 'TMPDIR' will be prepended.  In any case,
476  * 6 random characters will be appended to the name to create a unique
477  * filename.
478  *
479  * @param t component to use for the name;
480  *        does NOT contain "XXXXXX" or "/tmp/".
481  * @return NULL on error, otherwise name of fresh
482  *         file on disk in directory for temporary files
483  */
484 char *
485 GNUNET_DISK_mkdtemp (const char *t)
486 {
487   char *fn;
488
489   fn = mktemp_name (t);
490   if (fn != mkdtemp (fn))
491   {
492     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
493     GNUNET_free (fn);
494     return NULL;
495   }
496   return fn;
497 }
498
499
500 /**
501  * Move a file out of the way (create a backup) by
502  * renaming it to "orig.NUM~" where NUM is the smallest
503  * number that is not used yet.
504  *
505  * @param fil name of the file to back up
506  */
507 void
508 GNUNET_DISK_file_backup (const char *fil)
509 {
510   size_t slen;
511   char *target;
512   unsigned int num;
513
514   slen = strlen (fil) + 20;
515   target = GNUNET_malloc (slen);
516   num = 0;
517   do
518   {
519     GNUNET_snprintf (target, slen,
520                      "%s.%u~",
521                      fil,
522                      num++);
523   } while (0 == access (target, F_OK));
524   if (0 != rename (fil, target))
525     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
526                               "rename",
527                               fil);
528   GNUNET_free (target);  
529 }
530
531
532 /**
533  * Create an (empty) temporary file on disk.  If the given name is not
534  * an absolute path, the current 'TMPDIR' will be prepended.  In any case,
535  * 6 random characters will be appended to the name to create a unique
536  * filename.
537  *
538  * @param t component to use for the name;
539  *        does NOT contain "XXXXXX" or "/tmp/".
540  * @return NULL on error, otherwise name of fresh
541  *         file on disk in directory for temporary files
542  */
543 char *
544 GNUNET_DISK_mktemp (const char *t)
545 {
546   int fd;
547   char *fn;
548
549   fn = mktemp_name (t);
550   if (-1 == (fd = mkstemp (fn)))
551   {
552     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
553     GNUNET_free (fn);
554     return NULL;
555   }
556   if (0 != CLOSE (fd))
557     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
558   return fn;
559 }
560
561
562 /**
563  * Test if "fil" is a directory and listable. Optionally, also check if the
564  * directory is readable.  Will not print an error message if the directory does
565  * not exist.  Will log errors if GNUNET_SYSERR is returned (i.e., a file exists
566  * with the same name).
567  *
568  * @param fil filename to test
569  * @param is_readable GNUNET_YES to additionally check if "fil" is readable;
570  *          GNUNET_NO to disable this check
571  * @return GNUNET_YES if yes, GNUNET_NO if not; GNUNET_SYSERR if it
572  *           does not exist or stat'ed
573  */
574 int
575 GNUNET_DISK_directory_test (const char *fil, int is_readable)
576 {
577   struct stat filestat;
578   int ret;
579
580   ret = STAT (fil, &filestat);
581   if (ret != 0)
582   {
583     if (errno != ENOENT)
584       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
585     return GNUNET_SYSERR;
586   }
587   if (!S_ISDIR (filestat.st_mode))
588   {
589     LOG (GNUNET_ERROR_TYPE_WARNING,
590          "A file already exits with the same name %s\n", fil);
591     return GNUNET_NO;
592   }
593   if (GNUNET_YES == is_readable)
594     ret = ACCESS (fil, R_OK | X_OK);
595   else
596     ret = ACCESS (fil, X_OK);
597   if (ret < 0)
598   {
599     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
600     return GNUNET_NO;
601   }
602   return GNUNET_YES;
603 }
604
605
606 /**
607  * Check that fil corresponds to a filename
608  * (of a file that exists and that is not a directory).
609  *
610  * @param fil filename to check
611  * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
612  * else (will print an error message in that case, too).
613  */
614 int
615 GNUNET_DISK_file_test (const char *fil)
616 {
617   struct stat filestat;
618   int ret;
619   char *rdir;
620
621   rdir = GNUNET_STRINGS_filename_expand (fil);
622   if (rdir == NULL)
623     return GNUNET_SYSERR;
624
625   ret = STAT (rdir, &filestat);
626   if (ret != 0)
627   {
628     if (errno != ENOENT)
629     {
630       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
631       GNUNET_free (rdir);
632       return GNUNET_SYSERR;
633     }
634     GNUNET_free (rdir);
635     return GNUNET_NO;
636   }
637   if (!S_ISREG (filestat.st_mode))
638   {
639     GNUNET_free (rdir);
640     return GNUNET_NO;
641   }
642   if (ACCESS (rdir, F_OK) < 0)
643   {
644     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
645     GNUNET_free (rdir);
646     return GNUNET_SYSERR;
647   }
648   GNUNET_free (rdir);
649   return GNUNET_YES;
650 }
651
652
653 /**
654  * Implementation of "mkdir -p"
655  * @param dir the directory to create
656  * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
657  */
658 int
659 GNUNET_DISK_directory_create (const char *dir)
660 {
661   char *rdir;
662   unsigned int len;
663   unsigned int pos;
664   unsigned int pos2;
665   int ret = GNUNET_OK;
666
667   rdir = GNUNET_STRINGS_filename_expand (dir);
668   if (rdir == NULL)
669     return GNUNET_SYSERR;
670
671   len = strlen (rdir);
672 #ifndef MINGW
673   pos = 1;                      /* skip heading '/' */
674 #else
675   /* Local or Network path? */
676   if (strncmp (rdir, "\\\\", 2) == 0)
677   {
678     pos = 2;
679     while (rdir[pos])
680     {
681       if (rdir[pos] == '\\')
682       {
683         pos++;
684         break;
685       }
686       pos++;
687     }
688   }
689   else
690   {
691     pos = 3;                    /* strlen("C:\\") */
692   }
693 #endif
694   /* Check which low level directories already exist */
695   pos2 = len;
696   rdir[len] = DIR_SEPARATOR;
697   while (pos <= pos2)
698   {
699     if (DIR_SEPARATOR == rdir[pos2])
700     {
701       rdir[pos2] = '\0';
702       ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
703       if (GNUNET_NO == ret)
704       {
705         GNUNET_free (rdir);
706         return GNUNET_SYSERR;
707       }
708       rdir[pos2] = DIR_SEPARATOR;
709       if (GNUNET_YES == ret)
710       {
711         pos2++;
712         break;
713       }
714     }
715     pos2--;
716   }
717   rdir[len] = '\0';
718   if (pos < pos2)
719     pos = pos2;
720   /* Start creating directories */
721   while (pos <= len)
722   {
723     if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
724     {
725       rdir[pos] = '\0';
726       ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
727       if (GNUNET_NO == ret)
728       {
729         GNUNET_free (rdir);
730         return GNUNET_SYSERR;
731       }
732       if (GNUNET_SYSERR == ret)
733       {
734 #ifndef MINGW
735         ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);        /* 755 */
736 #else
737         wchar_t wrdir[MAX_PATH + 1];
738         if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
739           ret = !CreateDirectoryW (wrdir, NULL);
740         else
741           ret = 1;
742 #endif
743         if ((ret != 0) && (errno != EEXIST))
744         {
745           LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
746           GNUNET_free (rdir);
747           return GNUNET_SYSERR;
748         }
749       }
750       rdir[pos] = DIR_SEPARATOR;
751     }
752     pos++;
753   }
754   GNUNET_free (rdir);
755   return GNUNET_OK;
756 }
757
758
759 /**
760  * Create the directory structure for storing
761  * a file.
762  *
763  * @param filename name of a file in the directory
764  * @returns GNUNET_OK on success,
765  *          GNUNET_SYSERR on failure,
766  *          GNUNET_NO if the directory
767  *          exists but is not writeable for us
768  */
769 int
770 GNUNET_DISK_directory_create_for_file (const char *filename)
771 {
772   char *rdir;
773   int len;
774   int ret;
775
776   rdir = GNUNET_STRINGS_filename_expand (filename);
777   if (rdir == NULL)
778     return GNUNET_SYSERR;
779   len = strlen (rdir);
780   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
781     len--;
782   rdir[len] = '\0';
783   ret = GNUNET_DISK_directory_create (rdir);
784   if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
785     ret = GNUNET_NO;
786   GNUNET_free (rdir);
787   return ret;
788 }
789
790
791 /**
792  * Read the contents of a binary file into a buffer.
793  * @param h handle to an open file
794  * @param result the buffer to write the result to
795  * @param len the maximum number of bytes to read
796  * @return the number of bytes read on success, GNUNET_SYSERR on failure
797  */
798 ssize_t
799 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
800                        size_t len)
801 {
802   if (h == NULL)
803   {
804     errno = EINVAL;
805     return GNUNET_SYSERR;
806   }
807
808 #ifdef MINGW
809   DWORD bytesRead;
810
811   if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
812   {
813     if (!ReadFile (h->h, result, len, &bytesRead, NULL))
814     {
815       SetErrnoFromWinError (GetLastError ());
816       return GNUNET_SYSERR;
817     }
818   }
819   else
820   {
821     if (!ReadFile (h->h, result, len, &bytesRead, 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, &bytesRead, TRUE);
831     }
832     LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
833   }
834   return bytesRead;
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 (h == NULL)
857   {
858     errno = EINVAL;
859     return GNUNET_SYSERR;
860   }
861
862 #ifdef MINGW
863   DWORD bytesRead;
864
865   if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
866   {
867     if (!ReadFile (h->h, result, len, &bytesRead, NULL))
868     {
869       SetErrnoFromWinError (GetLastError ());
870       return GNUNET_SYSERR;
871     }
872   }
873   else
874   {
875     if (!ReadFile (h->h, result, len, &bytesRead, 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", bytesRead);
893   }
894   return bytesRead;
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, void *result, size_t len)
925 {
926   struct GNUNET_DISK_FileHandle *fh;
927   ssize_t ret;
928
929   fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
930   if (!fh)
931     return GNUNET_SYSERR;
932   ret = GNUNET_DISK_file_read (fh, result, len);
933   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
934
935   return ret;
936 }
937
938
939 /**
940  * Write a buffer to a file.
941  * @param h handle to open file
942  * @param buffer the data to write
943  * @param n number of bytes to write
944  * @return number of bytes written on success, GNUNET_SYSERR on error
945  */
946 ssize_t
947 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
948                         const void *buffer, size_t n)
949 {
950   if (h == NULL)
951   {
952     errno = EINVAL;
953     return GNUNET_SYSERR;
954   }
955
956 #ifdef MINGW
957   DWORD bytesWritten;
958
959   if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
960   {
961     if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
962     {
963       SetErrnoFromWinError (GetLastError ());
964       return GNUNET_SYSERR;
965     }
966   }
967   else
968   {
969     LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
970     if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
971     {
972       if (GetLastError () != ERROR_IO_PENDING)
973       {
974         SetErrnoFromWinError (GetLastError ());
975         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
976             GetLastError ());
977         return GNUNET_SYSERR;
978       }
979       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
980       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
981       {
982         SetErrnoFromWinError (GetLastError ());
983         LOG (GNUNET_ERROR_TYPE_DEBUG,
984             "Error getting overlapped result while writing to pipe: %u\n",
985             GetLastError ());
986         return GNUNET_SYSERR;
987       }
988     }
989     else
990     {
991       DWORD ovr;
992       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
993       {
994         LOG (GNUNET_ERROR_TYPE_DEBUG,
995             "Error getting control overlapped result while writing to pipe: %u\n",
996             GetLastError ());
997       }
998       else
999       {
1000         LOG (GNUNET_ERROR_TYPE_DEBUG,
1001             "Wrote %u bytes (ovr says %u), picking the greatest\n",
1002             bytesWritten, ovr);
1003       }
1004     }
1005     if (bytesWritten == 0)
1006     {
1007       if (n > 0)
1008       {
1009         LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
1010         errno = EAGAIN;
1011         return GNUNET_SYSERR;
1012       }
1013     }
1014     LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1015   }
1016   return bytesWritten;
1017 #else
1018   return write (h->fd, buffer, n);
1019 #endif
1020 }
1021
1022
1023 /**
1024  * Write a buffer to a file, blocking, if necessary.
1025  * @param h handle to open file
1026  * @param buffer the data to write
1027  * @param n number of bytes to write
1028  * @return number of bytes written on success, GNUNET_SYSERR on error
1029  */
1030 ssize_t
1031 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1032     const void *buffer, size_t n)
1033 {
1034   if (h == NULL)
1035   {
1036     errno = EINVAL;
1037     return GNUNET_SYSERR;
1038   }
1039
1040 #ifdef MINGW
1041   DWORD bytesWritten;
1042   /* We do a non-overlapped write, which is as blocking as it gets */
1043   LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1044   if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1045   {
1046     SetErrnoFromWinError (GetLastError ());
1047     LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1048         GetLastError ());
1049     return GNUNET_SYSERR;
1050   }
1051   if (bytesWritten == 0 && n > 0)
1052   {
1053     LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1054     WaitForSingleObject (h->h, INFINITE);
1055     if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1056     {
1057       SetErrnoFromWinError (GetLastError ());
1058       LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1059           GetLastError ());
1060       return GNUNET_SYSERR;
1061     }
1062   }
1063   LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1064   return bytesWritten;
1065 #else
1066   int flags;
1067   ssize_t ret;
1068
1069   /* set to blocking, write, then set back */
1070   flags = fcntl (h->fd, F_GETFL);
1071   if (0 != (flags & O_NONBLOCK))
1072     (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1073   ret = write (h->fd, buffer, n);
1074   if (0 == (flags & O_NONBLOCK))
1075     (void) fcntl (h->fd, F_SETFL, flags);
1076   return ret;
1077 #endif
1078 }
1079
1080
1081 /**
1082  * Write a buffer to a file.  If the file is longer than the
1083  * number of bytes that will be written, it will be truncated.
1084  *
1085  * @param fn file name
1086  * @param buffer the data to write
1087  * @param n number of bytes to write
1088  * @param mode file permissions
1089  * @return number of bytes written on success, GNUNET_SYSERR on error
1090  */
1091 ssize_t
1092 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1093                       enum GNUNET_DISK_AccessPermissions mode)
1094 {
1095   struct GNUNET_DISK_FileHandle *fh;
1096   ssize_t ret;
1097
1098   fh = GNUNET_DISK_file_open (fn,
1099                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1100                               | GNUNET_DISK_OPEN_CREATE, mode);
1101   if (!fh)
1102     return GNUNET_SYSERR;
1103   ret = GNUNET_DISK_file_write (fh, buffer, n);
1104   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1105   return ret;
1106 }
1107
1108
1109 /**
1110  * Scan a directory for files.
1111  *
1112  * @param dirName the name of the directory
1113  * @param callback the method to call for each file,
1114  *        can be NULL, in that case, we only count
1115  * @param callback_cls closure for callback
1116  * @return the number of files found, GNUNET_SYSERR on error or
1117  *         ieration aborted by callback returning GNUNET_SYSERR
1118  */
1119 int
1120 GNUNET_DISK_directory_scan (const char *dirName,
1121                             GNUNET_FileNameCallback callback,
1122                             void *callback_cls)
1123 {
1124   DIR *dinfo;
1125   struct dirent *finfo;
1126   struct stat istat;
1127   int count = 0;
1128   int ret;
1129   char *name;
1130   char *dname;
1131   unsigned int name_len;
1132   unsigned int n_size;
1133
1134   GNUNET_assert (dirName != NULL);
1135   dname = GNUNET_STRINGS_filename_expand (dirName);
1136   if (dname == NULL)
1137     return GNUNET_SYSERR;
1138   while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1139     dname[strlen (dname) - 1] = '\0';
1140   if (0 != STAT (dname, &istat))
1141   {
1142     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1143     GNUNET_free (dname);
1144     return GNUNET_SYSERR;
1145   }
1146   if (!S_ISDIR (istat.st_mode))
1147   {
1148     LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1149          dirName);
1150     GNUNET_free (dname);
1151     return GNUNET_SYSERR;
1152   }
1153   errno = 0;
1154   dinfo = OPENDIR (dname);
1155   if ((errno == EACCES) || (dinfo == NULL))
1156   {
1157     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1158     if (dinfo != NULL)
1159       CLOSEDIR (dinfo);
1160     GNUNET_free (dname);
1161     return GNUNET_SYSERR;
1162   }
1163   name_len = 256;
1164   n_size = strlen (dname) + name_len + 2;
1165   name = GNUNET_malloc (n_size);
1166   while ((finfo = READDIR (dinfo)) != NULL)
1167   {
1168     if ((0 == strcmp (finfo->d_name, ".")) ||
1169         (0 == strcmp (finfo->d_name, "..")))
1170       continue;
1171     if (callback != NULL)
1172     {
1173       if (name_len < strlen (finfo->d_name))
1174       {
1175         GNUNET_free (name);
1176         name_len = strlen (finfo->d_name);
1177         n_size = strlen (dname) + name_len + 2;
1178         name = GNUNET_malloc (n_size);
1179       }
1180       /* dname can end in "/" only if dname == "/";
1181        * if dname does not end in "/", we need to add
1182        * a "/" (otherwise, we must not!) */
1183       GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1184                        (strcmp (dname, DIR_SEPARATOR_STR) ==
1185                         0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1186       ret = callback (callback_cls, name);
1187       if (GNUNET_OK != ret)
1188       {
1189         CLOSEDIR (dinfo);
1190         GNUNET_free (name);
1191         GNUNET_free (dname);
1192         if (GNUNET_NO == ret)
1193           return count;
1194         return GNUNET_SYSERR;
1195       }
1196     }
1197     count++;
1198   }
1199   CLOSEDIR (dinfo);
1200   GNUNET_free (name);
1201   GNUNET_free (dname);
1202   return count;
1203 }
1204
1205
1206 /**
1207  * Opaque handle used for iterating over a directory.
1208  */
1209 struct GNUNET_DISK_DirectoryIterator
1210 {
1211
1212   /**
1213    * Function to call on directory entries.
1214    */
1215   GNUNET_DISK_DirectoryIteratorCallback callback;
1216
1217   /**
1218    * Closure for callback.
1219    */
1220   void *callback_cls;
1221
1222   /**
1223    * Reference to directory.
1224    */
1225   DIR *directory;
1226
1227   /**
1228    * Directory name.
1229    */
1230   char *dirname;
1231
1232   /**
1233    * Next filename to process.
1234    */
1235   char *next_name;
1236
1237   /**
1238    * Our priority.
1239    */
1240   enum GNUNET_SCHEDULER_Priority priority;
1241
1242 };
1243
1244
1245 /**
1246  * Task used by the directory iterator.
1247  */
1248 static void
1249 directory_iterator_task (void *cls,
1250                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1251 {
1252   struct GNUNET_DISK_DirectoryIterator *iter = cls;
1253   char *name;
1254
1255   name = iter->next_name;
1256   GNUNET_assert (name != NULL);
1257   iter->next_name = NULL;
1258   iter->callback (iter->callback_cls, iter, name, iter->dirname);
1259   GNUNET_free (name);
1260 }
1261
1262
1263 /**
1264  * This function must be called during the DiskIteratorCallback
1265  * (exactly once) to schedule the task to process the next
1266  * filename in the directory (if there is one).
1267  *
1268  * @param iter opaque handle for the iterator
1269  * @param can set to GNUNET_YES to terminate the iteration early
1270  * @return GNUNET_YES if iteration will continue,
1271  *         GNUNET_NO if this was the last entry (and iteration is complete),
1272  *         GNUNET_SYSERR if abort was YES
1273  */
1274 int
1275 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1276                                      int can)
1277 {
1278   struct dirent *finfo;
1279
1280   GNUNET_assert (iter->next_name == NULL);
1281   if (can == GNUNET_YES)
1282   {
1283     CLOSEDIR (iter->directory);
1284     GNUNET_free (iter->dirname);
1285     GNUNET_free (iter);
1286     return GNUNET_SYSERR;
1287   }
1288   while (NULL != (finfo = READDIR (iter->directory)))
1289   {
1290     if ((0 == strcmp (finfo->d_name, ".")) ||
1291         (0 == strcmp (finfo->d_name, "..")))
1292       continue;
1293     GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1294                      DIR_SEPARATOR_STR, finfo->d_name);
1295     break;
1296   }
1297   if (finfo == NULL)
1298   {
1299     GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1300     return GNUNET_NO;
1301   }
1302   GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1303                                       iter);
1304   return GNUNET_YES;
1305 }
1306
1307
1308 /**
1309  * Scan a directory for files using the scheduler to run a task for
1310  * each entry.  The name of the directory must be expanded first (!).
1311  * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1312  * may provide a simpler API.
1313  *
1314  * @param prio priority to use
1315  * @param dirName the name of the directory
1316  * @param callback the method to call for each file
1317  * @param callback_cls closure for callback
1318  * @return GNUNET_YES if directory is not empty and 'callback'
1319  *         will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1320  */
1321 int
1322 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1323                                       const char *dirName,
1324                                       GNUNET_DISK_DirectoryIteratorCallback
1325                                       callback, void *callback_cls)
1326 {
1327   struct GNUNET_DISK_DirectoryIterator *di;
1328
1329   di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1330   di->callback = callback;
1331   di->callback_cls = callback_cls;
1332   di->directory = OPENDIR (dirName);
1333   if (di->directory == NULL)
1334   {
1335     GNUNET_free (di);
1336     callback (callback_cls, NULL, NULL, NULL);
1337     return GNUNET_SYSERR;
1338   }
1339   di->dirname = GNUNET_strdup (dirName);
1340   di->priority = prio;
1341   return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1342 }
1343
1344
1345 /**
1346  * Function that removes the given directory by calling
1347  * "GNUNET_DISK_directory_remove".
1348  *
1349  * @param unused not used
1350  * @param fn directory to remove
1351  * @return GNUNET_OK
1352  */
1353 static int
1354 remove_helper (void *unused, const char *fn)
1355 {
1356   (void) GNUNET_DISK_directory_remove (fn);
1357   return GNUNET_OK;
1358 }
1359
1360
1361 /**
1362  * Remove all files in a directory (rm -rf). Call with
1363  * caution.
1364  *
1365  *
1366  * @param filename the file to remove
1367  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1368  */
1369 int
1370 GNUNET_DISK_directory_remove (const char *filename)
1371 {
1372   struct stat istat;
1373
1374   if (0 != LSTAT (filename, &istat))
1375     return GNUNET_NO;           /* file may not exist... */
1376   (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1377   if (UNLINK (filename) == 0)
1378     return GNUNET_OK;
1379   if ((errno != EISDIR) &&
1380       /* EISDIR is not sufficient in all cases, e.g.
1381        * sticky /tmp directory may result in EPERM on BSD.
1382        * So we also explicitly check "isDirectory" */
1383       (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1384   {
1385     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1386     return GNUNET_SYSERR;
1387   }
1388   if (GNUNET_SYSERR ==
1389       GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1390     return GNUNET_SYSERR;
1391   if (0 != RMDIR (filename))
1392   {
1393     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1394     return GNUNET_SYSERR;
1395   }
1396   return GNUNET_OK;
1397 }
1398
1399
1400 /**
1401  * Copy a file.
1402  *
1403  * @param src file to copy
1404  * @param dst destination file name
1405  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1406  */
1407 int
1408 GNUNET_DISK_file_copy (const char *src, const char *dst)
1409 {
1410   char *buf;
1411   uint64_t pos;
1412   uint64_t size;
1413   size_t len;
1414   struct GNUNET_DISK_FileHandle *in;
1415   struct GNUNET_DISK_FileHandle *out;
1416
1417   if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1418     return GNUNET_SYSERR;
1419   pos = 0;
1420   in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1421                               GNUNET_DISK_PERM_NONE);
1422   if (!in)
1423     return GNUNET_SYSERR;
1424   out =
1425       GNUNET_DISK_file_open (dst,
1426                              GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1427                              GNUNET_DISK_OPEN_FAILIFEXISTS,
1428                              GNUNET_DISK_PERM_USER_READ |
1429                              GNUNET_DISK_PERM_USER_WRITE |
1430                              GNUNET_DISK_PERM_GROUP_READ |
1431                              GNUNET_DISK_PERM_GROUP_WRITE);
1432   if (!out)
1433   {
1434     GNUNET_DISK_file_close (in);
1435     return GNUNET_SYSERR;
1436   }
1437   buf = GNUNET_malloc (COPY_BLK_SIZE);
1438   while (pos < size)
1439   {
1440     len = COPY_BLK_SIZE;
1441     if (len > size - pos)
1442       len = size - pos;
1443     if (len != GNUNET_DISK_file_read (in, buf, len))
1444       goto FAIL;
1445     if (len != GNUNET_DISK_file_write (out, buf, len))
1446       goto FAIL;
1447     pos += len;
1448   }
1449   GNUNET_free (buf);
1450   GNUNET_DISK_file_close (in);
1451   GNUNET_DISK_file_close (out);
1452   return GNUNET_OK;
1453 FAIL:
1454   GNUNET_free (buf);
1455   GNUNET_DISK_file_close (in);
1456   GNUNET_DISK_file_close (out);
1457   return GNUNET_SYSERR;
1458 }
1459
1460
1461 /**
1462  * @brief Removes special characters as ':' from a filename.
1463  * @param fn the filename to canonicalize
1464  */
1465 void
1466 GNUNET_DISK_filename_canonicalize (char *fn)
1467 {
1468   char *idx;
1469   char c;
1470
1471   idx = fn;
1472   while (*idx)
1473   {
1474     c = *idx;
1475
1476     if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1477         c == '<' || c == '>' || c == '|')
1478     {
1479       *idx = '_';
1480     }
1481
1482     idx++;
1483   }
1484 }
1485
1486
1487
1488 /**
1489  * @brief Change owner of a file
1490  *
1491  * @param filename name of file to change the owner of
1492  * @param user name of the new owner
1493  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1494  */
1495 int
1496 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1497 {
1498 #ifndef MINGW
1499   struct passwd *pws;
1500
1501   pws = getpwnam (user);
1502   if (pws == NULL)
1503   {
1504     LOG (GNUNET_ERROR_TYPE_ERROR,
1505          _("Cannot obtain information about user `%s': %s\n"), user,
1506          STRERROR (errno));
1507     return GNUNET_SYSERR;
1508   }
1509   if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1510     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1511 #endif
1512   return GNUNET_OK;
1513 }
1514
1515
1516 /**
1517  * Lock a part of a file
1518  * @param fh file handle
1519  * @param lockStart absolute position from where to lock
1520  * @param lockEnd absolute position until where to lock
1521  * @param excl GNUNET_YES for an exclusive lock
1522  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1523  */
1524 int
1525 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1526                        OFF_T lockEnd, int excl)
1527 {
1528   if (fh == NULL)
1529   {
1530     errno = EINVAL;
1531     return GNUNET_SYSERR;
1532   }
1533
1534 #ifndef MINGW
1535   struct flock fl;
1536
1537   memset (&fl, 0, sizeof (struct flock));
1538   fl.l_type = excl ? F_WRLCK : F_RDLCK;
1539   fl.l_whence = SEEK_SET;
1540   fl.l_start = lockStart;
1541   fl.l_len = lockEnd;
1542
1543   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1544 #else
1545   OVERLAPPED o;
1546   OFF_T diff = lockEnd - lockStart;
1547   DWORD diff_low, diff_high;
1548   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1549   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1550
1551   memset (&o, 0, sizeof (OVERLAPPED));
1552   o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1553   o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1554
1555   if (!LockFileEx
1556       (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1557        0, diff_low, diff_high, &o))
1558   {
1559     SetErrnoFromWinError (GetLastError ());
1560     return GNUNET_SYSERR;
1561   }
1562
1563   return GNUNET_OK;
1564 #endif
1565 }
1566
1567
1568 /**
1569  * Unlock a part of a file
1570  * @param fh file handle
1571  * @param unlockStart absolute position from where to unlock
1572  * @param unlockEnd absolute position until where to unlock
1573  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1574  */
1575 int
1576 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1577                          OFF_T unlockEnd)
1578 {
1579   if (fh == NULL)
1580   {
1581     errno = EINVAL;
1582     return GNUNET_SYSERR;
1583   }
1584
1585 #ifndef MINGW
1586   struct flock fl;
1587
1588   memset (&fl, 0, sizeof (struct flock));
1589   fl.l_type = F_UNLCK;
1590   fl.l_whence = SEEK_SET;
1591   fl.l_start = unlockStart;
1592   fl.l_len = unlockEnd;
1593
1594   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1595 #else
1596   OVERLAPPED o;
1597   OFF_T diff = unlockEnd - unlockStart;
1598   DWORD diff_low, diff_high;
1599   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1600   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1601
1602   memset (&o, 0, sizeof (OVERLAPPED));
1603   o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1604   o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1605
1606   if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1607   {
1608     SetErrnoFromWinError (GetLastError ());
1609     return GNUNET_SYSERR;
1610   }
1611
1612   return GNUNET_OK;
1613 #endif
1614 }
1615
1616
1617 /**
1618  * Open a file.  Note that the access permissions will only be
1619  * used if a new file is created and if the underlying operating
1620  * system supports the given permissions.
1621  *
1622  * @param fn file name to be opened
1623  * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1624  * @param perm permissions for the newly created file, use
1625  *             GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1626  *             call (because of flags)
1627  * @return IO handle on success, NULL on error
1628  */
1629 struct GNUNET_DISK_FileHandle *
1630 GNUNET_DISK_file_open (const char *fn, 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 serviceName 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 *serviceName, ...)
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, serviceName, "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          serviceName);
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, serviceName);
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, serviceName);
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 /* Copyright Bob Byrnes  <byrnes <at> curl.com>
2170    http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2171 */
2172 /* Create a pipe, and return handles to the read and write ends,
2173    just like CreatePipe, but ensure that the write end permits
2174    FILE_READ_ATTRIBUTES access, on later versions of win32 where
2175    this is supported.  This access is needed by NtQueryInformationFile,
2176    which is used to implement select and nonblocking writes.
2177    Note that the return value is either NO_ERROR or GetLastError,
2178    unlike CreatePipe, which returns a bool for success or failure.  */
2179 static int
2180 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2181                         LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2182                         DWORD dwReadMode, DWORD dwWriteMode)
2183 {
2184   /* Default to error. */
2185   *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2186
2187   HANDLE read_pipe;
2188   HANDLE write_pipe;
2189
2190   /* Ensure that there is enough pipe buffer space for atomic writes.  */
2191   if (psize < PIPE_BUF)
2192     psize = PIPE_BUF;
2193
2194   char pipename[MAX_PATH];
2195
2196   /* Retry CreateNamedPipe as long as the pipe name is in use.
2197    * Retrying will probably never be necessary, but we want
2198    * to be as robust as possible.  */
2199   while (1)
2200   {
2201     static volatile LONG pipe_unique_id;
2202
2203     snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2204               getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2205     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2206          pipename, psize);
2207     /* Use CreateNamedPipe instead of CreatePipe, because the latter
2208      * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2209      * access, on versions of win32 earlier than WinXP SP2.
2210      * CreatePipe also stupidly creates a full duplex pipe, which is
2211      * a waste, since only a single direction is actually used.
2212      * It's important to only allow a single instance, to ensure that
2213      * the pipe was not created earlier by some other process, even if
2214      * the pid has been reused.  */
2215     read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,   /* max instances */
2216                                   psize,        /* output buffer size */
2217                                   psize,        /* input buffer size */
2218                                   NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2219
2220     if (read_pipe != INVALID_HANDLE_VALUE)
2221     {
2222       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2223       break;
2224     }
2225
2226     DWORD err = GetLastError ();
2227
2228     switch (err)
2229     {
2230     case ERROR_PIPE_BUSY:
2231       /* The pipe is already open with compatible parameters.
2232        * Pick a new name and retry.  */
2233       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2234       continue;
2235     case ERROR_ACCESS_DENIED:
2236       /* The pipe is already open with incompatible parameters.
2237        * Pick a new name and retry.  */
2238       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2239       continue;
2240     case ERROR_CALL_NOT_IMPLEMENTED:
2241       /* We are on an older Win9x platform without named pipes.
2242        * Return an anonymous pipe as the best approximation.  */
2243       LOG (GNUNET_ERROR_TYPE_DEBUG,
2244            "CreateNamedPipe not implemented, resorting to "
2245            "CreatePipe: size = %lu\n", psize);
2246       if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2247       {
2248         LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2249              *read_pipe_ptr,
2250              *write_pipe_ptr);
2251         return GNUNET_OK;
2252       }
2253       err = GetLastError ();
2254       LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2255       return err;
2256     default:
2257       LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2258       return err;
2259     }
2260     /* NOTREACHED */
2261   }
2262   LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2263
2264   /* Open the named pipe for writing.
2265    * Be sure to permit FILE_READ_ATTRIBUTES access.  */
2266   write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0,  /* share mode */
2267                             sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2268                             0); /* handle to template file */
2269
2270   if (write_pipe == INVALID_HANDLE_VALUE)
2271   {
2272     /* Failure. */
2273     DWORD err = GetLastError ();
2274
2275     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2276     CloseHandle (read_pipe);
2277     return err;
2278   }
2279   LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2280   /* Success. */
2281   *read_pipe_ptr = read_pipe;
2282   *write_pipe_ptr = write_pipe;
2283   return GNUNET_OK;
2284 }
2285 #endif
2286
2287
2288 /**
2289  * Creates an interprocess channel
2290  *
2291  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2292  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2293  * @param inherit_read inherit the parent processes stdin (only for windows)
2294  * @param inherit_write inherit the parent processes stdout (only for windows)
2295  * @return handle to the new pipe, NULL on error
2296  */
2297 struct GNUNET_DISK_PipeHandle *
2298 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2299 {
2300 #ifndef MINGW
2301   int fd[2];
2302   int ret;
2303   int eno;
2304
2305   ret = pipe (fd);
2306   if (ret == -1)
2307   {
2308     eno = errno;
2309     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2310     errno = eno;
2311     return NULL;
2312   }
2313   return GNUNET_DISK_pipe_from_fd (blocking_read,
2314                                    blocking_write,
2315                                    fd);
2316 #else
2317   struct GNUNET_DISK_PipeHandle *p;
2318   BOOL ret;
2319   HANDLE tmp_handle;
2320   int save_errno;
2321
2322   p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2323   p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2324   p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2325
2326   /* All pipes are overlapped. If you want them to block - just
2327    * call WriteFile() and ReadFile() with NULL overlapped pointer.
2328    * NOTE: calling with NULL overlapped pointer works only
2329    * for pipes, and doesn't seem to be a documented feature.
2330    * It will NOT work for files, because overlapped files need
2331    * to read offsets from the overlapped structure, regardless.
2332    * Pipes are not seekable, and need no offsets, which is
2333    * probably why it works for them.
2334    */
2335   ret =
2336       create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2337                               FILE_FLAG_OVERLAPPED,
2338                               FILE_FLAG_OVERLAPPED);
2339   if (!ret)
2340   {
2341     SetErrnoFromWinError (GetLastError ());
2342     save_errno = errno;
2343     GNUNET_free (p->fd[0]);
2344     GNUNET_free (p->fd[1]);
2345     GNUNET_free (p);
2346     errno = save_errno;
2347     return NULL;
2348   }
2349   if (!DuplicateHandle
2350       (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2351        inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2352   {
2353     SetErrnoFromWinError (GetLastError ());
2354     save_errno = errno;
2355     CloseHandle (p->fd[0]->h);
2356     CloseHandle (p->fd[1]->h);
2357     GNUNET_free (p->fd[0]);
2358     GNUNET_free (p->fd[1]);
2359     GNUNET_free (p);
2360     errno = save_errno;
2361     return NULL;
2362   }
2363   CloseHandle (p->fd[0]->h);
2364   p->fd[0]->h = tmp_handle;
2365
2366   if (!DuplicateHandle
2367       (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2368        inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2369   {
2370     SetErrnoFromWinError (GetLastError ());
2371     save_errno = errno;
2372     CloseHandle (p->fd[0]->h);
2373     CloseHandle (p->fd[1]->h);
2374     GNUNET_free (p->fd[0]);
2375     GNUNET_free (p->fd[1]);
2376     GNUNET_free (p);
2377     errno = save_errno;
2378     return NULL;
2379   }
2380   CloseHandle (p->fd[1]->h);
2381   p->fd[1]->h = tmp_handle;
2382
2383   p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2384   p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2385
2386   p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2387   p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2388   p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2389   p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2390
2391   p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2392   p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2393
2394   p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2395   p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2396
2397   return p;
2398 #endif
2399 }
2400
2401
2402 /**
2403  * Creates a pipe object from a couple of file descriptors.
2404  * Useful for wrapping existing pipe FDs.
2405  *
2406  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2407  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2408  * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2409  *
2410  * @return handle to the new pipe, NULL on error
2411  */
2412 struct GNUNET_DISK_PipeHandle *
2413 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2414 {
2415   struct GNUNET_DISK_PipeHandle *p;
2416
2417   p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2418
2419 #ifndef MINGW
2420   int ret;
2421   int flags;
2422   int eno = 0; /* make gcc happy */
2423
2424   ret = 0;
2425   if (fd[0] >= 0)
2426   {
2427     p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2428     p->fd[0]->fd = fd[0];
2429     if (!blocking_read)
2430     {
2431       flags = fcntl (fd[0], F_GETFL);
2432       flags |= O_NONBLOCK;
2433       if (0 > fcntl (fd[0], F_SETFL, flags))
2434       {
2435         ret = -1;
2436         eno = errno;
2437       }
2438     }
2439     flags = fcntl (fd[0], F_GETFD);
2440     flags |= FD_CLOEXEC;
2441     if (0 > fcntl (fd[0], F_SETFD, flags))
2442     {
2443       ret = -1;
2444       eno = errno;
2445     }
2446   }
2447
2448   if (fd[1] >= 0)
2449   {
2450     p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2451     p->fd[1]->fd = fd[1];
2452     if (!blocking_write)
2453     {
2454       flags = fcntl (fd[1], F_GETFL);
2455       flags |= O_NONBLOCK;
2456       if (0 > fcntl (fd[1], F_SETFL, flags))
2457       {
2458         ret = -1;
2459         eno = errno;
2460       }
2461     }
2462     flags = fcntl (fd[1], F_GETFD);
2463     flags |= FD_CLOEXEC;
2464     if (0 > fcntl (fd[1], F_SETFD, flags))
2465     {
2466       ret = -1;
2467       eno = errno;
2468     }
2469   }
2470   if (ret == -1)
2471   {
2472     errno = eno;
2473     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2474     if (p->fd[0]->fd >= 0)
2475       GNUNET_break (0 == close (p->fd[0]->fd));
2476     if (p->fd[1]->fd >= 0)
2477       GNUNET_break (0 == close (p->fd[1]->fd));
2478     GNUNET_free_non_null (p->fd[0]);
2479     GNUNET_free_non_null (p->fd[1]);
2480     GNUNET_free (p);
2481     errno = eno;
2482     return NULL;
2483   }
2484 #else
2485   if (fd[0] >= 0)
2486   {
2487     p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2488     p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2489     if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2490     {
2491       p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2492       p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2493       p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2494       p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2495       p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2496     }
2497     else
2498     {
2499       GNUNET_free (p->fd[0]);
2500       p->fd[0] = NULL;
2501     }
2502   }
2503   if (fd[1] >= 0)
2504   {
2505     p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2506     p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2507     if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2508     {
2509       p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2510       p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2511       p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2512       p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2513       p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2514     }
2515     else
2516     {
2517       GNUNET_free (p->fd[1]);
2518       p->fd[1] = NULL;
2519     }
2520   }
2521
2522 #endif
2523   return p;
2524 }
2525
2526
2527 /**
2528  * Closes an interprocess channel
2529  *
2530  * @param p pipe to close
2531  * @param end which end of the pipe to close
2532  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2533  */
2534 int
2535 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2536                             enum GNUNET_DISK_PipeEnd end)
2537 {
2538   int ret = GNUNET_OK;
2539
2540   if (end == GNUNET_DISK_PIPE_END_READ)
2541   {
2542     if (p->fd[0])
2543     {
2544       ret = GNUNET_DISK_file_close (p->fd[0]);
2545       p->fd[0] = NULL;
2546     }
2547   }
2548   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2549   {
2550     if (p->fd[1])
2551     {
2552       ret = GNUNET_DISK_file_close (p->fd[1]);
2553       p->fd[1] = NULL;
2554     }
2555   }
2556
2557   return ret;
2558 }
2559
2560 /**
2561  * Detaches one of the ends from the pipe.
2562  * Detached end is a fully-functional FileHandle, it will
2563  * not be affected by anything you do with the pipe afterwards.
2564  * Each end of a pipe can only be detched from it once (i.e.
2565  * it is not duplicated).
2566  *
2567  * @param p pipe to detach an end from
2568  * @param end which end of the pipe to detach
2569  * @return Detached end on success, NULL on failure
2570  * (or if that end is not present or is closed).
2571  */
2572 struct GNUNET_DISK_FileHandle *
2573 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2574                              enum GNUNET_DISK_PipeEnd end)
2575 {
2576   struct GNUNET_DISK_FileHandle *ret = NULL;
2577
2578   if (end == GNUNET_DISK_PIPE_END_READ)
2579   {
2580     if (p->fd[0])
2581     {
2582       ret = p->fd[0];
2583       p->fd[0] = NULL;
2584     }
2585   }
2586   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2587   {
2588     if (p->fd[1])
2589     {
2590       ret = p->fd[1];
2591       p->fd[1] = NULL;
2592     }
2593   }
2594
2595   return ret;
2596 }
2597
2598
2599 /**
2600  * Closes an interprocess channel
2601  *
2602  * @param p pipe to close
2603  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2604  */
2605 int
2606 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2607 {
2608   int ret = GNUNET_OK;
2609
2610   int read_end_close;
2611   int write_end_close;
2612   int read_end_close_errno;
2613   int write_end_close_errno;
2614
2615   read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2616   read_end_close_errno = errno;
2617   write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2618   write_end_close_errno = errno;
2619   GNUNET_free (p);
2620
2621   if (GNUNET_OK != read_end_close)
2622   {
2623     errno = read_end_close_errno;
2624     ret = read_end_close;
2625   }
2626   else if (GNUNET_OK != write_end_close)
2627   {
2628     errno = write_end_close_errno;
2629     ret = write_end_close;
2630   }
2631
2632   return ret;
2633 }
2634
2635
2636 /**
2637  * Get the handle to a particular pipe end
2638  *
2639  * @param p pipe
2640  * @param n end to access
2641  * @return handle for the respective end
2642  */
2643 const struct GNUNET_DISK_FileHandle *
2644 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2645                          enum GNUNET_DISK_PipeEnd n)
2646 {
2647   switch (n)
2648   {
2649   case GNUNET_DISK_PIPE_END_READ:
2650   case GNUNET_DISK_PIPE_END_WRITE:
2651     return p->fd[n];
2652   default:
2653     GNUNET_break (0);
2654     return NULL;
2655   }
2656 }
2657
2658
2659 /**
2660  * Retrieve OS file handle
2661  * @internal
2662  * @param fh GNUnet file descriptor
2663  * @param dst destination buffer
2664  * @param dst_len length of dst
2665  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2666  */
2667 int
2668 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2669                                    void *dst, size_t dst_len)
2670 {
2671 #ifdef MINGW
2672   if (dst_len < sizeof (HANDLE))
2673     return GNUNET_SYSERR;
2674   *((HANDLE *) dst) = fh->h;
2675 #else
2676   if (dst_len < sizeof (int))
2677     return GNUNET_SYSERR;
2678   *((int *) dst) = fh->fd;
2679 #endif
2680
2681   return GNUNET_OK;
2682 }
2683
2684 /* end of disk.c */