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