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