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