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 LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
39 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
41 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
43 #define DEBUG_NPIPE GNUNET_EXTRA_LOGGING
45 #define DEBUG_PIPE GNUNET_EXTRA_LOGGING
48 * Block size for IO for copying files.
50 #define COPY_BLK_SIZE 65536
54 #if defined(LINUX) || defined(CYGWIN)
57 #if defined(SOMEBSD) || defined(DARWIN)
58 #include <sys/param.h>
59 #include <sys/mount.h>
62 #include <sys/types.h>
63 #include <sys/statvfs.h>
68 ULONG PipeSerialNumber;
70 #define _IFMT 0170000 /* type of file */
71 #define _IFLNK 0120000 /* symbolic link */
72 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
74 #error PORT-ME: need to port statfs (how much space is left on the drive?)
80 #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS)
84 #include <sys/statvfs.h>
89 * Handle used to manage a pipe.
91 struct GNUNET_DISK_PipeHandle
94 * File descriptors for the pipe.
96 struct GNUNET_DISK_FileHandle *fd[2];
101 * Closure for the recursion to determine the file size
104 struct GetFileSizeData
107 * Set to the total file size.
112 * GNUNET_YES if symbolic links should be included.
114 int include_sym_links;
119 translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
124 if (perm & GNUNET_DISK_PERM_USER_READ)
126 if (perm & GNUNET_DISK_PERM_USER_WRITE)
128 if (perm & GNUNET_DISK_PERM_USER_EXEC)
130 if (perm & GNUNET_DISK_PERM_GROUP_READ)
132 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
134 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
136 if (perm & GNUNET_DISK_PERM_OTHER_READ)
138 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
140 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
148 * Iterate over all files in the given directory and
149 * accumulate their size.
151 * @param cls closure of type "struct GetFileSizeData"
152 * @param fn current filename we are looking at
153 * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
156 getSizeRec (void *cls, const char *fn)
158 struct GetFileSizeData *gfsd = cls;
167 if (0 != STAT64 (fn, &buf))
169 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat64", fn);
170 return GNUNET_SYSERR;
173 if (0 != STAT (fn, &buf))
175 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fn);
176 return GNUNET_SYSERR;
179 if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
180 gfsd->total += buf.st_size;
181 if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
182 ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
184 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
185 return GNUNET_SYSERR;
192 * Checks whether a handle is invalid
194 * @param h handle to check
195 * @return GNUNET_YES if invalid, GNUNET_NO if valid
198 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
201 return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
203 return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
208 * Get the size of an open file.
210 * @param fh open file handle
211 * @param size where to write size of the file
212 * @return GNUNET_OK on success, GNUNET_SYSERR on error
215 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
221 b = GetFileSizeEx (fh->h, &li);
224 SetErrnoFromWinError (GetLastError ());
225 return GNUNET_SYSERR;
227 *size = (OFF_T) li.QuadPart;
231 if (0 != FSTAT (fh->fd, &sbuf))
232 return GNUNET_SYSERR;
233 *size = sbuf.st_size;
240 * Move the read/write pointer in a file
242 * @param h handle of an open file
243 * @param offset position to move to
244 * @param whence specification to which position the offset parameter relates to
245 * @return the new position on success, GNUNET_SYSERR otherwise
248 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
249 enum GNUNET_DISK_Seek whence)
254 return GNUNET_SYSERR;
258 LARGE_INTEGER li, new_pos;
261 static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
262 [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
264 li.QuadPart = offset;
266 b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
269 SetErrnoFromWinError (GetLastError ());
270 return GNUNET_SYSERR;
272 return (OFF_T) new_pos.QuadPart;
274 static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
275 [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
278 return lseek (h->fd, offset, t[whence]);
284 * Get the size of the file (or directory) of the given file (in
287 * @param filename name of the file or directory
288 * @param size set to the size of the file (or,
289 * in the case of directories, the sum
290 * of all sizes of files in the directory)
291 * @param includeSymLinks should symbolic links be
293 * @return GNUNET_SYSERR on error, GNUNET_OK on success
296 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
299 struct GetFileSizeData gfsd;
302 GNUNET_assert (size != NULL);
304 gfsd.include_sym_links = includeSymLinks;
305 ret = getSizeRec (&gfsd, filename);
312 * Obtain some unique identifiers for the given file
313 * that can be used to identify it in the local system.
314 * This function is used between GNUnet processes to
315 * quickly check if two files with the same absolute path
316 * are actually identical. The two processes represent
317 * the same peer but may communicate over the network
318 * (and the file may be on an NFS volume). This function
319 * may not be supported on all operating systems.
321 * @param filename name of the file
322 * @param dev set to the device ID
323 * @param ino set to the inode ID
324 * @return GNUNET_OK on success
327 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
334 if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
336 *dev = (uint64_t) fbuf.f_fsid;
337 *ino = (uint64_t) sbuf.st_ino;
344 if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
346 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
347 ((uint64_t) fbuf.f_fsid.val[1]);
348 *ino = (uint64_t) sbuf.st_ino;
352 // FIXME NILS: test this
353 struct GNUNET_DISK_FileHandle *fh;
354 BY_HANDLE_FILE_INFORMATION info;
357 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
359 return GNUNET_SYSERR;
360 succ = GetFileInformationByHandle (fh->h, &info);
361 GNUNET_DISK_file_close (fh);
364 *dev = info.dwVolumeSerialNumber;
365 *ino = ((info.nFileIndexHigh << sizeof (DWORD)) | info.nFileIndexLow);
369 return GNUNET_SYSERR;
372 return GNUNET_SYSERR;
377 * Create an (empty) temporary file on disk. If the given name is not
378 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
379 * 6 random characters will be appended to the name to create a unique
382 * @param t component to use for the name;
383 * does NOT contain "XXXXXX" or "/tmp/".
384 * @return NULL on error, otherwise name of fresh
385 * file on disk in directory for temporary files
388 GNUNET_DISK_mktemp (const char *t)
395 if ((t[0] != '/') && (t[0] != '\\')
397 && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
401 /* FIXME: This uses system codepage on W32, not UTF-8 */
402 tmpdir = getenv ("TMPDIR");
403 tmpdir = tmpdir ? tmpdir : "/tmp";
404 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
408 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
411 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
412 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
422 /* FIXME: why is this not MKSTEMP()? This function is implemented in plibc.
423 * It will assume that fn is UTF-8-encoded, if compiled with UTF-8 support.
428 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
433 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
439 * Get the number of blocks that are left on the partition that
440 * contains the given file (for normal users).
442 * @param part a file on the partition to check
443 * @return -1 on errors, otherwise the number of free blocks
446 GNUNET_DISK_get_blocks_available (const char *part)
451 if (0 != statvfs (part, &buf))
453 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
461 wchar_t wpath[MAX_PATH + 1];
464 path = GNUNET_STRINGS_filename_expand (part);
467 /* "part" was in UTF-8, and so is "path" */
468 if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
474 wcsncpy (szDrive, wpath, 3);
477 if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
479 LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
480 "GetDiskFreeSpace", szDrive, GetLastError ());
488 if (0 != statfs (part, &s))
490 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
499 * Test if "fil" is a directory.
500 * Will not print an error message if the directory
501 * does not exist. Will log errors if GNUNET_SYSERR is
502 * returned (i.e., a file exists with the same name).
504 * @param fil filename to test
505 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
509 GNUNET_DISK_directory_test (const char *fil)
511 struct stat filestat;
514 ret = STAT (fil, &filestat);
519 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
520 return GNUNET_SYSERR;
524 if (!S_ISDIR (filestat.st_mode))
526 if (ACCESS (fil, R_OK | X_OK) < 0)
528 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
529 return GNUNET_SYSERR;
535 * Check that fil corresponds to a filename
536 * (of a file that exists and that is not a directory).
538 * @param fil filename to check
539 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
540 * else (will print an error message in that case, too).
543 GNUNET_DISK_file_test (const char *fil)
545 struct stat filestat;
549 rdir = GNUNET_STRINGS_filename_expand (fil);
551 return GNUNET_SYSERR;
553 ret = STAT (rdir, &filestat);
558 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
560 return GNUNET_SYSERR;
565 if (!S_ISREG (filestat.st_mode))
570 if (ACCESS (rdir, R_OK) < 0)
572 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
574 return GNUNET_SYSERR;
582 * Implementation of "mkdir -p"
583 * @param dir the directory to create
584 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
587 GNUNET_DISK_directory_create (const char *dir)
594 rdir = GNUNET_STRINGS_filename_expand (dir);
596 return GNUNET_SYSERR;
600 pos = 1; /* skip heading '/' */
602 /* Local or Network path? */
603 if (strncmp (rdir, "\\\\", 2) == 0)
608 if (rdir[pos] == '\\')
618 pos = 3; /* strlen("C:\\") */
623 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
626 ret = GNUNET_DISK_directory_test (rdir);
627 if (ret == GNUNET_SYSERR)
630 return GNUNET_SYSERR;
632 if (ret == GNUNET_NO)
635 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
637 wchar_t wrdir[MAX_PATH + 1];
638 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
639 ret = !CreateDirectoryW (wrdir, NULL);
643 if ((ret != 0) && (errno != EEXIST))
645 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
647 return GNUNET_SYSERR;
650 rdir[pos] = DIR_SEPARATOR;
660 * Create the directory structure for storing
663 * @param filename name of a file in the directory
664 * @returns GNUNET_OK on success,
665 * GNUNET_SYSERR on failure,
666 * GNUNET_NO if the directory
667 * exists but is not writeable for us
670 GNUNET_DISK_directory_create_for_file (const char *filename)
676 rdir = GNUNET_STRINGS_filename_expand (filename);
678 return GNUNET_SYSERR;
680 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
683 ret = GNUNET_DISK_directory_create (rdir);
684 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
692 * Read the contents of a binary file into a buffer.
693 * @param h handle to an open file
694 * @param result the buffer to write the result to
695 * @param len the maximum number of bytes to read
696 * @return the number of bytes read on success, GNUNET_SYSERR on failure
699 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
705 return GNUNET_SYSERR;
711 if (h->type != GNUNET_PIPE)
713 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
715 SetErrnoFromWinError (GetLastError ());
716 return GNUNET_SYSERR;
721 if (!ReadFile (h->h, result, len, NULL, h->oOverlapRead))
723 if (GetLastError () != ERROR_IO_PENDING)
725 SetErrnoFromWinError (GetLastError ());
726 return GNUNET_SYSERR;
729 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
733 return read (h->fd, result, len);
739 * Read the contents of a binary file into a buffer.
741 * @param fn file name
742 * @param result the buffer to write the result to
743 * @param len the maximum number of bytes to read
744 * @return number of bytes read, GNUNET_SYSERR on failure
747 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
749 struct GNUNET_DISK_FileHandle *fh;
752 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
754 return GNUNET_SYSERR;
755 ret = GNUNET_DISK_file_read (fh, result, len);
756 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
763 * Write a buffer to a file.
764 * @param h handle to open file
765 * @param buffer the data to write
766 * @param n number of bytes to write
767 * @return number of bytes written on success, GNUNET_SYSERR on error
770 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
771 const void *buffer, size_t n)
776 return GNUNET_SYSERR;
782 if (h->type != GNUNET_PIPE)
784 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
786 SetErrnoFromWinError (GetLastError ());
787 return GNUNET_SYSERR;
793 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write\n");
795 if (!WriteFile (h->h, buffer, n, NULL, h->oOverlapWrite))
797 if (GetLastError () != ERROR_IO_PENDING)
799 SetErrnoFromWinError (GetLastError ());
801 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe\n");
803 return GNUNET_SYSERR;
807 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
809 GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE);
813 return write (h->fd, buffer, n);
818 * Write a buffer to a file. If the file is longer than the
819 * number of bytes that will be written, it will be truncated.
821 * @param fn file name
822 * @param buffer the data to write
823 * @param n number of bytes to write
824 * @param mode file permissions
825 * @return number of bytes written on success, GNUNET_SYSERR on error
828 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
829 enum GNUNET_DISK_AccessPermissions mode)
831 struct GNUNET_DISK_FileHandle *fh;
834 fh = GNUNET_DISK_file_open (fn,
835 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
836 | GNUNET_DISK_OPEN_CREATE, mode);
838 return GNUNET_SYSERR;
839 ret = GNUNET_DISK_file_write (fh, buffer, n);
840 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
846 * Scan a directory for files.
848 * @param dirName the name of the directory
849 * @param callback the method to call for each file,
850 * can be NULL, in that case, we only count
851 * @param callback_cls closure for callback
852 * @return the number of files found, GNUNET_SYSERR on error or
853 * ieration aborted by callback returning GNUNET_SYSERR
856 GNUNET_DISK_directory_scan (const char *dirName,
857 GNUNET_FileNameCallback callback,
861 struct dirent *finfo;
866 unsigned int name_len;
869 GNUNET_assert (dirName != NULL);
870 dname = GNUNET_STRINGS_filename_expand (dirName);
872 return GNUNET_SYSERR;
873 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
874 dname[strlen (dname) - 1] = '\0';
875 if (0 != STAT (dname, &istat))
877 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
879 return GNUNET_SYSERR;
881 if (!S_ISDIR (istat.st_mode))
883 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
886 return GNUNET_SYSERR;
889 dinfo = OPENDIR (dname);
890 if ((errno == EACCES) || (dinfo == NULL))
892 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
896 return GNUNET_SYSERR;
899 n_size = strlen (dname) + name_len + 2;
900 name = GNUNET_malloc (n_size);
901 while ((finfo = READDIR (dinfo)) != NULL)
903 if ((0 == strcmp (finfo->d_name, ".")) ||
904 (0 == strcmp (finfo->d_name, "..")))
906 if (callback != NULL)
908 if (name_len < strlen (finfo->d_name))
911 name_len = strlen (finfo->d_name);
912 n_size = strlen (dname) + name_len + 2;
913 name = GNUNET_malloc (n_size);
915 /* dname can end in "/" only if dname == "/";
916 * if dname does not end in "/", we need to add
917 * a "/" (otherwise, we must not!) */
918 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
919 (strcmp (dname, DIR_SEPARATOR_STR) ==
920 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
921 if (GNUNET_OK != callback (callback_cls, name))
926 return GNUNET_SYSERR;
939 * Opaque handle used for iterating over a directory.
941 struct GNUNET_DISK_DirectoryIterator
945 * Function to call on directory entries.
947 GNUNET_DISK_DirectoryIteratorCallback callback;
950 * Closure for callback.
955 * Reference to directory.
965 * Next filename to process.
972 enum GNUNET_SCHEDULER_Priority priority;
978 * Task used by the directory iterator.
981 directory_iterator_task (void *cls,
982 const struct GNUNET_SCHEDULER_TaskContext *tc)
984 struct GNUNET_DISK_DirectoryIterator *iter = cls;
987 name = iter->next_name;
988 GNUNET_assert (name != NULL);
989 iter->next_name = NULL;
990 iter->callback (iter->callback_cls, iter, name, iter->dirname);
996 * This function must be called during the DiskIteratorCallback
997 * (exactly once) to schedule the task to process the next
998 * filename in the directory (if there is one).
1000 * @param iter opaque handle for the iterator
1001 * @param can set to GNUNET_YES to terminate the iteration early
1002 * @return GNUNET_YES if iteration will continue,
1003 * GNUNET_NO if this was the last entry (and iteration is complete),
1004 * GNUNET_SYSERR if abort was YES
1007 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1010 struct dirent *finfo;
1012 GNUNET_assert (iter->next_name == NULL);
1013 if (can == GNUNET_YES)
1015 CLOSEDIR (iter->directory);
1016 GNUNET_free (iter->dirname);
1018 return GNUNET_SYSERR;
1020 while (NULL != (finfo = READDIR (iter->directory)))
1022 if ((0 == strcmp (finfo->d_name, ".")) ||
1023 (0 == strcmp (finfo->d_name, "..")))
1025 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1026 DIR_SEPARATOR_STR, finfo->d_name);
1031 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1034 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1041 * Scan a directory for files using the scheduler to run a task for
1042 * each entry. The name of the directory must be expanded first (!).
1043 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1044 * may provide a simpler API.
1046 * @param prio priority to use
1047 * @param dirName the name of the directory
1048 * @param callback the method to call for each file
1049 * @param callback_cls closure for callback
1052 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1053 const char *dirName,
1054 GNUNET_DISK_DirectoryIteratorCallback
1055 callback, void *callback_cls)
1057 struct GNUNET_DISK_DirectoryIterator *di;
1059 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1060 di->callback = callback;
1061 di->callback_cls = callback_cls;
1062 di->directory = OPENDIR (dirName);
1063 if (di->directory == NULL)
1066 callback (callback_cls, NULL, NULL, NULL);
1069 di->dirname = GNUNET_strdup (dirName);
1070 di->priority = prio;
1071 GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1076 * Function that removes the given directory by calling
1077 * "GNUNET_DISK_directory_remove".
1079 * @param unused not used
1080 * @param fn directory to remove
1084 remove_helper (void *unused, const char *fn)
1086 (void) GNUNET_DISK_directory_remove (fn);
1092 * Remove all files in a directory (rm -rf). Call with
1096 * @param fileName the file to remove
1097 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1100 GNUNET_DISK_directory_remove (const char *fileName)
1104 if (0 != LSTAT (fileName, &istat))
1105 return GNUNET_NO; /* file may not exist... */
1106 CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR);
1107 if (UNLINK (fileName) == 0)
1109 if ((errno != EISDIR) &&
1110 /* EISDIR is not sufficient in all cases, e.g.
1111 * sticky /tmp directory may result in EPERM on BSD.
1112 * So we also explicitly check "isDirectory" */
1113 (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
1115 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1116 return GNUNET_SYSERR;
1118 if (GNUNET_SYSERR ==
1119 GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL))
1120 return GNUNET_SYSERR;
1121 if (0 != RMDIR (fileName))
1123 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1124 return GNUNET_SYSERR;
1133 * @param src file to copy
1134 * @param dst destination file name
1135 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1138 GNUNET_DISK_file_copy (const char *src, const char *dst)
1144 struct GNUNET_DISK_FileHandle *in;
1145 struct GNUNET_DISK_FileHandle *out;
1147 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES))
1148 return GNUNET_SYSERR;
1150 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1151 GNUNET_DISK_PERM_NONE);
1153 return GNUNET_SYSERR;
1155 GNUNET_DISK_file_open (dst,
1156 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1157 GNUNET_DISK_OPEN_FAILIFEXISTS,
1158 GNUNET_DISK_PERM_USER_READ |
1159 GNUNET_DISK_PERM_USER_WRITE |
1160 GNUNET_DISK_PERM_GROUP_READ |
1161 GNUNET_DISK_PERM_GROUP_WRITE);
1164 GNUNET_DISK_file_close (in);
1165 return GNUNET_SYSERR;
1167 buf = GNUNET_malloc (COPY_BLK_SIZE);
1170 len = COPY_BLK_SIZE;
1171 if (len > size - pos)
1173 if (len != GNUNET_DISK_file_read (in, buf, len))
1175 if (len != GNUNET_DISK_file_write (out, buf, len))
1180 GNUNET_DISK_file_close (in);
1181 GNUNET_DISK_file_close (out);
1185 GNUNET_DISK_file_close (in);
1186 GNUNET_DISK_file_close (out);
1187 return GNUNET_SYSERR;
1192 * @brief Removes special characters as ':' from a filename.
1193 * @param fn the filename to canonicalize
1196 GNUNET_DISK_filename_canonicalize (char *fn)
1206 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1207 c == '<' || c == '>' || c == '|')
1219 * @brief Change owner of a file
1221 * @param filename name of file to change the owner of
1222 * @param user name of the new owner
1223 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1226 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1231 pws = getpwnam (user);
1234 LOG (GNUNET_ERROR_TYPE_ERROR,
1235 _("Cannot obtain information about user `%s': %s\n"), user,
1237 return GNUNET_SYSERR;
1239 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1240 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1247 * Lock a part of a file
1248 * @param fh file handle
1249 * @param lockStart absolute position from where to lock
1250 * @param lockEnd absolute position until where to lock
1251 * @param excl GNUNET_YES for an exclusive lock
1252 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1255 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1256 OFF_T lockEnd, int excl)
1261 return GNUNET_SYSERR;
1267 memset (&fl, 0, sizeof (struct flock));
1268 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1269 fl.l_whence = SEEK_SET;
1270 fl.l_start = lockStart;
1273 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1277 memset (&o, 0, sizeof (OVERLAPPED));
1278 o.Offset = lockStart;
1281 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1282 0, lockEnd - lockStart, 0, &o))
1284 SetErrnoFromWinError (GetLastError ());
1285 return GNUNET_SYSERR;
1294 * Unlock a part of a file
1295 * @param fh file handle
1296 * @param unlockStart absolute position from where to unlock
1297 * @param unlockEnd absolute position until where to unlock
1298 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1301 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1307 return GNUNET_SYSERR;
1313 memset (&fl, 0, sizeof (struct flock));
1314 fl.l_type = F_UNLCK;
1315 fl.l_whence = SEEK_SET;
1316 fl.l_start = unlockStart;
1317 fl.l_len = unlockEnd;
1319 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1323 memset (&o, 0, sizeof (OVERLAPPED));
1324 o.Offset = unlockStart;
1326 if (!UnlockFileEx (fh->h, 0, unlockEnd - unlockStart, 0, &o))
1328 SetErrnoFromWinError (GetLastError ());
1329 return GNUNET_SYSERR;
1338 * Open a file. Note that the access permissions will only be
1339 * used if a new file is created and if the underlying operating
1340 * system supports the given permissions.
1342 * @param fn file name to be opened
1343 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1344 * @param perm permissions for the newly created file, use
1345 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1346 * call (because of flags)
1347 * @return IO handle on success, NULL on error
1349 struct GNUNET_DISK_FileHandle *
1350 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1351 enum GNUNET_DISK_AccessPermissions perm)
1354 struct GNUNET_DISK_FileHandle *ret;
1360 wchar_t wexpfn[MAX_PATH + 1];
1367 expfn = GNUNET_STRINGS_filename_expand (fn);
1372 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1373 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1374 else if (flags & GNUNET_DISK_OPEN_READ)
1376 else if (flags & GNUNET_DISK_OPEN_WRITE)
1381 GNUNET_free (expfn);
1384 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1385 oflags |= (O_CREAT | O_EXCL);
1386 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1388 if (flags & GNUNET_DISK_OPEN_APPEND)
1390 if (flags & GNUNET_DISK_OPEN_CREATE)
1392 (void) GNUNET_DISK_directory_create_for_file (expfn);
1394 mode = translate_unix_perms (perm);
1397 fd = open (expfn, oflags | O_LARGEFILE, mode);
1400 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1401 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1403 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1404 GNUNET_free (expfn);
1411 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1412 access = FILE_READ_DATA | FILE_WRITE_DATA;
1413 else if (flags & GNUNET_DISK_OPEN_READ)
1414 access = FILE_READ_DATA;
1415 else if (flags & GNUNET_DISK_OPEN_WRITE)
1416 access = FILE_WRITE_DATA;
1418 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1422 else if (flags & GNUNET_DISK_OPEN_CREATE)
1424 (void) GNUNET_DISK_directory_create_for_file (expfn);
1425 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1426 disp = CREATE_ALWAYS;
1430 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1432 disp = TRUNCATE_EXISTING;
1436 disp = OPEN_EXISTING;
1439 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1440 h = CreateFileW (wexpfn, access,
1441 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1442 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1444 h = INVALID_HANDLE_VALUE;
1445 if (h == INVALID_HANDLE_VALUE)
1447 SetErrnoFromWinError (GetLastError ());
1448 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1449 GNUNET_free (expfn);
1453 if (flags & GNUNET_DISK_OPEN_APPEND)
1454 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1456 SetErrnoFromWinError (GetLastError ());
1457 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1459 GNUNET_free (expfn);
1464 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1467 ret->type = GNUNET_DISK_FILE;
1471 GNUNET_free (expfn);
1477 * Close an open file
1478 * @param h file handle
1479 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1482 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1487 return GNUNET_SYSERR;
1491 if (!CloseHandle (h->h))
1493 SetErrnoFromWinError (GetLastError ());
1494 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1495 GNUNET_free (h->oOverlapRead);
1496 GNUNET_free (h->oOverlapWrite);
1498 return GNUNET_SYSERR;
1501 if (close (h->fd) != 0)
1503 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1505 return GNUNET_SYSERR;
1514 * Construct full path to a file inside of the private
1515 * directory used by GNUnet. Also creates the corresponding
1516 * directory. If the resulting name is supposed to be
1517 * a directory, end the last argument in '/' (or pass
1518 * DIR_SEPARATOR_STR as the last argument before NULL).
1520 * @param cfg configuration to use (determines HOME)
1521 * @param serviceName name of the service
1522 * @param ... is NULL-terminated list of
1523 * path components to append to the
1524 * private directory name.
1525 * @return the constructed filename
1528 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1529 const char *serviceName, ...)
1535 unsigned int needed;
1538 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1542 LOG (GNUNET_ERROR_TYPE_WARNING,
1543 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1547 needed = strlen (pfx) + 2;
1548 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1550 va_start (ap, serviceName);
1553 c = va_arg (ap, const char *);
1557 needed += strlen (c);
1558 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1562 ret = GNUNET_malloc (needed);
1565 va_start (ap, serviceName);
1568 c = va_arg (ap, const char *);
1572 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1573 strcat (ret, DIR_SEPARATOR_STR);
1577 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1578 (void) GNUNET_DISK_directory_create_for_file (ret);
1580 (void) GNUNET_DISK_directory_create (ret);
1586 * Handle for a memory-mapping operation.
1588 struct GNUNET_DISK_MapHandle
1591 * Address where the map is in memory.
1597 * Underlying OS handle.
1602 * Number of bytes mapped.
1610 #define MAP_FAILED ((void *) -1)
1614 * Map a file into memory
1616 * @param h open file handle
1617 * @param m handle to the new mapping
1618 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1619 * @param len size of the mapping
1620 * @return pointer to the mapped memory region, NULL on failure
1623 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1624 struct GNUNET_DISK_MapHandle **m,
1625 enum GNUNET_DISK_MapType access, size_t len)
1634 DWORD mapAccess, protect;
1636 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1637 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1639 protect = PAGE_READWRITE;
1640 mapAccess = FILE_MAP_ALL_ACCESS;
1642 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1644 protect = PAGE_READONLY;
1645 mapAccess = FILE_MAP_READ;
1647 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1649 protect = PAGE_READWRITE;
1650 mapAccess = FILE_MAP_WRITE;
1658 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1659 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1660 if ((*m)->h == INVALID_HANDLE_VALUE)
1662 SetErrnoFromWinError (GetLastError ());
1667 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1670 SetErrnoFromWinError (GetLastError ());
1671 CloseHandle ((*m)->h);
1680 if (access & GNUNET_DISK_MAP_TYPE_READ)
1682 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1684 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1685 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1686 GNUNET_assert (NULL != (*m)->addr);
1687 if (MAP_FAILED == (*m)->addr)
1699 * @param h mapping handle
1700 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1703 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1710 return GNUNET_SYSERR;
1714 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
1715 if (ret != GNUNET_OK)
1716 SetErrnoFromWinError (GetLastError ());
1717 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
1719 ret = GNUNET_SYSERR;
1720 SetErrnoFromWinError (GetLastError ());
1723 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1731 * Write file changes to disk
1732 * @param h handle to an open file
1733 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1736 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1741 return GNUNET_SYSERR;
1747 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1748 if (ret != GNUNET_OK)
1749 SetErrnoFromWinError (GetLastError ());
1751 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
1752 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1754 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1759 /* Copyright Bob Byrnes <byrnes <at> curl.com>
1760 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
1762 /* Create a pipe, and return handles to the read and write ends,
1763 just like CreatePipe, but ensure that the write end permits
1764 FILE_READ_ATTRIBUTES access, on later versions of win32 where
1765 this is supported. This access is needed by NtQueryInformationFile,
1766 which is used to implement select and nonblocking writes.
1767 Note that the return value is either NO_ERROR or GetLastError,
1768 unlike CreatePipe, which returns a bool for success or failure. */
1770 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
1771 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
1772 DWORD dwReadMode, DWORD dwWriteMode)
1774 /* Default to error. */
1775 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
1777 HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
1779 /* Ensure that there is enough pipe buffer space for atomic writes. */
1780 if (psize < PIPE_BUF)
1783 char pipename[MAX_PATH];
1785 /* Retry CreateNamedPipe as long as the pipe name is in use.
1786 * Retrying will probably never be necessary, but we want
1787 * to be as robust as possible. */
1790 static volatile LONG pipe_unique_id;
1792 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
1793 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
1795 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
1798 /* Use CreateNamedPipe instead of CreatePipe, because the latter
1799 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
1800 * access, on versions of win32 earlier than WinXP SP2.
1801 * CreatePipe also stupidly creates a full duplex pipe, which is
1802 * a waste, since only a single direction is actually used.
1803 * It's important to only allow a single instance, to ensure that
1804 * the pipe was not created earlier by some other process, even if
1805 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
1806 * because that is only available for Win2k SP2 and WinXP. */
1807 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
1808 psize, /* output buffer size */
1809 psize, /* input buffer size */
1810 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
1812 if (read_pipe != INVALID_HANDLE_VALUE)
1815 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
1820 DWORD err = GetLastError ();
1824 case ERROR_PIPE_BUSY:
1825 /* The pipe is already open with compatible parameters.
1826 * Pick a new name and retry. */
1828 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
1831 case ERROR_ACCESS_DENIED:
1832 /* The pipe is already open with incompatible parameters.
1833 * Pick a new name and retry. */
1835 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
1838 case ERROR_CALL_NOT_IMPLEMENTED:
1839 /* We are on an older Win9x platform without named pipes.
1840 * Return an anonymous pipe as the best approximation. */
1842 LOG (GNUNET_ERROR_TYPE_DEBUG,
1843 "CreateNamedPipe not implemented, resorting to "
1844 "CreatePipe: size = %lu\n", psize);
1846 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
1849 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n",
1851 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n",
1856 err = GetLastError ();
1857 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
1860 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
1866 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
1869 /* Open the named pipe for writing.
1870 * Be sure to permit FILE_READ_ATTRIBUTES access. */
1871 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
1872 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
1873 0); /* handle to template file */
1875 if (write_pipe == INVALID_HANDLE_VALUE)
1878 DWORD err = GetLastError ();
1881 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
1883 CloseHandle (read_pipe);
1887 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
1890 *read_pipe_ptr = read_pipe;
1891 *write_pipe_ptr = write_pipe;
1897 * Creates an interprocess channel
1899 * @param blocking creates an asynchronous pipe if set to GNUNET_NO
1900 * @param inherit_read inherit the parent processes stdin (only for windows)
1901 * @param inherit_write inherit the parent processes stdout (only for windows)
1903 * @return handle to the new pipe, NULL on error
1905 struct GNUNET_DISK_PipeHandle *
1906 GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
1908 struct GNUNET_DISK_PipeHandle *p;
1909 struct GNUNET_DISK_FileHandle *fds;
1911 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
1912 2 * sizeof (struct GNUNET_DISK_FileHandle));
1913 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
1926 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1931 p->fd[0]->fd = fd[0];
1932 p->fd[1]->fd = fd[1];
1934 flags = fcntl (fd[0], F_GETFL);
1936 flags |= O_NONBLOCK;
1937 if (0 > fcntl (fd[0], F_SETFL, flags))
1939 flags = fcntl (fd[0], F_GETFD);
1940 flags |= FD_CLOEXEC;
1941 if (0 > fcntl (fd[0], F_SETFD, flags))
1944 flags = fcntl (fd[1], F_GETFL);
1946 flags |= O_NONBLOCK;
1947 if (0 > fcntl (fd[1], F_SETFL, flags))
1949 flags = fcntl (fd[1], F_GETFD);
1950 flags |= FD_CLOEXEC;
1951 if (0 > fcntl (fd[1], F_SETFD, flags))
1956 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
1957 GNUNET_break (0 == close (p->fd[0]->fd));
1958 GNUNET_break (0 == close (p->fd[1]->fd));
1968 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
1969 FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED);
1973 SetErrnoFromWinError (GetLastError ());
1976 if (!DuplicateHandle
1977 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
1978 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
1980 SetErrnoFromWinError (GetLastError ());
1981 CloseHandle (p->fd[0]->h);
1982 CloseHandle (p->fd[1]->h);
1986 CloseHandle (p->fd[0]->h);
1987 p->fd[0]->h = tmp_handle;
1989 if (!DuplicateHandle
1990 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
1991 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
1993 SetErrnoFromWinError (GetLastError ());
1994 CloseHandle (p->fd[0]->h);
1995 CloseHandle (p->fd[1]->h);
1999 CloseHandle (p->fd[1]->h);
2000 p->fd[1]->h = tmp_handle;
2006 SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
2007 SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
2008 /* this always fails on Windows 95, so we don't care about error handling */
2010 p->fd[0]->type = GNUNET_PIPE;
2011 p->fd[1]->type = GNUNET_PIPE;
2013 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2014 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2015 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2016 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2018 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2019 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2021 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2022 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2030 * Closes an interprocess channel
2032 * @param p pipe to close
2033 * @param end which end of the pipe to close
2034 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2037 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2038 enum GNUNET_DISK_PipeEnd end)
2040 int ret = GNUNET_OK;
2044 if (end == GNUNET_DISK_PIPE_END_READ)
2046 if (!CloseHandle (p->fd[0]->h))
2048 SetErrnoFromWinError (GetLastError ());
2049 ret = GNUNET_SYSERR;
2051 p->fd[0]->h = INVALID_HANDLE_VALUE;
2053 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2055 if (!CloseHandle (p->fd[1]->h))
2057 SetErrnoFromWinError (GetLastError ());
2058 ret = GNUNET_SYSERR;
2060 p->fd[1]->h = INVALID_HANDLE_VALUE;
2065 if (end == GNUNET_DISK_PIPE_END_READ)
2067 if (0 != close (p->fd[0]->fd))
2069 ret = GNUNET_SYSERR;
2074 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2076 if (0 != close (p->fd[1]->fd))
2078 ret = GNUNET_SYSERR;
2089 * Closes an interprocess channel
2091 * @param p pipe to close
2092 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2095 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2097 int ret = GNUNET_OK;
2101 if (!CloseHandle (p->fd[0]->h))
2103 SetErrnoFromWinError (GetLastError ());
2104 ret = GNUNET_SYSERR;
2106 if (!CloseHandle (p->fd[1]->h))
2108 SetErrnoFromWinError (GetLastError ());
2109 ret = GNUNET_SYSERR;
2114 if (p->fd[0]->fd != -1)
2116 if (0 != close (p->fd[0]->fd))
2118 ret = GNUNET_SYSERR;
2123 if (p->fd[1]->fd != -1)
2125 if (0 != close (p->fd[1]->fd))
2127 ret = GNUNET_SYSERR;
2139 * Creates a named pipe/FIFO and opens it
2140 * @param fn pointer to the name of the named pipe or to NULL
2141 * @param flags open flags
2142 * @param perm access permissions
2143 * @return pipe handle on success, NULL on error
2145 struct GNUNET_DISK_FileHandle *
2146 GNUNET_DISK_npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags,
2147 enum GNUNET_DISK_AccessPermissions perm)
2150 struct GNUNET_DISK_FileHandle *ret;
2156 if (flags & GNUNET_DISK_OPEN_READWRITE)
2157 openMode = PIPE_ACCESS_DUPLEX;
2158 else if (flags & GNUNET_DISK_OPEN_READ)
2159 openMode = PIPE_ACCESS_INBOUND;
2160 else if (flags & GNUNET_DISK_OPEN_WRITE)
2161 openMode = PIPE_ACCESS_OUTBOUND;
2163 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
2164 openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
2173 GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn);
2175 LOG (GNUNET_ERROR_TYPE_DEBUG,
2176 "Trying to create an instance of named pipe `%s'\n", name);
2178 /* 1) This might work just fine with UTF-8 strings as it is.
2179 * 2) This is only used by GNUnet itself, and only with latin names.
2181 h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED,
2182 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
2187 GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu",
2188 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
2191 LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n",
2194 h = CreateNamedPipe (*fn,
2195 openMode | FILE_FLAG_OVERLAPPED |
2196 FILE_FLAG_FIRST_PIPE_INSTANCE,
2197 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0,
2200 error_code = GetLastError ();
2203 /* don't re-set name to NULL yet */
2204 if (h == INVALID_HANDLE_VALUE)
2206 SetErrnoFromWinError (error_code);
2208 LOG (GNUNET_ERROR_TYPE_DEBUG,
2209 "Pipe creation have failed because of %d, errno is %d\n", error_code,
2215 LOG (GNUNET_ERROR_TYPE_DEBUG,
2216 "Pipe was to be unique, considering re-creation\n");
2220 if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY)
2225 LOG (GNUNET_ERROR_TYPE_DEBUG,
2226 "Pipe name was not unique, trying again\n");
2236 ret = GNUNET_malloc (sizeof (*ret));
2238 ret->type = GNUNET_PIPE;
2240 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2241 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2243 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2244 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2250 char dir[] = "/tmp/gnunet-pipe-XXXXXX";
2252 if (mkdtemp (dir) == NULL)
2254 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp");
2257 GNUNET_asprintf (fn, "%s/child-control", dir);
2260 if (mkfifo (*fn, translate_unix_perms (perm)) == -1)
2262 if ((errno != EEXIST) || (0 != (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)))
2266 flags = flags & (~GNUNET_DISK_OPEN_FAILIFEXISTS);
2267 return GNUNET_DISK_file_open (*fn, flags, perm);
2273 * Opens already existing named pipe/FIFO
2275 * @param fn name of an existing named pipe
2276 * @param flags open flags
2277 * @param perm access permissions
2278 * @return pipe handle on success, NULL on error
2280 struct GNUNET_DISK_FileHandle *
2281 GNUNET_DISK_npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
2282 enum GNUNET_DISK_AccessPermissions perm)
2285 struct GNUNET_DISK_FileHandle *ret;
2290 if (flags & GNUNET_DISK_OPEN_READWRITE)
2291 openMode = GENERIC_WRITE | GENERIC_READ;
2292 else if (flags & GNUNET_DISK_OPEN_READ)
2293 openMode = GENERIC_READ;
2294 else if (flags & GNUNET_DISK_OPEN_WRITE)
2295 openMode = GENERIC_WRITE;
2297 h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING,
2298 FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
2299 if (h == INVALID_HANDLE_VALUE)
2301 SetErrnoFromWinError (GetLastError ());
2305 ret = GNUNET_malloc (sizeof (*ret));
2307 ret->type = GNUNET_PIPE;
2308 ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2309 ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2310 ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2311 ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2315 flags = flags & (~GNUNET_DISK_OPEN_FAILIFEXISTS);
2316 return GNUNET_DISK_file_open (fn, flags, perm);
2321 * Closes a named pipe/FIFO
2322 * @param pipe named pipe
2323 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2326 GNUNET_DISK_npipe_close (struct GNUNET_DISK_FileHandle *pipe)
2329 return close (pipe->fd) == 0 ? GNUNET_OK : GNUNET_SYSERR;
2333 ret = CloseHandle (pipe->h);
2336 SetErrnoFromWinError (GetLastError ());
2337 return GNUNET_SYSERR;
2346 * Get the handle to a particular pipe end
2349 * @param n end to access
2350 * @return handle for the respective end
2352 const struct GNUNET_DISK_FileHandle *
2353 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2354 enum GNUNET_DISK_PipeEnd n)
2358 case GNUNET_DISK_PIPE_END_READ:
2359 case GNUNET_DISK_PIPE_END_WRITE:
2369 * Retrieve OS file handle
2371 * @param fh GNUnet file descriptor
2372 * @param dst destination buffer
2373 * @param dst_len length of dst
2374 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2377 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2378 void *dst, size_t dst_len)
2381 if (dst_len < sizeof (HANDLE))
2382 return GNUNET_SYSERR;
2383 *((HANDLE *) dst) = fh->h;
2385 if (dst_len < sizeof (int))
2386 return GNUNET_SYSERR;
2387 *((int *) dst) = fh->fd;