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