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