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