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