2 This file is part of GNUnet.
3 (C) 2001, 2002, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
23 * @brief disk IO convenience methods
24 * @author Christian Grothoff
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"
37 #define DEBUG_NPIPE GNUNET_YES
40 * Block size for IO for copying files.
42 #define COPY_BLK_SIZE 65536
46 #if defined(LINUX) || defined(CYGWIN)
49 #if defined(SOMEBSD) || defined(DARWIN)
50 #include <sys/param.h>
51 #include <sys/mount.h>
54 #include <sys/types.h>
55 #include <sys/statvfs.h>
58 #define _IFMT 0170000 /* type of file */
59 #define _IFLNK 0120000 /* symbolic link */
60 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
62 #error PORT-ME: need to port statfs (how much space is left on the drive?)
68 #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS)
72 #include <sys/statvfs.h>
77 * Handle used to manage a pipe.
79 struct GNUNET_DISK_PipeHandle
82 * File descriptors for the pipe.
84 struct GNUNET_DISK_FileHandle *fd[2];
89 * Closure for the recursion to determine the file size
92 struct GetFileSizeData
95 * Set to the total file size.
100 * GNUNET_YES if symbolic links should be included.
102 int include_sym_links;
106 int translate_unix_perms(enum GNUNET_DISK_AccessPermissions perm)
111 if (perm & GNUNET_DISK_PERM_USER_READ)
113 if (perm & GNUNET_DISK_PERM_USER_WRITE)
115 if (perm & GNUNET_DISK_PERM_USER_EXEC)
117 if (perm & GNUNET_DISK_PERM_GROUP_READ)
119 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
121 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
123 if (perm & GNUNET_DISK_PERM_OTHER_READ)
125 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
127 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
135 * Iterate over all files in the given directory and
136 * accumulate their size.
138 * @param cls closure of type "struct GetFileSizeData"
139 * @param fn current filename we are looking at
140 * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
143 getSizeRec (void *cls, const char *fn)
145 struct GetFileSizeData *gfsd = cls;
153 if (0 != STAT64 (fn, &buf))
155 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat64", fn);
156 return GNUNET_SYSERR;
159 if (0 != STAT (fn, &buf))
161 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", fn);
162 return GNUNET_SYSERR;
165 if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
166 gfsd->total += buf.st_size;
167 if ((S_ISDIR (buf.st_mode)) &&
168 (0 == ACCESS (fn, X_OK)) &&
169 ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
171 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
172 return GNUNET_SYSERR;
179 * Checks whether a handle is invalid
181 * @param h handle to check
182 * @return GNUNET_YES if invalid, GNUNET_NO if valid
185 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
188 return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
190 return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
196 * Move the read/write pointer in a file
198 * @param h handle of an open file
199 * @param offset position to move to
200 * @param whence specification to which position the offset parameter relates to
201 * @return the new position on success, GNUNET_SYSERR otherwise
204 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, off_t offset,
205 enum GNUNET_DISK_Seek whence)
210 return GNUNET_SYSERR;
215 static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
216 [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
219 ret = SetFilePointer (h->h, offset, NULL, t[whence]);
220 if (ret == INVALID_SET_FILE_POINTER)
222 SetErrnoFromWinError (GetLastError ());
223 return GNUNET_SYSERR;
227 static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
228 [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
231 return lseek (h->fd, offset, t[whence]);
237 * Get the size of the file (or directory) of the given file (in
240 * @param filename name of the file or directory
241 * @param size set to the size of the file (or,
242 * in the case of directories, the sum
243 * of all sizes of files in the directory)
244 * @param includeSymLinks should symbolic links be
246 * @return GNUNET_SYSERR on error, GNUNET_OK on success
249 GNUNET_DISK_file_size (const char *filename,
250 uint64_t * size, int includeSymLinks)
252 struct GetFileSizeData gfsd;
255 GNUNET_assert (size != NULL);
257 gfsd.include_sym_links = includeSymLinks;
258 ret = getSizeRec (&gfsd, filename);
265 * Obtain some unique identifiers for the given file
266 * that can be used to identify it in the local system.
267 * This function is used between GNUnet processes to
268 * quickly check if two files with the same absolute path
269 * are actually identical. The two processes represent
270 * the same peer but may communicate over the network
271 * (and the file may be on an NFS volume). This function
272 * may not be supported on all operating systems.
274 * @param filename name of the file
275 * @param dev set to the device ID
276 * @param ino set to the inode ID
277 * @return GNUNET_OK on success
280 GNUNET_DISK_file_get_identifiers (const char *filename,
281 uint64_t * dev, uint64_t * ino)
287 if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
289 *dev = (uint64_t) fbuf.f_fsid;
290 *ino = (uint64_t) sbuf.st_ino;
297 if ( (0 == stat (filename, &sbuf)) &&
298 (0 == statfs (filename, &fbuf) ) )
300 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 || ((uint64_t) fbuf.f_fsid.val[1]);
301 *ino = (uint64_t) sbuf.st_ino;
305 // FIXME NILS: test this
306 struct GNUNET_DISK_FileHandle *fh;
307 BY_HANDLE_FILE_INFORMATION info;
310 fh = GNUNET_DISK_file_open(filename, GNUNET_DISK_OPEN_READ, 0);
312 return GNUNET_SYSERR;
313 succ = GetFileInformationByHandle(fh->h, &info);
314 GNUNET_DISK_file_close(fh);
317 *dev = info.dwVolumeSerialNumber;
318 *ino = ((info.nFileIndexHigh << sizeof(DWORD)) | info.nFileIndexLow);
322 return GNUNET_SYSERR;
325 return GNUNET_SYSERR;
330 * Create an (empty) temporary file on disk. If the given name is not
331 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
332 * 6 random characters will be appended to the name to create a unique
335 * @param t component to use for the name;
336 * does NOT contain "XXXXXX" or "/tmp/".
337 * @return NULL on error, otherwise name of fresh
338 * file on disk in directory for temporary files
341 GNUNET_DISK_mktemp (const char *t)
348 if ( (t[0] != '/') &&
351 tmpdir = getenv ("TMPDIR");
352 tmpdir = tmpdir ? tmpdir : "/tmp";
353 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
357 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
360 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
361 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
374 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
379 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn);
385 * Get the number of blocks that are left on the partition that
386 * contains the given file (for normal users).
388 * @param part a file on the partition to check
389 * @return -1 on errors, otherwise the number of free blocks
392 GNUNET_DISK_get_blocks_available (const char *part)
397 if (0 != statvfs (part, &buf))
399 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
409 path = GNUNET_STRINGS_filename_expand (part);
412 memcpy (szDrive, path, 3);
415 if (!GetDiskFreeSpace (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
418 _("`%s' failed for drive `%s': %u\n"),
419 "GetDiskFreeSpace", szDrive, GetLastError ());
426 if (0 != statfs (part, &s))
428 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
437 * Test if "fil" is a directory.
438 * Will not print an error message if the directory
439 * does not exist. Will log errors if GNUNET_SYSERR is
440 * returned (i.e., a file exists with the same name).
442 * @param fil filename to test
443 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
447 GNUNET_DISK_directory_test (const char *fil)
449 struct stat filestat;
452 ret = STAT (fil, &filestat);
457 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
458 return GNUNET_SYSERR;
462 if (!S_ISDIR (filestat.st_mode))
464 if (ACCESS (fil, R_OK | X_OK) < 0)
466 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "access", fil);
467 return GNUNET_SYSERR;
473 * Check that fil corresponds to a filename
474 * (of a file that exists and that is not a directory).
476 * @param fil filename to check
477 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
478 * else (will print an error message in that case, too).
481 GNUNET_DISK_file_test (const char *fil)
483 struct stat filestat;
487 rdir = GNUNET_STRINGS_filename_expand (fil);
489 return GNUNET_SYSERR;
491 ret = STAT (rdir, &filestat);
496 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
498 return GNUNET_SYSERR;
503 if (!S_ISREG (filestat.st_mode))
508 if (ACCESS (rdir, R_OK) < 0)
510 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
512 return GNUNET_SYSERR;
520 * Implementation of "mkdir -p"
521 * @param dir the directory to create
522 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
525 GNUNET_DISK_directory_create (const char *dir)
532 rdir = GNUNET_STRINGS_filename_expand (dir);
534 return GNUNET_SYSERR;
538 pos = 1; /* skip heading '/' */
540 /* Local or Network path? */
541 if (strncmp (rdir, "\\\\", 2) == 0)
546 if (rdir[pos] == '\\')
556 pos = 3; /* strlen("C:\\") */
561 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
564 ret = GNUNET_DISK_directory_test (rdir);
565 if (ret == GNUNET_SYSERR)
568 return GNUNET_SYSERR;
570 if (ret == GNUNET_NO)
573 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
577 if ((ret != 0) && (errno != EEXIST))
579 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir",
582 return GNUNET_SYSERR;
585 rdir[pos] = DIR_SEPARATOR;
595 * Create the directory structure for storing
598 * @param filename name of a file in the directory
599 * @returns GNUNET_OK on success,
600 * GNUNET_SYSERR on failure,
601 * GNUNET_NO if the directory
602 * exists but is not writeable for us
605 GNUNET_DISK_directory_create_for_file (const char *filename)
611 rdir = GNUNET_STRINGS_filename_expand (filename);
613 return GNUNET_SYSERR;
615 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
618 ret = GNUNET_DISK_directory_create (rdir);
619 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
627 * Read the contents of a binary file into a buffer.
628 * @param h handle to an open file
629 * @param result the buffer to write the result to
630 * @param len the maximum number of bytes to read
631 * @return the number of bytes read on success, GNUNET_SYSERR on failure
634 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
640 return GNUNET_SYSERR;
646 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
648 SetErrnoFromWinError (GetLastError ());
649 return GNUNET_SYSERR;
653 return read (h->fd, result, len);
659 * Read the contents of a binary file into a buffer.
661 * @param fn file name
662 * @param result the buffer to write the result to
663 * @param len the maximum number of bytes to read
664 * @return number of bytes read, GNUNET_SYSERR on failure
667 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
669 struct GNUNET_DISK_FileHandle *fh;
672 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ,
673 GNUNET_DISK_PERM_NONE);
675 return GNUNET_SYSERR;
676 ret = GNUNET_DISK_file_read (fh, result, len);
677 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
684 * Write a buffer to a file.
685 * @param h handle to open file
686 * @param buffer the data to write
687 * @param n number of bytes to write
688 * @return number of bytes written on success, GNUNET_SYSERR on error
691 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
692 const void *buffer, size_t n)
697 return GNUNET_SYSERR;
703 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
705 SetErrnoFromWinError (GetLastError ());
706 return GNUNET_SYSERR;
710 return write (h->fd, buffer, n);
715 * Write a buffer to a file. If the file is longer than the
716 * number of bytes that will be written, it will be truncated.
718 * @param fn file name
719 * @param buffer the data to write
720 * @param n number of bytes to write
721 * @param mode file permissions
722 * @return number of bytes written on success, GNUNET_SYSERR on error
725 GNUNET_DISK_fn_write (const char *fn, const void *buffer,
726 size_t n, enum GNUNET_DISK_AccessPermissions mode)
728 struct GNUNET_DISK_FileHandle *fh;
731 fh = GNUNET_DISK_file_open (fn,
732 GNUNET_DISK_OPEN_WRITE
733 | GNUNET_DISK_OPEN_TRUNCATE
734 | GNUNET_DISK_OPEN_CREATE, mode);
736 return GNUNET_SYSERR;
737 ret = GNUNET_DISK_file_write (fh, buffer, n);
738 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
743 * Scan a directory for files.
745 * @param dirName the name of the directory
746 * @param callback the method to call for each file,
747 * can be NULL, in that case, we only count
748 * @param callback_cls closure for callback
749 * @return the number of files found, GNUNET_SYSERR on error or
750 * ieration aborted by callback returning GNUNET_SYSERR
753 GNUNET_DISK_directory_scan (const char *dirName,
754 GNUNET_FileNameCallback callback,
758 struct dirent *finfo;
763 unsigned int name_len;
766 GNUNET_assert (dirName != NULL);
767 dname = GNUNET_STRINGS_filename_expand (dirName);
769 return GNUNET_SYSERR;
770 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
771 dname[strlen (dname) - 1] = '\0';
772 if (0 != STAT (dname, &istat))
774 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
776 return GNUNET_SYSERR;
778 if (!S_ISDIR (istat.st_mode))
780 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
781 _("Expected `%s' to be a directory!\n"), dirName);
783 return GNUNET_SYSERR;
786 dinfo = OPENDIR (dname);
787 if ((errno == EACCES) || (dinfo == NULL))
789 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
793 return GNUNET_SYSERR;
796 n_size = strlen (dname) + name_len + 2;
797 name = GNUNET_malloc (n_size);
798 while ((finfo = readdir (dinfo)) != NULL)
800 if ((0 == strcmp (finfo->d_name, ".")) ||
801 (0 == strcmp (finfo->d_name, "..")))
803 if (callback != NULL)
805 if (name_len < strlen (finfo->d_name))
808 name_len = strlen (finfo->d_name);
809 n_size = strlen (dname) + name_len + 2;
810 name = GNUNET_malloc (n_size);
812 /* dname can end in "/" only if dname == "/";
813 if dname does not end in "/", we need to add
814 a "/" (otherwise, we must not!) */
815 GNUNET_snprintf (name,
819 (strcmp (dname, DIR_SEPARATOR_STR) ==
820 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
821 if (GNUNET_OK != callback (callback_cls, name))
826 return GNUNET_SYSERR;
839 * Opaque handle used for iterating over a directory.
841 struct GNUNET_DISK_DirectoryIterator
845 * Function to call on directory entries.
847 GNUNET_DISK_DirectoryIteratorCallback callback;
850 * Closure for callback.
855 * Reference to directory.
865 * Next filename to process.
872 enum GNUNET_SCHEDULER_Priority priority;
878 * Task used by the directory iterator.
881 directory_iterator_task (void *cls,
882 const struct GNUNET_SCHEDULER_TaskContext *tc)
884 struct GNUNET_DISK_DirectoryIterator *iter = cls;
887 name = iter->next_name;
888 GNUNET_assert (name != NULL);
889 iter->next_name = NULL;
890 iter->callback (iter->callback_cls, iter, name, iter->dirname);
896 * This function must be called during the DiskIteratorCallback
897 * (exactly once) to schedule the task to process the next
898 * filename in the directory (if there is one).
900 * @param iter opaque handle for the iterator
901 * @param can set to GNUNET_YES to terminate the iteration early
902 * @return GNUNET_YES if iteration will continue,
903 * GNUNET_NO if this was the last entry (and iteration is complete),
904 * GNUNET_SYSERR if abort was YES
907 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator
910 struct dirent *finfo;
912 GNUNET_assert (iter->next_name == NULL);
913 if (can == GNUNET_YES)
915 closedir (iter->directory);
916 GNUNET_free (iter->dirname);
918 return GNUNET_SYSERR;
920 while (NULL != (finfo = readdir (iter->directory)))
922 if ((0 == strcmp (finfo->d_name, ".")) ||
923 (0 == strcmp (finfo->d_name, "..")))
925 GNUNET_asprintf (&iter->next_name,
927 iter->dirname, DIR_SEPARATOR_STR, finfo->d_name);
932 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
935 GNUNET_SCHEDULER_add_with_priority (iter->priority,
936 &directory_iterator_task, iter);
942 * Scan a directory for files using the scheduler to run a task for
943 * each entry. The name of the directory must be expanded first (!).
944 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
945 * may provide a simpler API.
947 * @param prio priority to use
948 * @param dirName the name of the directory
949 * @param callback the method to call for each file
950 * @param callback_cls closure for callback
953 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
955 GNUNET_DISK_DirectoryIteratorCallback
956 callback, void *callback_cls)
958 struct GNUNET_DISK_DirectoryIterator *di;
960 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
961 di->callback = callback;
962 di->callback_cls = callback_cls;
963 di->directory = OPENDIR (dirName);
964 if (di->directory == NULL)
967 callback (callback_cls, NULL, NULL, NULL);
970 di->dirname = GNUNET_strdup (dirName);
972 GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
977 * Function that removes the given directory by calling
978 * "GNUNET_DISK_directory_remove".
980 * @param unused not used
981 * @param fn directory to remove
985 remove_helper (void *unused, const char *fn)
987 (void) GNUNET_DISK_directory_remove (fn);
993 * Remove all files in a directory (rm -rf). Call with
997 * @param fileName the file to remove
998 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1001 GNUNET_DISK_directory_remove (const char *fileName)
1005 if (0 != LSTAT (fileName, &istat))
1006 return GNUNET_NO; /* file may not exist... */
1007 if (UNLINK (fileName) == 0)
1009 if ((errno != EISDIR) &&
1010 /* EISDIR is not sufficient in all cases, e.g.
1011 sticky /tmp directory may result in EPERM on BSD.
1012 So we also explicitly check "isDirectory" */
1013 (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
1015 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1016 return GNUNET_SYSERR;
1018 if (GNUNET_SYSERR ==
1019 GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL))
1020 return GNUNET_SYSERR;
1021 if (0 != RMDIR (fileName))
1023 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1024 return GNUNET_SYSERR;
1033 * @param src file to copy
1034 * @param dst destination file name
1035 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1038 GNUNET_DISK_file_copy (const char *src, const char *dst)
1044 struct GNUNET_DISK_FileHandle *in;
1045 struct GNUNET_DISK_FileHandle *out;
1047 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES))
1048 return GNUNET_SYSERR;
1050 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1051 GNUNET_DISK_PERM_NONE);
1053 return GNUNET_SYSERR;
1054 out = GNUNET_DISK_file_open (dst, GNUNET_DISK_OPEN_WRITE
1055 | GNUNET_DISK_OPEN_CREATE |
1056 GNUNET_DISK_OPEN_FAILIFEXISTS,
1057 GNUNET_DISK_PERM_USER_READ |
1058 GNUNET_DISK_PERM_USER_WRITE |
1059 GNUNET_DISK_PERM_GROUP_READ |
1060 GNUNET_DISK_PERM_GROUP_WRITE);
1063 GNUNET_DISK_file_close (in);
1064 return GNUNET_SYSERR;
1066 buf = GNUNET_malloc (COPY_BLK_SIZE);
1069 len = COPY_BLK_SIZE;
1070 if (len > size - pos)
1072 if (len != GNUNET_DISK_file_read (in, buf, len))
1074 if (len != GNUNET_DISK_file_write (out, buf, len))
1079 GNUNET_DISK_file_close (in);
1080 GNUNET_DISK_file_close (out);
1084 GNUNET_DISK_file_close (in);
1085 GNUNET_DISK_file_close (out);
1086 return GNUNET_SYSERR;
1091 * @brief Removes special characters as ':' from a filename.
1092 * @param fn the filename to canonicalize
1095 GNUNET_DISK_filename_canonicalize (char *fn)
1105 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' ||
1106 c == '"' || c == '<' || c == '>' || c == '|')
1118 * @brief Change owner of a file
1120 * @param filename name of file to change the owner of
1121 * @param user name of the new owner
1122 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1125 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1130 pws = getpwnam (user);
1133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1134 _("Cannot obtain information about user `%s': %s\n"),
1135 user, STRERROR (errno));
1136 return GNUNET_SYSERR;
1138 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1139 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1146 * Lock a part of a file
1147 * @param fh file handle
1148 * @param lockStart absolute position from where to lock
1149 * @param lockEnd absolute position until where to lock
1150 * @param excl GNUNET_YES for an exclusive lock
1151 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1154 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
1155 off_t lockEnd, int excl)
1160 return GNUNET_SYSERR;
1166 memset (&fl, 0, sizeof (struct flock));
1167 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1168 fl.l_whence = SEEK_SET;
1169 fl.l_start = lockStart;
1172 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1176 memset (&o, 0, sizeof (OVERLAPPED));
1177 o.Offset = lockStart;
1179 if (!LockFileEx (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)
1180 | LOCKFILE_FAIL_IMMEDIATELY, 0, lockEnd - lockStart, 0,
1183 SetErrnoFromWinError (GetLastError ());
1184 return GNUNET_SYSERR;
1193 * Unlock a part of a file
1194 * @param fh file handle
1195 * @param unlockStart absolute position from where to unlock
1196 * @param unlockEnd absolute position until where to unlock
1197 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1200 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlockStart,
1206 return GNUNET_SYSERR;
1212 memset (&fl, 0, sizeof (struct flock));
1213 fl.l_type = F_UNLCK;
1214 fl.l_whence = SEEK_SET;
1215 fl.l_start = unlockStart;
1216 fl.l_len = unlockEnd;
1218 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1222 memset (&o, 0, sizeof (OVERLAPPED));
1223 o.Offset = unlockStart;
1225 if (!UnlockFileEx (fh->h, 0, unlockEnd - unlockStart, 0, &o))
1227 SetErrnoFromWinError (GetLastError ());
1228 return GNUNET_SYSERR;
1237 * Open a file. Note that the access permissions will only be
1238 * used if a new file is created and if the underlying operating
1239 * system supports the given permissions.
1241 * @param fn file name to be opened
1242 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1243 * @param perm permissions for the newly created file, use
1244 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1245 * call (because of flags)
1246 * @return IO handle on success, NULL on error
1248 struct GNUNET_DISK_FileHandle *
1249 GNUNET_DISK_file_open (const char *fn,
1250 enum GNUNET_DISK_OpenFlags flags,
1251 enum GNUNET_DISK_AccessPermissions perm)
1254 struct GNUNET_DISK_FileHandle *ret;
1265 expfn = GNUNET_STRINGS_filename_expand (fn);
1270 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1271 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1272 else if (flags & GNUNET_DISK_OPEN_READ)
1274 else if (flags & GNUNET_DISK_OPEN_WRITE)
1279 GNUNET_free (expfn);
1282 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1283 oflags |= (O_CREAT | O_EXCL);
1284 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1286 if (flags & GNUNET_DISK_OPEN_APPEND)
1288 if (flags & GNUNET_DISK_OPEN_CREATE)
1290 (void) GNUNET_DISK_directory_create_for_file (expfn);
1292 mode = translate_unix_perms(perm);
1295 fd = open (expfn, oflags | O_LARGEFILE, mode);
1298 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1299 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1301 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1302 GNUNET_free (expfn);
1309 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1310 access = FILE_READ_DATA | FILE_WRITE_DATA;
1311 else if (flags & GNUNET_DISK_OPEN_READ)
1312 access = FILE_READ_DATA;
1313 else if (flags & GNUNET_DISK_OPEN_WRITE)
1314 access = FILE_WRITE_DATA;
1316 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1320 else if (flags & GNUNET_DISK_OPEN_CREATE)
1322 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1323 disp = CREATE_ALWAYS;
1327 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1329 disp = TRUNCATE_EXISTING;
1333 disp = OPEN_EXISTING;
1336 /* TODO: access priviledges? */
1337 h = CreateFile (expfn, access, FILE_SHARE_DELETE | FILE_SHARE_READ
1338 | FILE_SHARE_WRITE, NULL, disp, FILE_ATTRIBUTE_NORMAL,
1340 if (h == INVALID_HANDLE_VALUE)
1342 SetErrnoFromWinError (GetLastError ());
1343 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1344 GNUNET_free (expfn);
1348 if (flags & GNUNET_DISK_OPEN_APPEND)
1349 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1351 SetErrnoFromWinError (GetLastError ());
1352 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer",
1355 GNUNET_free (expfn);
1360 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1363 ret->type = GNUNET_DISK_FILE;
1367 GNUNET_free (expfn);
1373 * Close an open file
1374 * @param h file handle
1375 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1378 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1383 return GNUNET_SYSERR;
1387 if (!CloseHandle (h->h))
1389 SetErrnoFromWinError (GetLastError ());
1390 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
1392 return GNUNET_SYSERR;
1395 if (close (h->fd) != 0)
1397 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
1399 return GNUNET_SYSERR;
1408 * Construct full path to a file inside of the private
1409 * directory used by GNUnet. Also creates the corresponding
1410 * directory. If the resulting name is supposed to be
1411 * a directory, end the last argument in '/' (or pass
1412 * DIR_SEPARATOR_STR as the last argument before NULL).
1414 * @param cfg configuration to use (determines HOME)
1415 * @param serviceName name of the service
1416 * @param ... is NULL-terminated list of
1417 * path components to append to the
1418 * private directory name.
1419 * @return the constructed filename
1422 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1423 const char *serviceName, ...)
1429 unsigned int needed;
1432 GNUNET_CONFIGURATION_get_value_filename (cfg,
1433 serviceName, "HOME", &pfx))
1437 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1438 _("No `%s' specified for service `%s' in configuration.\n"),
1439 "HOME", serviceName);
1442 needed = strlen (pfx) + 2;
1443 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1445 va_start (ap, serviceName);
1448 c = va_arg (ap, const char *);
1451 needed += strlen (c);
1452 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1456 ret = GNUNET_malloc (needed);
1459 va_start (ap, serviceName);
1462 c = va_arg (ap, const char *);
1465 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1466 strcat (ret, DIR_SEPARATOR_STR);
1470 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1471 (void) GNUNET_DISK_directory_create_for_file (ret);
1473 (void) GNUNET_DISK_directory_create (ret);
1479 * Handle for a memory-mapping operation.
1481 struct GNUNET_DISK_MapHandle
1484 * Address where the map is in memory.
1490 * Underlying OS handle.
1495 * Number of bytes mapped.
1503 #define MAP_FAILED ((void *) -1)
1507 * Map a file into memory
1509 * @param h open file handle
1510 * @param m handle to the new mapping
1511 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1512 * @param len size of the mapping
1513 * @return pointer to the mapped memory region, NULL on failure
1516 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1517 struct GNUNET_DISK_MapHandle **m,
1518 enum GNUNET_DISK_MapType access, size_t len)
1527 DWORD mapAccess, protect;
1529 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1530 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1532 protect = PAGE_READWRITE;
1533 mapAccess = FILE_MAP_ALL_ACCESS;
1535 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1537 protect = PAGE_READONLY;
1538 mapAccess = FILE_MAP_READ;
1540 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1542 protect = PAGE_READWRITE;
1543 mapAccess = FILE_MAP_WRITE;
1551 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1552 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1553 if ((*m)->h == INVALID_HANDLE_VALUE)
1555 SetErrnoFromWinError (GetLastError ());
1560 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1563 SetErrnoFromWinError (GetLastError ());
1564 CloseHandle ((*m)->h);
1573 if (access & GNUNET_DISK_MAP_TYPE_READ)
1575 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1577 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1578 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1579 GNUNET_assert (NULL != (*m)->addr);
1580 if (MAP_FAILED == (*m)->addr)
1592 * @param h mapping handle
1593 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1596 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1602 return GNUNET_SYSERR;
1606 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
1607 if (ret != GNUNET_OK)
1608 SetErrnoFromWinError (GetLastError ());
1609 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
1611 ret = GNUNET_SYSERR;
1612 SetErrnoFromWinError (GetLastError ());
1615 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1623 * Write file changes to disk
1624 * @param h handle to an open file
1625 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1628 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1633 return GNUNET_SYSERR;
1639 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1640 if (ret != GNUNET_OK)
1641 SetErrnoFromWinError (GetLastError ());
1643 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
1644 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1646 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1652 * Creates an interprocess channel
1654 * @param blocking creates an asynchronous pipe if set to GNUNET_NO
1655 * @param inherit_read inherit the parent processes stdin (only for windows)
1656 * @param inherit_write inherit the parent processes stdout (only for windows)
1658 * @return handle to the new pipe, NULL on error
1660 struct GNUNET_DISK_PipeHandle *
1661 GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
1663 struct GNUNET_DISK_PipeHandle *p;
1664 struct GNUNET_DISK_FileHandle *fds;
1667 GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
1668 2 * sizeof (struct GNUNET_DISK_FileHandle));
1669 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
1682 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
1687 p->fd[0]->fd = fd[0];
1688 p->fd[1]->fd = fd[1];
1690 flags = fcntl (fd[0], F_GETFL);
1692 flags |= O_NONBLOCK;
1693 if (0 > fcntl (fd[0], F_SETFL, flags))
1695 flags = fcntl (fd[0], F_GETFD);
1696 flags |= FD_CLOEXEC;
1697 if (0 > fcntl (fd[0], F_SETFD, flags))
1700 flags = fcntl (fd[1], F_GETFL);
1702 flags |= O_NONBLOCK;
1703 if (0 > fcntl (fd[1], F_SETFL, flags))
1705 flags = fcntl (fd[1], F_GETFD);
1706 flags |= FD_CLOEXEC;
1707 if (0 > fcntl (fd[1], F_SETFD, flags))
1712 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fcntl");
1713 GNUNET_break (0 == close (p->fd[0]->fd));
1714 GNUNET_break (0 == close (p->fd[1]->fd));
1723 ret = CreatePipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0);
1727 SetErrnoFromWinError (GetLastError ());
1730 if (!DuplicateHandle (GetCurrentProcess (), p->fd[0]->h,
1731 GetCurrentProcess (), &tmp_handle, 0, inherit_read == GNUNET_YES ? TRUE : FALSE,
1732 DUPLICATE_SAME_ACCESS))
1734 SetErrnoFromWinError (GetLastError ());
1735 CloseHandle (p->fd[0]->h);
1736 CloseHandle (p->fd[1]->h);
1740 CloseHandle (p->fd[0]->h);
1741 p->fd[0]->h = tmp_handle;
1743 if (!DuplicateHandle (GetCurrentProcess (), p->fd[1]->h,
1744 GetCurrentProcess (), &tmp_handle, 0, inherit_write == GNUNET_YES ? TRUE : FALSE,
1745 DUPLICATE_SAME_ACCESS))
1747 SetErrnoFromWinError (GetLastError ());
1748 CloseHandle (p->fd[0]->h);
1749 CloseHandle (p->fd[1]->h);
1753 CloseHandle (p->fd[1]->h);
1754 p->fd[1]->h = tmp_handle;
1760 SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
1761 SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
1762 /* this always fails on Windows 95, so we don't care about error handling */
1764 p->fd[0]->type = GNUNET_PIPE;
1765 p->fd[1]->type = GNUNET_PIPE;
1772 * Closes an interprocess channel
1774 * @param p pipe to close
1775 * @param end which end of the pipe to close
1776 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1779 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
1780 enum GNUNET_DISK_PipeEnd end)
1782 int ret = GNUNET_OK;
1786 if (end == GNUNET_DISK_PIPE_END_READ)
1788 if (!CloseHandle (p->fd[0]->h))
1790 SetErrnoFromWinError (GetLastError ());
1791 ret = GNUNET_SYSERR;
1793 p->fd[0]->h = INVALID_HANDLE_VALUE;
1795 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1797 if (!CloseHandle (p->fd[1]->h))
1799 SetErrnoFromWinError (GetLastError ());
1800 ret = GNUNET_SYSERR;
1802 p->fd[1]->h = INVALID_HANDLE_VALUE;
1807 if (end == GNUNET_DISK_PIPE_END_READ)
1809 if (0 != close (p->fd[0]->fd))
1811 ret = GNUNET_SYSERR;
1816 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1818 if (0 != close (p->fd[1]->fd))
1820 ret = GNUNET_SYSERR;
1831 * Closes an interprocess channel
1833 * @param p pipe to close
1834 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1837 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
1839 int ret = GNUNET_OK;
1843 if (!CloseHandle (p->fd[0]->h))
1845 SetErrnoFromWinError (GetLastError ());
1846 ret = GNUNET_SYSERR;
1848 if (!CloseHandle (p->fd[1]->h))
1850 SetErrnoFromWinError (GetLastError ());
1851 ret = GNUNET_SYSERR;
1856 if (p->fd[0]->fd != -1)
1858 if (0 != close (p->fd[0]->fd))
1860 ret = GNUNET_SYSERR;
1865 if (p->fd[1]->fd != -1)
1867 if (0 != close (p->fd[1]->fd))
1869 ret = GNUNET_SYSERR;
1881 * Creates a named pipe/FIFO and opens it
1882 * @param fn pointer to the name of the named pipe or to NULL
1883 * @param flags open flags
1884 * @param perm access permissions
1885 * @return pipe handle on success, NULL on error
1887 struct GNUNET_DISK_FileHandle *
1888 GNUNET_DISK_npipe_create (char **fn,
1889 enum GNUNET_DISK_OpenFlags flags,
1890 enum GNUNET_DISK_AccessPermissions perm)
1893 struct GNUNET_DISK_FileHandle *ret;
1899 if (flags & GNUNET_DISK_OPEN_READWRITE)
1900 openMode = PIPE_ACCESS_DUPLEX;
1901 else if (flags & GNUNET_DISK_OPEN_READ)
1902 openMode = PIPE_ACCESS_INBOUND;
1903 else if (flags & GNUNET_DISK_OPEN_WRITE)
1904 openMode = PIPE_ACCESS_OUTBOUND;
1906 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1907 openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
1915 GNUNET_asprintf(&name, "\\\\.\\pipe\\%.246s", fn);
1917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to create an instance of named pipe `%s'\n", name);
1919 h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
1920 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
1924 GNUNET_asprintf(fn, "\\\\.\\pipe\\gnunet-%llu",
1925 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX));
1927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n", *fn);
1929 h = CreateNamedPipe (*fn, openMode | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
1930 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL);
1932 error_code = GetLastError ();
1935 /* don't re-set name to NULL yet */
1936 if (h == INVALID_HANDLE_VALUE)
1938 SetErrnoFromWinError(error_code);
1940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe creation have failed because of %d, errno is %d\n", error_code, errno);
1945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe was to be unique, considering re-creation\n");
1949 if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY)
1954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pipe name was not unique, trying again\n");
1964 ret = GNUNET_malloc(sizeof(*ret));
1966 ret->type = GNUNET_PIPE;
1972 char dir[] = "/tmp/gnunet-pipe-XXXXXX";
1974 if (mkdtemp(dir) == NULL)
1976 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "mkdtemp");
1979 GNUNET_asprintf(fn, "%s/child-control", dir);
1982 if (mkfifo(*fn, translate_unix_perms(perm)) == -1)
1984 if ( (errno != EEXIST) ||
1985 (0 != (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)) )
1989 flags = flags & (~GNUNET_DISK_OPEN_FAILIFEXISTS);
1990 return GNUNET_DISK_file_open(fn, flags, perm);
1995 * Opens already existing named pipe/FIFO
1997 * @param fn name of an existing named pipe
1998 * @param flags open flags
1999 * @param perm access permissions
2000 * @return pipe handle on success, NULL on error
2002 struct GNUNET_DISK_FileHandle *
2003 GNUNET_DISK_npipe_open (const char *fn,
2004 enum GNUNET_DISK_OpenFlags flags,
2005 enum GNUNET_DISK_AccessPermissions perm)
2008 struct GNUNET_DISK_FileHandle *ret;
2013 if (flags & GNUNET_DISK_OPEN_READWRITE)
2014 openMode = GENERIC_WRITE | GENERIC_READ;
2015 else if (flags & GNUNET_DISK_OPEN_READ)
2016 openMode = GENERIC_READ;
2017 else if (flags & GNUNET_DISK_OPEN_WRITE)
2018 openMode = GENERIC_WRITE;
2020 h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
2021 FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
2022 if (h == INVALID_HANDLE_VALUE)
2024 SetErrnoFromWinError(GetLastError());
2028 ret = GNUNET_malloc(sizeof(*ret));
2030 ret->type = GNUNET_PIPE;
2034 flags = flags & (~GNUNET_DISK_OPEN_FAILIFEXISTS);
2035 return GNUNET_DISK_file_open(fn, flags, perm);
2040 * Closes a named pipe/FIFO
2041 * @param pipe named pipe
2042 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2045 GNUNET_DISK_npipe_close (struct GNUNET_DISK_FileHandle *pipe)
2048 return close(pipe->fd) == 0 ? GNUNET_OK : GNUNET_SYSERR;
2052 ret = CloseHandle(pipe->h);
2055 SetErrnoFromWinError(GetLastError());
2056 return GNUNET_SYSERR;
2065 * Get the handle to a particular pipe end
2068 * @param n end to access
2069 * @return handle for the respective end
2071 const struct GNUNET_DISK_FileHandle *
2072 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2073 enum GNUNET_DISK_PipeEnd n)
2077 case GNUNET_DISK_PIPE_END_READ:
2078 case GNUNET_DISK_PIPE_END_WRITE:
2088 * Retrieve OS file handle
2090 * @param fh GNUnet file descriptor
2091 * @param dst destination buffer
2092 * @param dst_len length of dst
2093 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2096 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2097 void *dst, size_t dst_len)
2100 if (dst_len < sizeof (HANDLE))
2101 return GNUNET_SYSERR;
2102 *((HANDLE *) dst) = fh->h;
2104 if (dst_len < sizeof (int))
2105 return GNUNET_SYSERR;
2106 *((int *) dst) = fh->fd;