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