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