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