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