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