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