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