- fix end of kx condition to reception of valid payload only
[oweals/gnunet.git] / src / util / disk.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001--2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 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
804  * a file.
805  *
806  * @param filename name of a file in the directory
807  * @returns #GNUNET_OK on success,
808  *          #GNUNET_SYSERR on failure,
809  *          #GNUNET_NO if the directory
810  *          exists but is not writeable for us
811  */
812 int
813 GNUNET_DISK_directory_create_for_file (const char *filename)
814 {
815   char *rdir;
816   size_t len;
817   int ret;
818
819   rdir = GNUNET_STRINGS_filename_expand (filename);
820   if (rdir == NULL)
821     return GNUNET_SYSERR;
822   len = strlen (rdir);
823   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
824     len--;
825   rdir[len] = '\0';
826   ret = GNUNET_DISK_directory_create (rdir);
827   if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
828     ret = GNUNET_NO;
829   GNUNET_free (rdir);
830   return ret;
831 }
832
833
834 /**
835  * Read the contents of a binary file into a buffer.
836  *
837  * @param h handle to an open file
838  * @param result the buffer to write the result to
839  * @param len the maximum number of bytes to read
840  * @return the number of bytes read on success, #GNUNET_SYSERR on failure
841  */
842 ssize_t
843 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
844                        void *result,
845                        size_t len)
846 {
847   if (NULL == h)
848   {
849     errno = EINVAL;
850     return GNUNET_SYSERR;
851   }
852
853 #ifdef MINGW
854   DWORD bytes_read;
855
856   if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
857   {
858     if (!ReadFile (h->h, result, len, &bytes_read, NULL))
859     {
860       SetErrnoFromWinError (GetLastError ());
861       return GNUNET_SYSERR;
862     }
863   }
864   else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
865   {
866     if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
867     {
868       if (GetLastError () != ERROR_IO_PENDING)
869       {
870         LOG (GNUNET_ERROR_TYPE_DEBUG,
871              "Error reading from pipe: %u\n",
872              GetLastError ());
873         SetErrnoFromWinError (GetLastError ());
874         return GNUNET_SYSERR;
875       }
876       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
877       GetOverlappedResult (h->h, h->oOverlapRead, &bytes_read, TRUE);
878     }
879     LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytes_read);
880   }
881   else
882   {
883     bytes_read = 0;
884   }
885   return bytes_read;
886 #else
887   return read (h->fd, result, len);
888 #endif
889 }
890
891
892 /**
893  * Read the contents of a binary file into a buffer.
894  * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
895  * when no data can be read).
896  *
897  * @param h handle to an open file
898  * @param result the buffer to write the result to
899  * @param len the maximum number of bytes to read
900  * @return the number of bytes read on success, #GNUNET_SYSERR on failure
901  */
902 ssize_t
903 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
904                                     void *result,
905                                     size_t len)
906 {
907   if (NULL == h)
908   {
909     errno = EINVAL;
910     return GNUNET_SYSERR;
911   }
912
913 #ifdef MINGW
914   DWORD bytes_read;
915
916   if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
917   {
918     if (!ReadFile (h->h, result, len, &bytes_read, NULL))
919     {
920       SetErrnoFromWinError (GetLastError ());
921       return GNUNET_SYSERR;
922     }
923   }
924   else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
925   {
926     if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
927     {
928       if (GetLastError () != ERROR_IO_PENDING)
929       {
930         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
931         SetErrnoFromWinError (GetLastError ());
932         return GNUNET_SYSERR;
933       }
934       else
935       {
936         LOG (GNUNET_ERROR_TYPE_DEBUG,
937             "ReadFile() queued a read, cancelling\n");
938         CancelIo (h->h);
939         errno = EAGAIN;
940         return GNUNET_SYSERR;
941       }
942     }
943     LOG (GNUNET_ERROR_TYPE_DEBUG,
944          "Read %u bytes\n",
945          bytes_read);
946   }
947   else
948   {
949     bytes_read = 0;
950   }
951   return bytes_read;
952 #else
953   int flags;
954   ssize_t ret;
955
956   /* set to non-blocking, read, then set back */
957   flags = fcntl (h->fd, F_GETFL);
958   if (0 == (flags & O_NONBLOCK))
959     (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
960   ret = read (h->fd, result, len);
961   if (0 == (flags & O_NONBLOCK))
962     {
963       int eno = errno;
964       (void) fcntl (h->fd, F_SETFL, flags);
965       errno = eno;
966     }
967   return ret;
968 #endif
969 }
970
971
972 /**
973  * Read the contents of a binary file into a buffer.
974  *
975  * @param fn file name
976  * @param result the buffer to write the result to
977  * @param len the maximum number of bytes to read
978  * @return number of bytes read, #GNUNET_SYSERR on failure
979  */
980 ssize_t
981 GNUNET_DISK_fn_read (const char *fn,
982                      void *result,
983                      size_t len)
984 {
985   struct GNUNET_DISK_FileHandle *fh;
986   ssize_t ret;
987   int eno;
988
989   fh = GNUNET_DISK_file_open (fn,
990                               GNUNET_DISK_OPEN_READ,
991                               GNUNET_DISK_PERM_NONE);
992   if (NULL == fh)
993     return GNUNET_SYSERR;
994   ret = GNUNET_DISK_file_read (fh, result, len);
995   eno = errno;
996   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
997   errno = eno;
998   return ret;
999 }
1000
1001
1002 /**
1003  * Write a buffer to a file.
1004  *
1005  * @param h handle to open file
1006  * @param buffer the data to write
1007  * @param n number of bytes to write
1008  * @return number of bytes written on success, #GNUNET_SYSERR on error
1009  */
1010 ssize_t
1011 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
1012                         const void *buffer, size_t n)
1013 {
1014   if (NULL == h)
1015   {
1016     errno = EINVAL;
1017     return GNUNET_SYSERR;
1018   }
1019
1020 #ifdef MINGW
1021   DWORD bytes_written;
1022
1023   if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
1024   {
1025     if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1026     {
1027       SetErrnoFromWinError (GetLastError ());
1028       return GNUNET_SYSERR;
1029     }
1030   }
1031   else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1032   {
1033     LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
1034     if (!WriteFile (h->h, buffer, n, &bytes_written, h->oOverlapWrite))
1035     {
1036       if (GetLastError () != ERROR_IO_PENDING)
1037       {
1038         SetErrnoFromWinError (GetLastError ());
1039         LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1040             GetLastError ());
1041         return GNUNET_SYSERR;
1042       }
1043       LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
1044       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytes_written, TRUE))
1045       {
1046         SetErrnoFromWinError (GetLastError ());
1047         LOG (GNUNET_ERROR_TYPE_DEBUG,
1048             "Error getting overlapped result while writing to pipe: %u\n",
1049             GetLastError ());
1050         return GNUNET_SYSERR;
1051       }
1052     }
1053     else
1054     {
1055       DWORD ovr;
1056       if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1057       {
1058         LOG (GNUNET_ERROR_TYPE_DEBUG,
1059             "Error getting control overlapped result while writing to pipe: %u\n",
1060             GetLastError ());
1061       }
1062       else
1063       {
1064         LOG (GNUNET_ERROR_TYPE_DEBUG,
1065             "Wrote %u bytes (ovr says %u), picking the greatest\n",
1066             bytes_written, ovr);
1067       }
1068     }
1069     if (bytes_written == 0)
1070     {
1071       if (n > 0)
1072       {
1073         LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytes_written);
1074         errno = EAGAIN;
1075         return GNUNET_SYSERR;
1076       }
1077     }
1078     LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytes_written);
1079   }
1080   else
1081   {
1082     bytes_written = 0;
1083   }
1084   return bytes_written;
1085 #else
1086   return write (h->fd, buffer, n);
1087 #endif
1088 }
1089
1090
1091 /**
1092  * Write a buffer to a file, blocking, if necessary.
1093  *
1094  * @param h handle to open file
1095  * @param buffer the data to write
1096  * @param n number of bytes to write
1097  * @return number of bytes written on success, #GNUNET_SYSERR on error
1098  */
1099 ssize_t
1100 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1101                                  const void *buffer,
1102                                  size_t n)
1103 {
1104   if (NULL == h)
1105   {
1106     errno = EINVAL;
1107     return GNUNET_SYSERR;
1108   }
1109
1110 #ifdef MINGW
1111   DWORD bytes_written;
1112   /* We do a non-overlapped write, which is as blocking as it gets */
1113   LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1114   if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1115   {
1116     SetErrnoFromWinError (GetLastError ());
1117     LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1118         GetLastError ());
1119     return GNUNET_SYSERR;
1120   }
1121   if (bytes_written == 0 && n > 0)
1122   {
1123     LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1124     WaitForSingleObject (h->h, INFINITE);
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   }
1133   LOG (GNUNET_ERROR_TYPE_DEBUG,
1134        "Wrote %u bytes\n",
1135        bytes_written);
1136   return bytes_written;
1137 #else
1138   int flags;
1139   ssize_t ret;
1140
1141   /* set to blocking, write, then set back */
1142   flags = fcntl (h->fd, F_GETFL);
1143   if (0 != (flags & O_NONBLOCK))
1144     (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1145   ret = write (h->fd, buffer, n);
1146   if (0 == (flags & O_NONBLOCK))
1147     (void) fcntl (h->fd, F_SETFL, flags);
1148   return ret;
1149 #endif
1150 }
1151
1152
1153 /**
1154  * Write a buffer to a file.  If the file is longer than the
1155  * number of bytes that will be written, it will be truncated.
1156  *
1157  * @param fn file name
1158  * @param buffer the data to write
1159  * @param n number of bytes to write
1160  * @param mode file permissions
1161  * @return number of bytes written on success, #GNUNET_SYSERR on error
1162  */
1163 ssize_t
1164 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1165                       enum GNUNET_DISK_AccessPermissions mode)
1166 {
1167   struct GNUNET_DISK_FileHandle *fh;
1168   ssize_t ret;
1169
1170   fh = GNUNET_DISK_file_open (fn,
1171                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1172                               | GNUNET_DISK_OPEN_CREATE, mode);
1173   if (!fh)
1174     return GNUNET_SYSERR;
1175   ret = GNUNET_DISK_file_write (fh, buffer, n);
1176   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1177   return ret;
1178 }
1179
1180
1181 /**
1182  * Scan a directory for files.
1183  *
1184  * @param dir_name the name of the directory
1185  * @param callback the method to call for each file,
1186  *        can be NULL, in that case, we only count
1187  * @param callback_cls closure for @a callback
1188  * @return the number of files found, #GNUNET_SYSERR on error or
1189  *         ieration aborted by callback returning #GNUNET_SYSERR
1190  */
1191 int
1192 GNUNET_DISK_directory_scan (const char *dir_name,
1193                             GNUNET_FileNameCallback callback,
1194                             void *callback_cls)
1195 {
1196   DIR *dinfo;
1197   struct dirent *finfo;
1198   struct stat istat;
1199   int count = 0;
1200   int ret;
1201   char *name;
1202   char *dname;
1203   unsigned int name_len;
1204   unsigned int n_size;
1205
1206   GNUNET_assert (NULL != dir_name);
1207   dname = GNUNET_STRINGS_filename_expand (dir_name);
1208   if (dname == NULL)
1209     return GNUNET_SYSERR;
1210   while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1211     dname[strlen (dname) - 1] = '\0';
1212   if (0 != STAT (dname, &istat))
1213   {
1214     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1215     GNUNET_free (dname);
1216     return GNUNET_SYSERR;
1217   }
1218   if (! S_ISDIR (istat.st_mode))
1219   {
1220     LOG (GNUNET_ERROR_TYPE_WARNING,
1221          _("Expected `%s' to be a directory!\n"),
1222          dir_name);
1223     GNUNET_free (dname);
1224     return GNUNET_SYSERR;
1225   }
1226   errno = 0;
1227   dinfo = OPENDIR (dname);
1228   if ((errno == EACCES) || (NULL == dinfo))
1229   {
1230     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1231     if (dinfo != NULL)
1232       CLOSEDIR (dinfo);
1233     GNUNET_free (dname);
1234     return GNUNET_SYSERR;
1235   }
1236   name_len = 256;
1237   n_size = strlen (dname) + name_len + 2;
1238   name = GNUNET_malloc (n_size);
1239   while (NULL != (finfo = READDIR (dinfo)))
1240   {
1241     if ((0 == strcmp (finfo->d_name, ".")) ||
1242         (0 == strcmp (finfo->d_name, "..")))
1243       continue;
1244     if (NULL != callback)
1245     {
1246       if (name_len < strlen (finfo->d_name))
1247       {
1248         GNUNET_free (name);
1249         name_len = strlen (finfo->d_name);
1250         n_size = strlen (dname) + name_len + 2;
1251         name = GNUNET_malloc (n_size);
1252       }
1253       /* dname can end in "/" only if dname == "/";
1254        * if dname does not end in "/", we need to add
1255        * a "/" (otherwise, we must not!) */
1256       GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1257                        (strcmp (dname, DIR_SEPARATOR_STR) ==
1258                         0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1259       ret = callback (callback_cls, name);
1260       if (GNUNET_OK != ret)
1261       {
1262         CLOSEDIR (dinfo);
1263         GNUNET_free (name);
1264         GNUNET_free (dname);
1265         if (GNUNET_NO == ret)
1266           return count;
1267         return GNUNET_SYSERR;
1268       }
1269     }
1270     count++;
1271   }
1272   CLOSEDIR (dinfo);
1273   GNUNET_free (name);
1274   GNUNET_free (dname);
1275   return count;
1276 }
1277
1278
1279 /**
1280  * Function that removes the given directory by calling
1281  * "GNUNET_DISK_directory_remove".
1282  *
1283  * @param unused not used
1284  * @param fn directory to remove
1285  * @return #GNUNET_OK
1286  */
1287 static int
1288 remove_helper (void *unused, const char *fn)
1289 {
1290   (void) GNUNET_DISK_directory_remove (fn);
1291   return GNUNET_OK;
1292 }
1293
1294
1295 /**
1296  * Remove all files in a directory (rm -rf). Call with
1297  * caution.
1298  *
1299  * @param filename the file to remove
1300  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1301  */
1302 int
1303 GNUNET_DISK_directory_remove (const char *filename)
1304 {
1305   struct stat istat;
1306
1307   if (NULL == filename)
1308   {
1309     GNUNET_break (0);
1310     return GNUNET_SYSERR;
1311   }
1312   if (0 != LSTAT (filename, &istat))
1313     return GNUNET_NO;           /* file may not exist... */
1314   (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1315   if (UNLINK (filename) == 0)
1316     return GNUNET_OK;
1317   if ((errno != EISDIR) &&
1318       /* EISDIR is not sufficient in all cases, e.g.
1319        * sticky /tmp directory may result in EPERM on BSD.
1320        * So we also explicitly check "isDirectory" */
1321       (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1322   {
1323     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1324     return GNUNET_SYSERR;
1325   }
1326   if (GNUNET_SYSERR ==
1327       GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1328     return GNUNET_SYSERR;
1329   if (0 != RMDIR (filename))
1330   {
1331     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1332     return GNUNET_SYSERR;
1333   }
1334   return GNUNET_OK;
1335 }
1336
1337
1338 /**
1339  * Copy a file.
1340  *
1341  * @param src file to copy
1342  * @param dst destination file name
1343  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1344  */
1345 int
1346 GNUNET_DISK_file_copy (const char *src,
1347                        const char *dst)
1348 {
1349   char *buf;
1350   uint64_t pos;
1351   uint64_t size;
1352   size_t len;
1353   struct GNUNET_DISK_FileHandle *in;
1354   struct GNUNET_DISK_FileHandle *out;
1355
1356   if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1357     return GNUNET_SYSERR;
1358   pos = 0;
1359   in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1360                               GNUNET_DISK_PERM_NONE);
1361   if (!in)
1362     return GNUNET_SYSERR;
1363   out =
1364       GNUNET_DISK_file_open (dst,
1365                              GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1366                              GNUNET_DISK_OPEN_FAILIFEXISTS,
1367                              GNUNET_DISK_PERM_USER_READ |
1368                              GNUNET_DISK_PERM_USER_WRITE |
1369                              GNUNET_DISK_PERM_GROUP_READ |
1370                              GNUNET_DISK_PERM_GROUP_WRITE);
1371   if (!out)
1372   {
1373     GNUNET_DISK_file_close (in);
1374     return GNUNET_SYSERR;
1375   }
1376   buf = GNUNET_malloc (COPY_BLK_SIZE);
1377   while (pos < size)
1378   {
1379     len = COPY_BLK_SIZE;
1380     if (len > size - pos)
1381       len = size - pos;
1382     if (len != GNUNET_DISK_file_read (in, buf, len))
1383       goto FAIL;
1384     if (len != GNUNET_DISK_file_write (out, buf, len))
1385       goto FAIL;
1386     pos += len;
1387   }
1388   GNUNET_free (buf);
1389   GNUNET_DISK_file_close (in);
1390   GNUNET_DISK_file_close (out);
1391   return GNUNET_OK;
1392 FAIL:
1393   GNUNET_free (buf);
1394   GNUNET_DISK_file_close (in);
1395   GNUNET_DISK_file_close (out);
1396   return GNUNET_SYSERR;
1397 }
1398
1399
1400 /**
1401  * @brief Removes special characters as ':' from a filename.
1402  * @param fn the filename to canonicalize
1403  */
1404 void
1405 GNUNET_DISK_filename_canonicalize (char *fn)
1406 {
1407   char *idx;
1408   char c;
1409
1410   idx = fn;
1411   while (*idx)
1412   {
1413     c = *idx;
1414
1415     if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1416         c == '<' || c == '>' || c == '|')
1417     {
1418       *idx = '_';
1419     }
1420
1421     idx++;
1422   }
1423 }
1424
1425
1426
1427 /**
1428  * @brief Change owner of a file
1429  *
1430  * @param filename name of file to change the owner of
1431  * @param user name of the new owner
1432  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1433  */
1434 int
1435 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1436 {
1437 #ifndef MINGW
1438   struct passwd *pws;
1439
1440   pws = getpwnam (user);
1441   if (pws == NULL)
1442   {
1443     LOG (GNUNET_ERROR_TYPE_ERROR,
1444          _("Cannot obtain information about user `%s': %s\n"), user,
1445          STRERROR (errno));
1446     return GNUNET_SYSERR;
1447   }
1448   if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1449     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1450 #endif
1451   return GNUNET_OK;
1452 }
1453
1454
1455 /**
1456  * Lock a part of a file
1457  * @param fh file handle
1458  * @param lock_start absolute position from where to lock
1459  * @param lock_end absolute position until where to lock
1460  * @param excl GNUNET_YES for an exclusive lock
1461  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1462  */
1463 int
1464 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lock_start,
1465                        off_t lock_end, int excl)
1466 {
1467   if (fh == NULL)
1468   {
1469     errno = EINVAL;
1470     return GNUNET_SYSERR;
1471   }
1472
1473 #ifndef MINGW
1474   struct flock fl;
1475
1476   memset (&fl, 0, sizeof (struct flock));
1477   fl.l_type = excl ? F_WRLCK : F_RDLCK;
1478   fl.l_whence = SEEK_SET;
1479   fl.l_start = lock_start;
1480   fl.l_len = lock_end;
1481
1482   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1483 #else
1484   OVERLAPPED o;
1485   off_t diff = lock_end - lock_start;
1486   DWORD diff_low, diff_high;
1487   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1488   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1489
1490   memset (&o, 0, sizeof (OVERLAPPED));
1491   o.Offset = (DWORD) (lock_start & 0xFFFFFFFF);;
1492   o.OffsetHigh = (DWORD) (((lock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1493
1494   if (!LockFileEx
1495       (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1496        0, diff_low, diff_high, &o))
1497   {
1498     SetErrnoFromWinError (GetLastError ());
1499     return GNUNET_SYSERR;
1500   }
1501
1502   return GNUNET_OK;
1503 #endif
1504 }
1505
1506
1507 /**
1508  * Unlock a part of a file
1509  * @param fh file handle
1510  * @param unlock_start absolute position from where to unlock
1511  * @param unlock_end absolute position until where to unlock
1512  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1513  */
1514 int
1515 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlock_start,
1516                          off_t unlock_end)
1517 {
1518   if (fh == NULL)
1519   {
1520     errno = EINVAL;
1521     return GNUNET_SYSERR;
1522   }
1523
1524 #ifndef MINGW
1525   struct flock fl;
1526
1527   memset (&fl, 0, sizeof (struct flock));
1528   fl.l_type = F_UNLCK;
1529   fl.l_whence = SEEK_SET;
1530   fl.l_start = unlock_start;
1531   fl.l_len = unlock_end;
1532
1533   return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1534 #else
1535   OVERLAPPED o;
1536   off_t diff = unlock_end - unlock_start;
1537   DWORD diff_low, diff_high;
1538   diff_low = (DWORD) (diff & 0xFFFFFFFF);
1539   diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1540
1541   memset (&o, 0, sizeof (OVERLAPPED));
1542   o.Offset = (DWORD) (unlock_start & 0xFFFFFFFF);;
1543   o.OffsetHigh = (DWORD) (((unlock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1544
1545   if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1546   {
1547     SetErrnoFromWinError (GetLastError ());
1548     return GNUNET_SYSERR;
1549   }
1550
1551   return GNUNET_OK;
1552 #endif
1553 }
1554
1555
1556 /**
1557  * Open a file.  Note that the access permissions will only be
1558  * used if a new file is created and if the underlying operating
1559  * system supports the given permissions.
1560  *
1561  * @param fn file name to be opened
1562  * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1563  * @param perm permissions for the newly created file, use
1564  *             #GNUNET_DISK_PERM_NONE if a file could not be created by this
1565  *             call (because of flags)
1566  * @return IO handle on success, NULL on error
1567  */
1568 struct GNUNET_DISK_FileHandle *
1569 GNUNET_DISK_file_open (const char *fn,
1570                        enum GNUNET_DISK_OpenFlags flags,
1571                        enum GNUNET_DISK_AccessPermissions perm)
1572 {
1573   char *expfn;
1574   struct GNUNET_DISK_FileHandle *ret;
1575
1576 #ifdef MINGW
1577   DWORD access;
1578   DWORD disp;
1579   HANDLE h;
1580   wchar_t wexpfn[MAX_PATH + 1];
1581 #else
1582   int oflags;
1583   int mode;
1584   int fd;
1585 #endif
1586
1587   expfn = GNUNET_STRINGS_filename_expand (fn);
1588   if (NULL == expfn)
1589     return NULL;
1590 #ifndef MINGW
1591   mode = 0;
1592   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1593     oflags = O_RDWR;            /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1594   else if (flags & GNUNET_DISK_OPEN_READ)
1595     oflags = O_RDONLY;
1596   else if (flags & GNUNET_DISK_OPEN_WRITE)
1597     oflags = O_WRONLY;
1598   else
1599   {
1600     GNUNET_break (0);
1601     GNUNET_free (expfn);
1602     return NULL;
1603   }
1604   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1605     oflags |= (O_CREAT | O_EXCL);
1606   if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1607     oflags |= O_TRUNC;
1608   if (flags & GNUNET_DISK_OPEN_APPEND)
1609     oflags |= O_APPEND;
1610   if (flags & GNUNET_DISK_OPEN_CREATE)
1611   {
1612     (void) GNUNET_DISK_directory_create_for_file (expfn);
1613     oflags |= O_CREAT;
1614     mode = translate_unix_perms (perm);
1615   }
1616
1617   fd = open (expfn, oflags
1618 #if O_CLOEXEC
1619              | O_CLOEXEC
1620 #endif
1621              | O_LARGEFILE, mode);
1622   if (fd == -1)
1623   {
1624     if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1625       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1626     else
1627       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1628     GNUNET_free (expfn);
1629     return NULL;
1630   }
1631 #else
1632   access = 0;
1633   disp = OPEN_ALWAYS;
1634
1635   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1636     access = FILE_READ_DATA | FILE_WRITE_DATA;
1637   else if (flags & GNUNET_DISK_OPEN_READ)
1638     access = FILE_READ_DATA;
1639   else if (flags & GNUNET_DISK_OPEN_WRITE)
1640     access = FILE_WRITE_DATA;
1641
1642   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1643   {
1644     disp = CREATE_NEW;
1645   }
1646   else if (flags & GNUNET_DISK_OPEN_CREATE)
1647   {
1648     (void) GNUNET_DISK_directory_create_for_file (expfn);
1649     if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1650       disp = CREATE_ALWAYS;
1651     else
1652       disp = OPEN_ALWAYS;
1653   }
1654   else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1655   {
1656     disp = TRUNCATE_EXISTING;
1657   }
1658   else
1659   {
1660     disp = OPEN_EXISTING;
1661   }
1662
1663   if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1664     h = CreateFileW (wexpfn, access,
1665                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1666                     disp, FILE_ATTRIBUTE_NORMAL, NULL);
1667   else
1668     h = INVALID_HANDLE_VALUE;
1669   if (h == INVALID_HANDLE_VALUE)
1670   {
1671     int err;
1672     SetErrnoFromWinError (GetLastError ());
1673     err = errno;
1674     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1675     GNUNET_free (expfn);
1676     errno = err;
1677     return NULL;
1678   }
1679
1680   if (flags & GNUNET_DISK_OPEN_APPEND)
1681     if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1682     {
1683       SetErrnoFromWinError (GetLastError ());
1684       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1685       CloseHandle (h);
1686       GNUNET_free (expfn);
1687       return NULL;
1688     }
1689 #endif
1690
1691   ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1692 #ifdef MINGW
1693   ret->h = h;
1694   ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1695 #else
1696   ret->fd = fd;
1697 #endif
1698   GNUNET_free (expfn);
1699   return ret;
1700 }
1701
1702
1703 /**
1704  * Close an open file
1705  * @param h file handle
1706  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1707  */
1708 int
1709 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1710 {
1711   int ret;
1712   if (h == NULL)
1713   {
1714     errno = EINVAL;
1715     return GNUNET_SYSERR;
1716   }
1717
1718   ret = GNUNET_OK;
1719
1720 #if MINGW
1721   if (!CloseHandle (h->h))
1722   {
1723     SetErrnoFromWinError (GetLastError ());
1724     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1725     ret = GNUNET_SYSERR;
1726   }
1727   if (h->oOverlapRead)
1728   {
1729     if (!CloseHandle (h->oOverlapRead->hEvent))
1730     {
1731       SetErrnoFromWinError (GetLastError ());
1732       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1733       ret = GNUNET_SYSERR;
1734     }
1735     GNUNET_free (h->oOverlapRead);
1736   }
1737   if (h->oOverlapWrite)
1738   {
1739     if (!CloseHandle (h->oOverlapWrite->hEvent))
1740     {
1741       SetErrnoFromWinError (GetLastError ());
1742       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1743       ret = GNUNET_SYSERR;
1744     }
1745     GNUNET_free (h->oOverlapWrite);
1746   }
1747 #else
1748   if (close (h->fd) != 0)
1749   {
1750     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1751     ret = GNUNET_SYSERR;
1752   }
1753 #endif
1754   GNUNET_free (h);
1755   return ret;
1756 }
1757
1758 #ifdef WINDOWS
1759 /**
1760  * Get a GNUnet file handle from a W32 handle.
1761  *
1762  * @param handle native handle
1763  * @return GNUnet file handle corresponding to the W32 handle
1764  */
1765 struct GNUNET_DISK_FileHandle *
1766 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1767 {
1768   struct GNUNET_DISK_FileHandle *fh;
1769
1770   DWORD dwret;
1771   enum GNUNET_FILE_Type ftype;
1772
1773   dwret = GetFileType (osfh);
1774   switch (dwret)
1775   {
1776   case FILE_TYPE_DISK:
1777     ftype = GNUNET_DISK_HANLDE_TYPE_FILE;
1778     break;
1779   case FILE_TYPE_PIPE:
1780     ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1781     break;
1782   case FILE_TYPE_UNKNOWN:
1783     if (GetLastError () == NO_ERROR || GetLastError () == ERROR_INVALID_HANDLE)
1784     {
1785       if (0 != ResetEvent (osfh))
1786         ftype = GNUNET_DISK_HANLDE_TYPE_EVENT;
1787     }
1788     else
1789       return NULL;
1790     break;
1791   default:
1792     return NULL;
1793   }
1794
1795   fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1796
1797   fh->h = osfh;
1798   fh->type = ftype;
1799   if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1800   {
1801     /**
1802      * Note that we can't make it overlapped if it isn't already.
1803      * (ReOpenFile() is only available in 2003/Vista).
1804      * The process that opened this file in the first place (usually a parent
1805      * process, if this is stdin/stdout/stderr) must make it overlapped,
1806      * otherwise we're screwed, as selecting on non-overlapped handle
1807      * will block.
1808      */
1809     fh->oOverlapRead = GNUNET_new (OVERLAPPED);
1810     fh->oOverlapWrite = GNUNET_new (OVERLAPPED);
1811     fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1812     fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1813   }
1814
1815   return fh;
1816 }
1817 #endif
1818
1819 /**
1820  * Get a handle from a native integer FD.
1821  *
1822  * @param fno native integer file descriptor
1823  * @return file handle corresponding to the descriptor, NULL on error
1824  */
1825 struct GNUNET_DISK_FileHandle *
1826 GNUNET_DISK_get_handle_from_int_fd (int fno)
1827 {
1828   struct GNUNET_DISK_FileHandle *fh;
1829
1830   if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1831        (EBADF == errno) )
1832     return NULL; /* invalid FD */
1833
1834 #ifndef WINDOWS
1835   fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1836
1837   fh->fd = fno;
1838 #else
1839   intptr_t osfh;
1840
1841   osfh = _get_osfhandle (fno);
1842   if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1843     return NULL;
1844
1845   fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1846 #endif
1847
1848   return fh;
1849 }
1850
1851
1852 /**
1853  * Get a handle from a native streaming FD.
1854  *
1855  * @param fd native streaming file descriptor
1856  * @return file handle corresponding to the descriptor
1857  */
1858 struct GNUNET_DISK_FileHandle *
1859 GNUNET_DISK_get_handle_from_native (FILE *fd)
1860 {
1861   int fno;
1862
1863   fno = fileno (fd);
1864   if (-1 == fno)
1865     return NULL;
1866
1867   return GNUNET_DISK_get_handle_from_int_fd (fno);
1868 }
1869
1870
1871 /**
1872  * Handle for a memory-mapping operation.
1873  */
1874 struct GNUNET_DISK_MapHandle
1875 {
1876   /**
1877    * Address where the map is in memory.
1878    */
1879   void *addr;
1880
1881 #ifdef MINGW
1882   /**
1883    * Underlying OS handle.
1884    */
1885   HANDLE h;
1886 #else
1887   /**
1888    * Number of bytes mapped.
1889    */
1890   size_t len;
1891 #endif
1892 };
1893
1894
1895 #ifndef MAP_FAILED
1896 #define MAP_FAILED ((void *) -1)
1897 #endif
1898
1899 /**
1900  * Map a file into memory
1901  *
1902  * @param h open file handle
1903  * @param m handle to the new mapping
1904  * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1905  * @param len size of the mapping
1906  * @return pointer to the mapped memory region, NULL on failure
1907  */
1908 void *
1909 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1910                       struct GNUNET_DISK_MapHandle **m,
1911                       enum GNUNET_DISK_MapType access, size_t len)
1912 {
1913   if (h == NULL)
1914   {
1915     errno = EINVAL;
1916     return NULL;
1917   }
1918
1919 #ifdef MINGW
1920   DWORD mapAccess, protect;
1921
1922   if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1923       (access & GNUNET_DISK_MAP_TYPE_WRITE))
1924   {
1925     protect = PAGE_READWRITE;
1926     mapAccess = FILE_MAP_ALL_ACCESS;
1927   }
1928   else if (access & GNUNET_DISK_MAP_TYPE_READ)
1929   {
1930     protect = PAGE_READONLY;
1931     mapAccess = FILE_MAP_READ;
1932   }
1933   else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1934   {
1935     protect = PAGE_READWRITE;
1936     mapAccess = FILE_MAP_WRITE;
1937   }
1938   else
1939   {
1940     GNUNET_break (0);
1941     return NULL;
1942   }
1943
1944   *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
1945   (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1946   if ((*m)->h == INVALID_HANDLE_VALUE)
1947   {
1948     SetErrnoFromWinError (GetLastError ());
1949     GNUNET_free (*m);
1950     return NULL;
1951   }
1952
1953   (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1954   if (!(*m)->addr)
1955   {
1956     SetErrnoFromWinError (GetLastError ());
1957     CloseHandle ((*m)->h);
1958     GNUNET_free (*m);
1959   }
1960
1961   return (*m)->addr;
1962 #else
1963   int prot;
1964
1965   prot = 0;
1966   if (access & GNUNET_DISK_MAP_TYPE_READ)
1967     prot = PROT_READ;
1968   if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1969     prot |= PROT_WRITE;
1970   *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
1971   (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1972   GNUNET_assert (NULL != (*m)->addr);
1973   if (MAP_FAILED == (*m)->addr)
1974   {
1975     GNUNET_free (*m);
1976     return NULL;
1977   }
1978   (*m)->len = len;
1979   return (*m)->addr;
1980 #endif
1981 }
1982
1983 /**
1984  * Unmap a file
1985  * @param h mapping handle
1986  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1987  */
1988 int
1989 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1990 {
1991   int ret;
1992
1993   if (h == NULL)
1994   {
1995     errno = EINVAL;
1996     return GNUNET_SYSERR;
1997   }
1998
1999 #ifdef MINGW
2000   ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2001   if (ret != GNUNET_OK)
2002     SetErrnoFromWinError (GetLastError ());
2003   if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2004   {
2005     ret = GNUNET_SYSERR;
2006     SetErrnoFromWinError (GetLastError ());
2007   }
2008 #else
2009   ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2010 #endif
2011   GNUNET_free (h);
2012   return ret;
2013 }
2014
2015
2016 /**
2017  * Write file changes to disk
2018  * @param h handle to an open file
2019  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2020  */
2021 int
2022 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2023 {
2024   if (h == NULL)
2025   {
2026     errno = EINVAL;
2027     return GNUNET_SYSERR;
2028   }
2029
2030 #ifdef MINGW
2031   int ret;
2032
2033   ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2034   if (ret != GNUNET_OK)
2035     SetErrnoFromWinError (GetLastError ());
2036   return ret;
2037 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2038   return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2039 #else
2040   return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2041 #endif
2042 }
2043
2044
2045 #if WINDOWS
2046 #ifndef PIPE_BUF
2047 #define PIPE_BUF        512
2048 #endif
2049 /* Copyright Bob Byrnes  <byrnes <at> curl.com>
2050    http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2051 */
2052 /* Create a pipe, and return handles to the read and write ends,
2053    just like CreatePipe, but ensure that the write end permits
2054    FILE_READ_ATTRIBUTES access, on later versions of win32 where
2055    this is supported.  This access is needed by NtQueryInformationFile,
2056    which is used to implement select and nonblocking writes.
2057    Note that the return value is either NO_ERROR or GetLastError,
2058    unlike CreatePipe, which returns a bool for success or failure.  */
2059 static int
2060 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2061                         LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2062                         DWORD dwReadMode, DWORD dwWriteMode)
2063 {
2064   /* Default to error. */
2065   *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2066
2067   HANDLE read_pipe;
2068   HANDLE write_pipe;
2069
2070   /* Ensure that there is enough pipe buffer space for atomic writes.  */
2071   if (psize < PIPE_BUF)
2072     psize = PIPE_BUF;
2073
2074   char pipename[MAX_PATH];
2075
2076   /* Retry CreateNamedPipe as long as the pipe name is in use.
2077    * Retrying will probably never be necessary, but we want
2078    * to be as robust as possible.  */
2079   while (1)
2080   {
2081     static volatile LONG pipe_unique_id;
2082
2083     snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2084               getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2085     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2086          pipename, psize);
2087     /* Use CreateNamedPipe instead of CreatePipe, because the latter
2088      * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2089      * access, on versions of win32 earlier than WinXP SP2.
2090      * CreatePipe also stupidly creates a full duplex pipe, which is
2091      * a waste, since only a single direction is actually used.
2092      * It's important to only allow a single instance, to ensure that
2093      * the pipe was not created earlier by some other process, even if
2094      * the pid has been reused.  */
2095     read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,   /* max instances */
2096                                   psize,        /* output buffer size */
2097                                   psize,        /* input buffer size */
2098                                   NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2099
2100     if (read_pipe != INVALID_HANDLE_VALUE)
2101     {
2102       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2103       break;
2104     }
2105
2106     DWORD err = GetLastError ();
2107
2108     switch (err)
2109     {
2110     case ERROR_PIPE_BUSY:
2111       /* The pipe is already open with compatible parameters.
2112        * Pick a new name and retry.  */
2113       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2114       continue;
2115     case ERROR_ACCESS_DENIED:
2116       /* The pipe is already open with incompatible parameters.
2117        * Pick a new name and retry.  */
2118       LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2119       continue;
2120     case ERROR_CALL_NOT_IMPLEMENTED:
2121       /* We are on an older Win9x platform without named pipes.
2122        * Return an anonymous pipe as the best approximation.  */
2123       LOG (GNUNET_ERROR_TYPE_DEBUG,
2124            "CreateNamedPipe not implemented, resorting to "
2125            "CreatePipe: size = %lu\n", psize);
2126       if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2127       {
2128         LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2129              *read_pipe_ptr,
2130              *write_pipe_ptr);
2131         return GNUNET_OK;
2132       }
2133       err = GetLastError ();
2134       LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2135       return err;
2136     default:
2137       LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2138       return err;
2139     }
2140     /* NOTREACHED */
2141   }
2142   LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2143
2144   /* Open the named pipe for writing.
2145    * Be sure to permit FILE_READ_ATTRIBUTES access.  */
2146   write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0,  /* share mode */
2147                             sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2148                             0); /* handle to template file */
2149
2150   if (write_pipe == INVALID_HANDLE_VALUE)
2151   {
2152     /* Failure. */
2153     DWORD err = GetLastError ();
2154
2155     LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2156     CloseHandle (read_pipe);
2157     return err;
2158   }
2159   LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2160   /* Success. */
2161   *read_pipe_ptr = read_pipe;
2162   *write_pipe_ptr = write_pipe;
2163   return GNUNET_OK;
2164 }
2165 #endif
2166
2167
2168 /**
2169  * Creates an interprocess channel
2170  *
2171  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2172  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2173  * @param inherit_read inherit the parent processes stdin (only for windows)
2174  * @param inherit_write inherit the parent processes stdout (only for windows)
2175  * @return handle to the new pipe, NULL on error
2176  */
2177 struct GNUNET_DISK_PipeHandle *
2178 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2179 {
2180 #ifndef MINGW
2181   int fd[2];
2182   int ret;
2183   int eno;
2184
2185   ret = pipe (fd);
2186   if (ret == -1)
2187   {
2188     eno = errno;
2189     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2190     errno = eno;
2191     return NULL;
2192   }
2193   return GNUNET_DISK_pipe_from_fd (blocking_read,
2194                                    blocking_write,
2195                                    fd);
2196 #else
2197   struct GNUNET_DISK_PipeHandle *p;
2198   BOOL ret;
2199   HANDLE tmp_handle;
2200   int save_errno;
2201
2202   p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2203   p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2204   p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2205
2206   /* All pipes are overlapped. If you want them to block - just
2207    * call WriteFile() and ReadFile() with NULL overlapped pointer.
2208    * NOTE: calling with NULL overlapped pointer works only
2209    * for pipes, and doesn't seem to be a documented feature.
2210    * It will NOT work for files, because overlapped files need
2211    * to read offsets from the overlapped structure, regardless.
2212    * Pipes are not seekable, and need no offsets, which is
2213    * probably why it works for them.
2214    */
2215   ret =
2216       create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2217                               FILE_FLAG_OVERLAPPED,
2218                               FILE_FLAG_OVERLAPPED);
2219   if (!ret)
2220   {
2221     SetErrnoFromWinError (GetLastError ());
2222     save_errno = errno;
2223     GNUNET_free (p->fd[0]);
2224     GNUNET_free (p->fd[1]);
2225     GNUNET_free (p);
2226     errno = save_errno;
2227     return NULL;
2228   }
2229   if (!DuplicateHandle
2230       (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2231        inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2232   {
2233     SetErrnoFromWinError (GetLastError ());
2234     save_errno = errno;
2235     CloseHandle (p->fd[0]->h);
2236     CloseHandle (p->fd[1]->h);
2237     GNUNET_free (p->fd[0]);
2238     GNUNET_free (p->fd[1]);
2239     GNUNET_free (p);
2240     errno = save_errno;
2241     return NULL;
2242   }
2243   CloseHandle (p->fd[0]->h);
2244   p->fd[0]->h = tmp_handle;
2245
2246   if (!DuplicateHandle
2247       (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2248        inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2249   {
2250     SetErrnoFromWinError (GetLastError ());
2251     save_errno = errno;
2252     CloseHandle (p->fd[0]->h);
2253     CloseHandle (p->fd[1]->h);
2254     GNUNET_free (p->fd[0]);
2255     GNUNET_free (p->fd[1]);
2256     GNUNET_free (p);
2257     errno = save_errno;
2258     return NULL;
2259   }
2260   CloseHandle (p->fd[1]->h);
2261   p->fd[1]->h = tmp_handle;
2262
2263   p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2264   p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2265
2266   p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2267   p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2268   p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2269   p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2270
2271   p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2272   p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2273
2274   p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2275   p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2276
2277   return p;
2278 #endif
2279 }
2280
2281
2282 /**
2283  * Creates a pipe object from a couple of file descriptors.
2284  * Useful for wrapping existing pipe FDs.
2285  *
2286  * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2287  * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2288  * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2289  *
2290  * @return handle to the new pipe, NULL on error
2291  */
2292 struct GNUNET_DISK_PipeHandle *
2293 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2294 {
2295   struct GNUNET_DISK_PipeHandle *p;
2296
2297   p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2298
2299 #ifndef MINGW
2300   int ret;
2301   int flags;
2302   int eno = 0; /* make gcc happy */
2303
2304   ret = 0;
2305   if (fd[0] >= 0)
2306   {
2307     p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2308     p->fd[0]->fd = fd[0];
2309     if (!blocking_read)
2310     {
2311       flags = fcntl (fd[0], F_GETFL);
2312       flags |= O_NONBLOCK;
2313       if (0 > fcntl (fd[0], F_SETFL, flags))
2314       {
2315         ret = -1;
2316         eno = errno;
2317       }
2318     }
2319     flags = fcntl (fd[0], F_GETFD);
2320     flags |= FD_CLOEXEC;
2321     if (0 > fcntl (fd[0], F_SETFD, flags))
2322     {
2323       ret = -1;
2324       eno = errno;
2325     }
2326   }
2327
2328   if (fd[1] >= 0)
2329   {
2330     p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2331     p->fd[1]->fd = fd[1];
2332     if (!blocking_write)
2333     {
2334       flags = fcntl (fd[1], F_GETFL);
2335       flags |= O_NONBLOCK;
2336       if (0 > fcntl (fd[1], F_SETFL, flags))
2337       {
2338         ret = -1;
2339         eno = errno;
2340       }
2341     }
2342     flags = fcntl (fd[1], F_GETFD);
2343     flags |= FD_CLOEXEC;
2344     if (0 > fcntl (fd[1], F_SETFD, flags))
2345     {
2346       ret = -1;
2347       eno = errno;
2348     }
2349   }
2350   if (ret == -1)
2351   {
2352     errno = eno;
2353     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2354     if (p->fd[0]->fd >= 0)
2355       GNUNET_break (0 == close (p->fd[0]->fd));
2356     if (p->fd[1]->fd >= 0)
2357       GNUNET_break (0 == close (p->fd[1]->fd));
2358     GNUNET_free_non_null (p->fd[0]);
2359     GNUNET_free_non_null (p->fd[1]);
2360     GNUNET_free (p);
2361     errno = eno;
2362     return NULL;
2363   }
2364 #else
2365   if (fd[0] >= 0)
2366   {
2367     p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2368     p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2369     if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2370     {
2371       p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2372       p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2373       p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2374       p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2375       p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2376     }
2377     else
2378     {
2379       GNUNET_free (p->fd[0]);
2380       p->fd[0] = NULL;
2381     }
2382   }
2383   if (fd[1] >= 0)
2384   {
2385     p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2386     p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2387     if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2388     {
2389       p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2390       p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2391       p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2392       p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2393       p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2394     }
2395     else
2396     {
2397       GNUNET_free (p->fd[1]);
2398       p->fd[1] = NULL;
2399     }
2400   }
2401
2402 #endif
2403   return p;
2404 }
2405
2406
2407 /**
2408  * Closes an interprocess channel
2409  *
2410  * @param p pipe to close
2411  * @param end which end of the pipe to close
2412  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2413  */
2414 int
2415 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2416                             enum GNUNET_DISK_PipeEnd end)
2417 {
2418   int ret = GNUNET_OK;
2419
2420   if (end == GNUNET_DISK_PIPE_END_READ)
2421   {
2422     if (p->fd[0])
2423     {
2424       ret = GNUNET_DISK_file_close (p->fd[0]);
2425       p->fd[0] = NULL;
2426     }
2427   }
2428   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2429   {
2430     if (p->fd[1])
2431     {
2432       ret = GNUNET_DISK_file_close (p->fd[1]);
2433       p->fd[1] = NULL;
2434     }
2435   }
2436
2437   return ret;
2438 }
2439
2440 /**
2441  * Detaches one of the ends from the pipe.
2442  * Detached end is a fully-functional FileHandle, it will
2443  * not be affected by anything you do with the pipe afterwards.
2444  * Each end of a pipe can only be detched from it once (i.e.
2445  * it is not duplicated).
2446  *
2447  * @param p pipe to detach an end from
2448  * @param end which end of the pipe to detach
2449  * @return Detached end on success, NULL on failure
2450  * (or if that end is not present or is closed).
2451  */
2452 struct GNUNET_DISK_FileHandle *
2453 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2454                              enum GNUNET_DISK_PipeEnd end)
2455 {
2456   struct GNUNET_DISK_FileHandle *ret = NULL;
2457
2458   if (end == GNUNET_DISK_PIPE_END_READ)
2459   {
2460     if (p->fd[0])
2461     {
2462       ret = p->fd[0];
2463       p->fd[0] = NULL;
2464     }
2465   }
2466   else if (end == GNUNET_DISK_PIPE_END_WRITE)
2467   {
2468     if (p->fd[1])
2469     {
2470       ret = p->fd[1];
2471       p->fd[1] = NULL;
2472     }
2473   }
2474
2475   return ret;
2476 }
2477
2478
2479 /**
2480  * Closes an interprocess channel
2481  *
2482  * @param p pipe to close
2483  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2484  */
2485 int
2486 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2487 {
2488   int ret = GNUNET_OK;
2489
2490   int read_end_close;
2491   int write_end_close;
2492   int read_end_close_errno;
2493   int write_end_close_errno;
2494
2495   read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2496   read_end_close_errno = errno;
2497   write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2498   write_end_close_errno = errno;
2499   GNUNET_free (p);
2500
2501   if (GNUNET_OK != read_end_close)
2502   {
2503     errno = read_end_close_errno;
2504     ret = read_end_close;
2505   }
2506   else if (GNUNET_OK != write_end_close)
2507   {
2508     errno = write_end_close_errno;
2509     ret = write_end_close;
2510   }
2511
2512   return ret;
2513 }
2514
2515
2516 /**
2517  * Get the handle to a particular pipe end
2518  *
2519  * @param p pipe
2520  * @param n end to access
2521  * @return handle for the respective end
2522  */
2523 const struct GNUNET_DISK_FileHandle *
2524 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2525                          enum GNUNET_DISK_PipeEnd n)
2526 {
2527   switch (n)
2528   {
2529   case GNUNET_DISK_PIPE_END_READ:
2530   case GNUNET_DISK_PIPE_END_WRITE:
2531     return p->fd[n];
2532   default:
2533     GNUNET_break (0);
2534     return NULL;
2535   }
2536 }
2537
2538
2539 /**
2540  * Retrieve OS file handle
2541  * @internal
2542  * @param fh GNUnet file descriptor
2543  * @param dst destination buffer
2544  * @param dst_len length of dst
2545  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
2546  */
2547 int
2548 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2549                                    void *dst, size_t dst_len)
2550 {
2551   if (NULL == fh)
2552     return GNUNET_SYSERR;
2553 #ifdef MINGW
2554   if (dst_len < sizeof (HANDLE))
2555     return GNUNET_SYSERR;
2556   *((HANDLE *) dst) = fh->h;
2557 #else
2558   if (dst_len < sizeof (int))
2559     return GNUNET_SYSERR;
2560   *((int *) dst) = fh->fd;
2561 #endif
2562
2563   return GNUNET_OK;
2564 }
2565
2566 /* end of disk.c */