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