2 This file is part of GNUnet.
3 (C) 2001--2012 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)
44 * Block size for IO for copying files.
46 #define COPY_BLK_SIZE 65536
50 #if defined(LINUX) || defined(CYGWIN) || defined(GNU)
53 #if defined(SOMEBSD) || defined(DARWIN)
54 #include <sys/param.h>
55 #include <sys/mount.h>
58 #include <sys/types.h>
59 #include <sys/statvfs.h>
64 ULONG PipeSerialNumber;
66 #define _IFMT 0170000 /* type of file */
67 #define _IFLNK 0120000 /* symbolic link */
68 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
70 #error PORT-ME: need to port statfs (how much space is left on the drive?)
76 #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS)
80 #include <sys/statvfs.h>
85 * Handle used to manage a pipe.
87 struct GNUNET_DISK_PipeHandle
90 * File descriptors for the pipe.
92 struct GNUNET_DISK_FileHandle *fd[2];
97 * Closure for the recursion to determine the file size
100 struct GetFileSizeData
103 * Set to the total file size.
108 * GNUNET_YES if symbolic links should be included.
110 int include_sym_links;
113 * GNUNET_YES if mode is file-only (return total == -1 for directories).
115 int single_file_mode;
121 * Translate GNUnet-internal permission bitmap to UNIX file
122 * access permission bitmap.
124 * @param perm file permissions, GNUnet style
125 * @return file permissions, UNIX style
128 translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
133 if (perm & GNUNET_DISK_PERM_USER_READ)
135 if (perm & GNUNET_DISK_PERM_USER_WRITE)
137 if (perm & GNUNET_DISK_PERM_USER_EXEC)
139 if (perm & GNUNET_DISK_PERM_GROUP_READ)
141 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
143 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
145 if (perm & GNUNET_DISK_PERM_OTHER_READ)
147 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
149 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
158 * Iterate over all files in the given directory and
159 * accumulate their size.
161 * @param cls closure of type "struct GetFileSizeData"
162 * @param fn current filename we are looking at
163 * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
166 getSizeRec (void *cls, const char *fn)
168 struct GetFileSizeData *gfsd = cls;
177 if (0 != STAT64 (fn, &buf))
179 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
180 return GNUNET_SYSERR;
183 if (0 != STAT (fn, &buf))
185 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
186 return GNUNET_SYSERR;
189 if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
192 return GNUNET_SYSERR;
194 if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
195 gfsd->total += buf.st_size;
196 if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
197 ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
199 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
200 return GNUNET_SYSERR;
207 * Checks whether a handle is invalid
209 * @param h handle to check
210 * @return GNUNET_YES if invalid, GNUNET_NO if valid
213 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
216 return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
218 return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
223 * Get the size of an open file.
225 * @param fh open file handle
226 * @param size where to write size of the file
227 * @return GNUNET_OK on success, GNUNET_SYSERR on error
230 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
236 b = GetFileSizeEx (fh->h, &li);
239 SetErrnoFromWinError (GetLastError ());
240 return GNUNET_SYSERR;
242 *size = (OFF_T) li.QuadPart;
246 if (0 != FSTAT (fh->fd, &sbuf))
247 return GNUNET_SYSERR;
248 *size = sbuf.st_size;
255 * Move the read/write pointer in a file
257 * @param h handle of an open file
258 * @param offset position to move to
259 * @param whence specification to which position the offset parameter relates to
260 * @return the new position on success, GNUNET_SYSERR otherwise
263 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
264 enum GNUNET_DISK_Seek whence)
269 return GNUNET_SYSERR;
274 LARGE_INTEGER new_pos;
277 static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
278 [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
280 li.QuadPart = offset;
282 b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
285 SetErrnoFromWinError (GetLastError ());
286 return GNUNET_SYSERR;
288 return (OFF_T) new_pos.QuadPart;
290 static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
291 [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
294 return lseek (h->fd, offset, t[whence]);
300 * Get the size of the file (or directory) of the given file (in
303 * @param filename name of the file or directory
304 * @param size set to the size of the file (or,
305 * in the case of directories, the sum
306 * of all sizes of files in the directory)
307 * @param includeSymLinks should symbolic links be
309 * @param singleFileMode GNUNET_YES to only get size of one file
310 * and return GNUNET_SYSERR for directories.
311 * @return GNUNET_SYSERR on error, GNUNET_OK on success
314 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
315 int includeSymLinks, int singleFileMode)
317 struct GetFileSizeData gfsd;
320 GNUNET_assert (size != NULL);
322 gfsd.include_sym_links = includeSymLinks;
323 gfsd.single_file_mode = singleFileMode;
324 ret = getSizeRec (&gfsd, filename);
331 * Obtain some unique identifiers for the given file
332 * that can be used to identify it in the local system.
333 * This function is used between GNUnet processes to
334 * quickly check if two files with the same absolute path
335 * are actually identical. The two processes represent
336 * the same peer but may communicate over the network
337 * (and the file may be on an NFS volume). This function
338 * may not be supported on all operating systems.
340 * @param filename name of the file
341 * @param dev set to the device ID
342 * @param ino set to the inode ID
343 * @return GNUNET_OK on success
346 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
353 if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
355 *dev = (uint64_t) fbuf.f_fsid;
356 *ino = (uint64_t) sbuf.st_ino;
363 if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
365 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
366 ((uint64_t) fbuf.f_fsid.val[1]);
367 *ino = (uint64_t) sbuf.st_ino;
371 // FIXME NILS: test this
372 struct GNUNET_DISK_FileHandle *fh;
373 BY_HANDLE_FILE_INFORMATION info;
376 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
378 return GNUNET_SYSERR;
379 succ = GetFileInformationByHandle (fh->h, &info);
380 GNUNET_DISK_file_close (fh);
383 *dev = info.dwVolumeSerialNumber;
384 *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
388 return GNUNET_SYSERR;
391 return GNUNET_SYSERR;
396 * Create the name for a temporary file or directory from a template.
398 * @param t template (without XXXXX or "/tmp/")
399 * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
402 mktemp_name (const char *t)
408 if ((t[0] != '/') && (t[0] != '\\')
410 && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
414 /* FIXME: This uses system codepage on W32, not UTF-8 */
415 tmpdir = getenv ("TMPDIR");
417 tmpdir = getenv ("TMP");
419 tmpdir = getenv ("TEMP");
422 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
426 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
429 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
430 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
445 * Create an (empty) temporary directory on disk. If the given name is not
446 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
447 * 6 random characters will be appended to the name to create a unique
450 * @param t component to use for the name;
451 * does NOT contain "XXXXXX" or "/tmp/".
452 * @return NULL on error, otherwise name of fresh
453 * file on disk in directory for temporary files
456 GNUNET_DISK_mkdtemp (const char *t)
460 fn = mktemp_name (t);
461 if (fn != mkdtemp (fn))
463 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
472 * Create an (empty) temporary file on disk. If the given name is not
473 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
474 * 6 random characters will be appended to the name to create a unique
477 * @param t component to use for the name;
478 * does NOT contain "XXXXXX" or "/tmp/".
479 * @return NULL on error, otherwise name of fresh
480 * file on disk in directory for temporary files
483 GNUNET_DISK_mktemp (const char *t)
488 fn = mktemp_name (t);
489 if (-1 == (fd = mkstemp (fn)))
491 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
496 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
502 * Get the number of blocks that are left on the partition that
503 * contains the given file (for normal users).
505 * @param part a file on the partition to check
506 * @return -1 on errors, otherwise the number of free blocks
509 GNUNET_DISK_get_blocks_available (const char *part)
514 if (0 != statvfs (part, &buf))
516 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
524 wchar_t wpath[MAX_PATH + 1];
527 path = GNUNET_STRINGS_filename_expand (part);
530 /* "part" was in UTF-8, and so is "path" */
531 if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
537 wcsncpy (szDrive, wpath, 3);
539 if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
541 LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
542 "GetDiskFreeSpace", szDrive, GetLastError ());
550 if (0 != statfs (part, &s))
552 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
561 * Test if "fil" is a directory.
562 * Will not print an error message if the directory
563 * does not exist. Will log errors if GNUNET_SYSERR is
564 * returned (i.e., a file exists with the same name).
566 * @param fil filename to test
567 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
571 GNUNET_DISK_directory_test (const char *fil)
573 struct stat filestat;
576 ret = STAT (fil, &filestat);
581 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
582 return GNUNET_SYSERR;
586 if (!S_ISDIR (filestat.st_mode))
588 if (ACCESS (fil, R_OK | X_OK) < 0)
590 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
591 return GNUNET_SYSERR;
598 * Check that fil corresponds to a filename
599 * (of a file that exists and that is not a directory).
601 * @param fil filename to check
602 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
603 * else (will print an error message in that case, too).
606 GNUNET_DISK_file_test (const char *fil)
608 struct stat filestat;
612 rdir = GNUNET_STRINGS_filename_expand (fil);
614 return GNUNET_SYSERR;
616 ret = STAT (rdir, &filestat);
621 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
623 return GNUNET_SYSERR;
628 if (!S_ISREG (filestat.st_mode))
633 if (ACCESS (rdir, R_OK) < 0)
635 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
637 return GNUNET_SYSERR;
645 * Implementation of "mkdir -p"
646 * @param dir the directory to create
647 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
650 GNUNET_DISK_directory_create (const char *dir)
657 rdir = GNUNET_STRINGS_filename_expand (dir);
659 return GNUNET_SYSERR;
663 pos = 1; /* skip heading '/' */
665 /* Local or Network path? */
666 if (strncmp (rdir, "\\\\", 2) == 0)
671 if (rdir[pos] == '\\')
681 pos = 3; /* strlen("C:\\") */
686 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
689 ret = GNUNET_DISK_directory_test (rdir);
690 if (ret == GNUNET_SYSERR)
693 return GNUNET_SYSERR;
695 if (ret == GNUNET_NO)
698 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
700 wchar_t wrdir[MAX_PATH + 1];
701 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
702 ret = !CreateDirectoryW (wrdir, NULL);
706 if ((ret != 0) && (errno != EEXIST))
708 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
710 return GNUNET_SYSERR;
713 rdir[pos] = DIR_SEPARATOR;
723 * Create the directory structure for storing
726 * @param filename name of a file in the directory
727 * @returns GNUNET_OK on success,
728 * GNUNET_SYSERR on failure,
729 * GNUNET_NO if the directory
730 * exists but is not writeable for us
733 GNUNET_DISK_directory_create_for_file (const char *filename)
739 rdir = GNUNET_STRINGS_filename_expand (filename);
741 return GNUNET_SYSERR;
743 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
746 ret = GNUNET_DISK_directory_create (rdir);
747 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
755 * Read the contents of a binary file into a buffer.
756 * @param h handle to an open file
757 * @param result the buffer to write the result to
758 * @param len the maximum number of bytes to read
759 * @return the number of bytes read on success, GNUNET_SYSERR on failure
762 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
768 return GNUNET_SYSERR;
774 if (h->type != GNUNET_PIPE)
776 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
778 SetErrnoFromWinError (GetLastError ());
779 return GNUNET_SYSERR;
784 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
786 if (GetLastError () != ERROR_IO_PENDING)
788 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
789 SetErrnoFromWinError (GetLastError ());
790 return GNUNET_SYSERR;
792 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
793 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
795 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
799 return read (h->fd, result, len);
805 * Read the contents of a binary file into a buffer.
806 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
807 * when no data can be read).
809 * @param h handle to an open file
810 * @param result the buffer to write the result to
811 * @param len the maximum number of bytes to read
812 * @return the number of bytes read on success, GNUNET_SYSERR on failure
815 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
816 void *result, size_t len)
821 return GNUNET_SYSERR;
827 if (h->type != GNUNET_PIPE)
829 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
831 SetErrnoFromWinError (GetLastError ());
832 return GNUNET_SYSERR;
837 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
839 if (GetLastError () != ERROR_IO_PENDING)
841 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
842 SetErrnoFromWinError (GetLastError ());
843 return GNUNET_SYSERR;
847 LOG (GNUNET_ERROR_TYPE_DEBUG,
848 "ReadFile() queued a read, cancelling\n");
851 return GNUNET_SYSERR;
854 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
861 /* set to non-blocking, read, then set back */
862 flags = fcntl (h->fd, F_GETFL);
863 if (0 == (flags & O_NONBLOCK))
864 fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
865 ret = read (h->fd, result, len);
866 if (0 == (flags & O_NONBLOCK))
867 fcntl (h->fd, F_SETFL, flags);
874 * Read the contents of a binary file into a buffer.
876 * @param fn file name
877 * @param result the buffer to write the result to
878 * @param len the maximum number of bytes to read
879 * @return number of bytes read, GNUNET_SYSERR on failure
882 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
884 struct GNUNET_DISK_FileHandle *fh;
887 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
889 return GNUNET_SYSERR;
890 ret = GNUNET_DISK_file_read (fh, result, len);
891 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
898 * Write a buffer to a file.
899 * @param h handle to open file
900 * @param buffer the data to write
901 * @param n number of bytes to write
902 * @return number of bytes written on success, GNUNET_SYSERR on error
905 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
906 const void *buffer, size_t n)
911 return GNUNET_SYSERR;
917 if (h->type != GNUNET_PIPE)
919 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
921 SetErrnoFromWinError (GetLastError ());
922 return GNUNET_SYSERR;
927 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
928 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
930 if (GetLastError () != ERROR_IO_PENDING)
932 SetErrnoFromWinError (GetLastError ());
933 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
935 return GNUNET_SYSERR;
937 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
938 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
940 SetErrnoFromWinError (GetLastError ());
941 LOG (GNUNET_ERROR_TYPE_DEBUG,
942 "Error getting overlapped result while writing to pipe: %u\n",
944 return GNUNET_SYSERR;
950 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
952 LOG (GNUNET_ERROR_TYPE_DEBUG,
953 "Error getting control overlapped result while writing to pipe: %u\n",
958 LOG (GNUNET_ERROR_TYPE_DEBUG,
959 "Wrote %u bytes (ovr says %u), picking the greatest\n",
963 if (bytesWritten == 0)
967 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
969 return GNUNET_SYSERR;
972 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
976 return write (h->fd, buffer, n);
982 * Write a buffer to a file, blocking, if necessary.
983 * @param h handle to open file
984 * @param buffer the data to write
985 * @param n number of bytes to write
986 * @return number of bytes written on success, GNUNET_SYSERR on error
989 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
990 const void *buffer, size_t n)
995 return GNUNET_SYSERR;
1000 /* We do a non-overlapped write, which is as blocking as it gets */
1001 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1002 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1004 SetErrnoFromWinError (GetLastError ());
1005 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1007 return GNUNET_SYSERR;
1009 if (bytesWritten == 0 && n > 0)
1011 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1012 WaitForSingleObject (h->h, INFINITE);
1013 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1015 SetErrnoFromWinError (GetLastError ());
1016 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1018 return GNUNET_SYSERR;
1021 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1022 return bytesWritten;
1027 /* set to blocking, write, then set back */
1028 flags = fcntl (h->fd, F_GETFL);
1029 if (0 != (flags & O_NONBLOCK))
1030 fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1031 ret = write (h->fd, buffer, n);
1032 if (0 == (flags & O_NONBLOCK))
1033 fcntl (h->fd, F_SETFL, flags);
1040 * Write a buffer to a file. If the file is longer than the
1041 * number of bytes that will be written, it will be truncated.
1043 * @param fn file name
1044 * @param buffer the data to write
1045 * @param n number of bytes to write
1046 * @param mode file permissions
1047 * @return number of bytes written on success, GNUNET_SYSERR on error
1050 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1051 enum GNUNET_DISK_AccessPermissions mode)
1053 struct GNUNET_DISK_FileHandle *fh;
1056 fh = GNUNET_DISK_file_open (fn,
1057 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1058 | GNUNET_DISK_OPEN_CREATE, mode);
1060 return GNUNET_SYSERR;
1061 ret = GNUNET_DISK_file_write (fh, buffer, n);
1062 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1068 * Scan a directory for files.
1070 * @param dirName the name of the directory
1071 * @param callback the method to call for each file,
1072 * can be NULL, in that case, we only count
1073 * @param callback_cls closure for callback
1074 * @return the number of files found, GNUNET_SYSERR on error or
1075 * ieration aborted by callback returning GNUNET_SYSERR
1078 GNUNET_DISK_directory_scan (const char *dirName,
1079 GNUNET_FileNameCallback callback,
1083 struct dirent *finfo;
1088 unsigned int name_len;
1089 unsigned int n_size;
1091 GNUNET_assert (dirName != NULL);
1092 dname = GNUNET_STRINGS_filename_expand (dirName);
1094 return GNUNET_SYSERR;
1095 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1096 dname[strlen (dname) - 1] = '\0';
1097 if (0 != STAT (dname, &istat))
1099 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1100 GNUNET_free (dname);
1101 return GNUNET_SYSERR;
1103 if (!S_ISDIR (istat.st_mode))
1105 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1107 GNUNET_free (dname);
1108 return GNUNET_SYSERR;
1111 dinfo = OPENDIR (dname);
1112 if ((errno == EACCES) || (dinfo == NULL))
1114 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1117 GNUNET_free (dname);
1118 return GNUNET_SYSERR;
1121 n_size = strlen (dname) + name_len + 2;
1122 name = GNUNET_malloc (n_size);
1123 while ((finfo = READDIR (dinfo)) != NULL)
1125 if ((0 == strcmp (finfo->d_name, ".")) ||
1126 (0 == strcmp (finfo->d_name, "..")))
1128 if (callback != NULL)
1130 if (name_len < strlen (finfo->d_name))
1133 name_len = strlen (finfo->d_name);
1134 n_size = strlen (dname) + name_len + 2;
1135 name = GNUNET_malloc (n_size);
1137 /* dname can end in "/" only if dname == "/";
1138 * if dname does not end in "/", we need to add
1139 * a "/" (otherwise, we must not!) */
1140 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1141 (strcmp (dname, DIR_SEPARATOR_STR) ==
1142 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1143 if (GNUNET_OK != callback (callback_cls, name))
1147 GNUNET_free (dname);
1148 return GNUNET_SYSERR;
1155 GNUNET_free (dname);
1161 * Opaque handle used for iterating over a directory.
1163 struct GNUNET_DISK_DirectoryIterator
1167 * Function to call on directory entries.
1169 GNUNET_DISK_DirectoryIteratorCallback callback;
1172 * Closure for callback.
1177 * Reference to directory.
1187 * Next filename to process.
1194 enum GNUNET_SCHEDULER_Priority priority;
1200 * Task used by the directory iterator.
1203 directory_iterator_task (void *cls,
1204 const struct GNUNET_SCHEDULER_TaskContext *tc)
1206 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1209 name = iter->next_name;
1210 GNUNET_assert (name != NULL);
1211 iter->next_name = NULL;
1212 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1218 * This function must be called during the DiskIteratorCallback
1219 * (exactly once) to schedule the task to process the next
1220 * filename in the directory (if there is one).
1222 * @param iter opaque handle for the iterator
1223 * @param can set to GNUNET_YES to terminate the iteration early
1224 * @return GNUNET_YES if iteration will continue,
1225 * GNUNET_NO if this was the last entry (and iteration is complete),
1226 * GNUNET_SYSERR if abort was YES
1229 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1232 struct dirent *finfo;
1234 GNUNET_assert (iter->next_name == NULL);
1235 if (can == GNUNET_YES)
1237 CLOSEDIR (iter->directory);
1238 GNUNET_free (iter->dirname);
1240 return GNUNET_SYSERR;
1242 while (NULL != (finfo = READDIR (iter->directory)))
1244 if ((0 == strcmp (finfo->d_name, ".")) ||
1245 (0 == strcmp (finfo->d_name, "..")))
1247 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1248 DIR_SEPARATOR_STR, finfo->d_name);
1253 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1256 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1263 * Scan a directory for files using the scheduler to run a task for
1264 * each entry. The name of the directory must be expanded first (!).
1265 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1266 * may provide a simpler API.
1268 * @param prio priority to use
1269 * @param dirName the name of the directory
1270 * @param callback the method to call for each file
1271 * @param callback_cls closure for callback
1272 * @return GNUNET_YES if directory is not empty and 'callback'
1273 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1276 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1277 const char *dirName,
1278 GNUNET_DISK_DirectoryIteratorCallback
1279 callback, void *callback_cls)
1281 struct GNUNET_DISK_DirectoryIterator *di;
1283 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1284 di->callback = callback;
1285 di->callback_cls = callback_cls;
1286 di->directory = OPENDIR (dirName);
1287 if (di->directory == NULL)
1290 callback (callback_cls, NULL, NULL, NULL);
1291 return GNUNET_SYSERR;
1293 di->dirname = GNUNET_strdup (dirName);
1294 di->priority = prio;
1295 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1300 * Function that removes the given directory by calling
1301 * "GNUNET_DISK_directory_remove".
1303 * @param unused not used
1304 * @param fn directory to remove
1308 remove_helper (void *unused, const char *fn)
1310 (void) GNUNET_DISK_directory_remove (fn);
1316 * Remove all files in a directory (rm -rf). Call with
1320 * @param fileName the file to remove
1321 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1324 GNUNET_DISK_directory_remove (const char *fileName)
1328 if (0 != LSTAT (fileName, &istat))
1329 return GNUNET_NO; /* file may not exist... */
1330 CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR);
1331 if (UNLINK (fileName) == 0)
1333 if ((errno != EISDIR) &&
1334 /* EISDIR is not sufficient in all cases, e.g.
1335 * sticky /tmp directory may result in EPERM on BSD.
1336 * So we also explicitly check "isDirectory" */
1337 (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
1339 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1340 return GNUNET_SYSERR;
1342 if (GNUNET_SYSERR ==
1343 GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL))
1344 return GNUNET_SYSERR;
1345 if (0 != RMDIR (fileName))
1347 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1348 return GNUNET_SYSERR;
1357 * @param src file to copy
1358 * @param dst destination file name
1359 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1362 GNUNET_DISK_file_copy (const char *src, const char *dst)
1368 struct GNUNET_DISK_FileHandle *in;
1369 struct GNUNET_DISK_FileHandle *out;
1371 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1372 return GNUNET_SYSERR;
1374 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1375 GNUNET_DISK_PERM_NONE);
1377 return GNUNET_SYSERR;
1379 GNUNET_DISK_file_open (dst,
1380 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1381 GNUNET_DISK_OPEN_FAILIFEXISTS,
1382 GNUNET_DISK_PERM_USER_READ |
1383 GNUNET_DISK_PERM_USER_WRITE |
1384 GNUNET_DISK_PERM_GROUP_READ |
1385 GNUNET_DISK_PERM_GROUP_WRITE);
1388 GNUNET_DISK_file_close (in);
1389 return GNUNET_SYSERR;
1391 buf = GNUNET_malloc (COPY_BLK_SIZE);
1394 len = COPY_BLK_SIZE;
1395 if (len > size - pos)
1397 if (len != GNUNET_DISK_file_read (in, buf, len))
1399 if (len != GNUNET_DISK_file_write (out, buf, len))
1404 GNUNET_DISK_file_close (in);
1405 GNUNET_DISK_file_close (out);
1409 GNUNET_DISK_file_close (in);
1410 GNUNET_DISK_file_close (out);
1411 return GNUNET_SYSERR;
1416 * @brief Removes special characters as ':' from a filename.
1417 * @param fn the filename to canonicalize
1420 GNUNET_DISK_filename_canonicalize (char *fn)
1430 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1431 c == '<' || c == '>' || c == '|')
1443 * @brief Change owner of a file
1445 * @param filename name of file to change the owner of
1446 * @param user name of the new owner
1447 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1450 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1455 pws = getpwnam (user);
1458 LOG (GNUNET_ERROR_TYPE_ERROR,
1459 _("Cannot obtain information about user `%s': %s\n"), user,
1461 return GNUNET_SYSERR;
1463 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1464 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1471 * Lock a part of a file
1472 * @param fh file handle
1473 * @param lockStart absolute position from where to lock
1474 * @param lockEnd absolute position until where to lock
1475 * @param excl GNUNET_YES for an exclusive lock
1476 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1479 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1480 OFF_T lockEnd, int excl)
1485 return GNUNET_SYSERR;
1491 memset (&fl, 0, sizeof (struct flock));
1492 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1493 fl.l_whence = SEEK_SET;
1494 fl.l_start = lockStart;
1497 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1500 OFF_T diff = lockEnd - lockStart;
1501 DWORD diff_low, diff_high;
1502 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1503 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1505 memset (&o, 0, sizeof (OVERLAPPED));
1506 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1507 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1510 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1511 0, diff_low, diff_high, &o))
1513 SetErrnoFromWinError (GetLastError ());
1514 return GNUNET_SYSERR;
1523 * Unlock a part of a file
1524 * @param fh file handle
1525 * @param unlockStart absolute position from where to unlock
1526 * @param unlockEnd absolute position until where to unlock
1527 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1530 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1536 return GNUNET_SYSERR;
1542 memset (&fl, 0, sizeof (struct flock));
1543 fl.l_type = F_UNLCK;
1544 fl.l_whence = SEEK_SET;
1545 fl.l_start = unlockStart;
1546 fl.l_len = unlockEnd;
1548 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1551 OFF_T diff = unlockEnd - unlockStart;
1552 DWORD diff_low, diff_high;
1553 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1554 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1556 memset (&o, 0, sizeof (OVERLAPPED));
1557 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1558 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1560 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1562 SetErrnoFromWinError (GetLastError ());
1563 return GNUNET_SYSERR;
1572 * Open a file. Note that the access permissions will only be
1573 * used if a new file is created and if the underlying operating
1574 * system supports the given permissions.
1576 * @param fn file name to be opened
1577 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1578 * @param perm permissions for the newly created file, use
1579 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1580 * call (because of flags)
1581 * @return IO handle on success, NULL on error
1583 struct GNUNET_DISK_FileHandle *
1584 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1585 enum GNUNET_DISK_AccessPermissions perm)
1588 struct GNUNET_DISK_FileHandle *ret;
1594 wchar_t wexpfn[MAX_PATH + 1];
1601 expfn = GNUNET_STRINGS_filename_expand (fn);
1606 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1607 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1608 else if (flags & GNUNET_DISK_OPEN_READ)
1610 else if (flags & GNUNET_DISK_OPEN_WRITE)
1615 GNUNET_free (expfn);
1618 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1619 oflags |= (O_CREAT | O_EXCL);
1620 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1622 if (flags & GNUNET_DISK_OPEN_APPEND)
1624 if (flags & GNUNET_DISK_OPEN_CREATE)
1626 (void) GNUNET_DISK_directory_create_for_file (expfn);
1628 mode = translate_unix_perms (perm);
1631 fd = open (expfn, oflags | O_LARGEFILE, mode);
1634 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1635 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1637 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1638 GNUNET_free (expfn);
1645 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1646 access = FILE_READ_DATA | FILE_WRITE_DATA;
1647 else if (flags & GNUNET_DISK_OPEN_READ)
1648 access = FILE_READ_DATA;
1649 else if (flags & GNUNET_DISK_OPEN_WRITE)
1650 access = FILE_WRITE_DATA;
1652 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1656 else if (flags & GNUNET_DISK_OPEN_CREATE)
1658 (void) GNUNET_DISK_directory_create_for_file (expfn);
1659 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1660 disp = CREATE_ALWAYS;
1664 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1666 disp = TRUNCATE_EXISTING;
1670 disp = OPEN_EXISTING;
1673 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1674 h = CreateFileW (wexpfn, access,
1675 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1676 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1678 h = INVALID_HANDLE_VALUE;
1679 if (h == INVALID_HANDLE_VALUE)
1681 SetErrnoFromWinError (GetLastError ());
1682 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1683 GNUNET_free (expfn);
1687 if (flags & GNUNET_DISK_OPEN_APPEND)
1688 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1690 SetErrnoFromWinError (GetLastError ());
1691 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1693 GNUNET_free (expfn);
1698 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1701 ret->type = GNUNET_DISK_FILE;
1705 GNUNET_free (expfn);
1711 * Close an open file
1712 * @param h file handle
1713 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1716 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1721 return GNUNET_SYSERR;
1725 if (!CloseHandle (h->h))
1727 SetErrnoFromWinError (GetLastError ());
1728 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1729 GNUNET_free (h->oOverlapRead);
1730 GNUNET_free (h->oOverlapWrite);
1732 return GNUNET_SYSERR;
1735 if (close (h->fd) != 0)
1737 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1739 return GNUNET_SYSERR;
1748 * Construct full path to a file inside of the private
1749 * directory used by GNUnet. Also creates the corresponding
1750 * directory. If the resulting name is supposed to be
1751 * a directory, end the last argument in '/' (or pass
1752 * DIR_SEPARATOR_STR as the last argument before NULL).
1754 * @param cfg configuration to use (determines HOME)
1755 * @param serviceName name of the service
1756 * @param ... is NULL-terminated list of
1757 * path components to append to the
1758 * private directory name.
1759 * @return the constructed filename
1762 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1763 const char *serviceName, ...)
1769 unsigned int needed;
1772 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1776 LOG (GNUNET_ERROR_TYPE_WARNING,
1777 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1781 needed = strlen (pfx) + 2;
1782 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1784 va_start (ap, serviceName);
1787 c = va_arg (ap, const char *);
1791 needed += strlen (c);
1792 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1796 ret = GNUNET_malloc (needed);
1799 va_start (ap, serviceName);
1802 c = va_arg (ap, const char *);
1806 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1807 strcat (ret, DIR_SEPARATOR_STR);
1811 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1812 (void) GNUNET_DISK_directory_create_for_file (ret);
1814 (void) GNUNET_DISK_directory_create (ret);
1820 * Handle for a memory-mapping operation.
1822 struct GNUNET_DISK_MapHandle
1825 * Address where the map is in memory.
1831 * Underlying OS handle.
1836 * Number of bytes mapped.
1844 #define MAP_FAILED ((void *) -1)
1848 * Map a file into memory
1850 * @param h open file handle
1851 * @param m handle to the new mapping
1852 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1853 * @param len size of the mapping
1854 * @return pointer to the mapped memory region, NULL on failure
1857 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1858 struct GNUNET_DISK_MapHandle **m,
1859 enum GNUNET_DISK_MapType access, size_t len)
1868 DWORD mapAccess, protect;
1870 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1871 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1873 protect = PAGE_READWRITE;
1874 mapAccess = FILE_MAP_ALL_ACCESS;
1876 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1878 protect = PAGE_READONLY;
1879 mapAccess = FILE_MAP_READ;
1881 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1883 protect = PAGE_READWRITE;
1884 mapAccess = FILE_MAP_WRITE;
1892 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1893 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1894 if ((*m)->h == INVALID_HANDLE_VALUE)
1896 SetErrnoFromWinError (GetLastError ());
1901 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1904 SetErrnoFromWinError (GetLastError ());
1905 CloseHandle ((*m)->h);
1914 if (access & GNUNET_DISK_MAP_TYPE_READ)
1916 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1918 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1919 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1920 GNUNET_assert (NULL != (*m)->addr);
1921 if (MAP_FAILED == (*m)->addr)
1933 * @param h mapping handle
1934 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1937 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1944 return GNUNET_SYSERR;
1948 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
1949 if (ret != GNUNET_OK)
1950 SetErrnoFromWinError (GetLastError ());
1951 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
1953 ret = GNUNET_SYSERR;
1954 SetErrnoFromWinError (GetLastError ());
1957 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1965 * Write file changes to disk
1966 * @param h handle to an open file
1967 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1970 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1975 return GNUNET_SYSERR;
1981 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1982 if (ret != GNUNET_OK)
1983 SetErrnoFromWinError (GetLastError ());
1985 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
1986 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1988 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1994 /* Copyright Bob Byrnes <byrnes <at> curl.com>
1995 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
1997 /* Create a pipe, and return handles to the read and write ends,
1998 just like CreatePipe, but ensure that the write end permits
1999 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2000 this is supported. This access is needed by NtQueryInformationFile,
2001 which is used to implement select and nonblocking writes.
2002 Note that the return value is either NO_ERROR or GetLastError,
2003 unlike CreatePipe, which returns a bool for success or failure. */
2005 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2006 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2007 DWORD dwReadMode, DWORD dwWriteMode)
2009 /* Default to error. */
2010 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2012 HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
2014 /* Ensure that there is enough pipe buffer space for atomic writes. */
2015 if (psize < PIPE_BUF)
2018 char pipename[MAX_PATH];
2020 /* Retry CreateNamedPipe as long as the pipe name is in use.
2021 * Retrying will probably never be necessary, but we want
2022 * to be as robust as possible. */
2025 static volatile LONG pipe_unique_id;
2027 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2028 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2029 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2031 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2032 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2033 * access, on versions of win32 earlier than WinXP SP2.
2034 * CreatePipe also stupidly creates a full duplex pipe, which is
2035 * a waste, since only a single direction is actually used.
2036 * It's important to only allow a single instance, to ensure that
2037 * the pipe was not created earlier by some other process, even if
2038 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
2039 * because that is only available for Win2k SP2 and WinXP. */
2040 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2041 psize, /* output buffer size */
2042 psize, /* input buffer size */
2043 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2045 if (read_pipe != INVALID_HANDLE_VALUE)
2047 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2051 DWORD err = GetLastError ();
2055 case ERROR_PIPE_BUSY:
2056 /* The pipe is already open with compatible parameters.
2057 * Pick a new name and retry. */
2058 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2060 case ERROR_ACCESS_DENIED:
2061 /* The pipe is already open with incompatible parameters.
2062 * Pick a new name and retry. */
2063 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2065 case ERROR_CALL_NOT_IMPLEMENTED:
2066 /* We are on an older Win9x platform without named pipes.
2067 * Return an anonymous pipe as the best approximation. */
2068 LOG (GNUNET_ERROR_TYPE_DEBUG,
2069 "CreateNamedPipe not implemented, resorting to "
2070 "CreatePipe: size = %lu\n", psize);
2071 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2073 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2078 err = GetLastError ();
2079 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2082 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2087 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2089 /* Open the named pipe for writing.
2090 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2091 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2092 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2093 0); /* handle to template file */
2095 if (write_pipe == INVALID_HANDLE_VALUE)
2098 DWORD err = GetLastError ();
2100 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2101 CloseHandle (read_pipe);
2104 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2106 *read_pipe_ptr = read_pipe;
2107 *write_pipe_ptr = write_pipe;
2114 * Creates an interprocess channel
2116 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2117 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2118 * @param inherit_read inherit the parent processes stdin (only for windows)
2119 * @param inherit_write inherit the parent processes stdout (only for windows)
2120 * @return handle to the new pipe, NULL on error
2122 struct GNUNET_DISK_PipeHandle *
2123 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2134 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2138 return GNUNET_DISK_pipe_from_fd (blocking_read,
2142 struct GNUNET_DISK_PipeHandle *p;
2143 struct GNUNET_DISK_FileHandle *fds;
2148 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2149 2 * sizeof (struct GNUNET_DISK_FileHandle));
2150 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2154 /* All pipes are overlapped. If you want them to block - just
2155 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2158 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2159 FILE_FLAG_OVERLAPPED,
2160 FILE_FLAG_OVERLAPPED);
2164 SetErrnoFromWinError (GetLastError ());
2167 if (!DuplicateHandle
2168 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2169 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2171 SetErrnoFromWinError (GetLastError ());
2172 CloseHandle (p->fd[0]->h);
2173 CloseHandle (p->fd[1]->h);
2177 CloseHandle (p->fd[0]->h);
2178 p->fd[0]->h = tmp_handle;
2180 if (!DuplicateHandle
2181 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2182 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2184 SetErrnoFromWinError (GetLastError ());
2185 CloseHandle (p->fd[0]->h);
2186 CloseHandle (p->fd[1]->h);
2190 CloseHandle (p->fd[1]->h);
2191 p->fd[1]->h = tmp_handle;
2193 p->fd[0]->type = GNUNET_PIPE;
2194 p->fd[1]->type = GNUNET_PIPE;
2196 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2197 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2198 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2199 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2201 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2202 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2204 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2205 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2213 * Creates a pipe object from a couple of file descriptors.
2214 * Useful for wrapping existing pipe FDs.
2216 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2217 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2218 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2220 * @return handle to the new pipe, NULL on error
2222 struct GNUNET_DISK_PipeHandle *
2223 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2225 struct GNUNET_DISK_PipeHandle *p;
2226 struct GNUNET_DISK_FileHandle *fds;
2228 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2229 2 * sizeof (struct GNUNET_DISK_FileHandle));
2230 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2236 int eno = 0; /* make gcc happy */
2238 p->fd[0]->fd = fd[0];
2239 p->fd[1]->fd = fd[1];
2245 flags = fcntl (fd[0], F_GETFL);
2246 flags |= O_NONBLOCK;
2247 if (0 > fcntl (fd[0], F_SETFL, flags))
2253 flags = fcntl (fd[0], F_GETFD);
2254 flags |= FD_CLOEXEC;
2255 if (0 > fcntl (fd[0], F_SETFD, flags))
2264 if (!blocking_write)
2266 flags = fcntl (fd[1], F_GETFL);
2267 flags |= O_NONBLOCK;
2268 if (0 > fcntl (fd[1], F_SETFL, flags))
2274 flags = fcntl (fd[1], F_GETFD);
2275 flags |= FD_CLOEXEC;
2276 if (0 > fcntl (fd[1], F_SETFD, flags))
2285 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2286 if (p->fd[0]->fd >= 0)
2287 GNUNET_break (0 == close (p->fd[0]->fd));
2288 if (p->fd[1]->fd >= 0)
2289 GNUNET_break (0 == close (p->fd[1]->fd));
2296 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2298 p->fd[0]->h = INVALID_HANDLE_VALUE;
2300 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2302 p->fd[1]->h = INVALID_HANDLE_VALUE;
2304 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2306 p->fd[0]->type = GNUNET_PIPE;
2307 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2308 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2309 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2310 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2313 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2315 p->fd[1]->type = GNUNET_PIPE;
2316 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2317 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2318 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2319 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2327 * Closes an interprocess channel
2329 * @param p pipe to close
2330 * @param end which end of the pipe to close
2331 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2334 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2335 enum GNUNET_DISK_PipeEnd end)
2337 int ret = GNUNET_OK;
2341 if (end == GNUNET_DISK_PIPE_END_READ)
2343 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2345 if (!CloseHandle (p->fd[0]->h))
2347 SetErrnoFromWinError (GetLastError ());
2348 ret = GNUNET_SYSERR;
2350 GNUNET_free (p->fd[0]->oOverlapRead);
2351 GNUNET_free (p->fd[0]->oOverlapWrite);
2352 p->fd[0]->h = INVALID_HANDLE_VALUE;
2355 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2357 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2359 if (!CloseHandle (p->fd[1]->h))
2361 SetErrnoFromWinError (GetLastError ());
2362 ret = GNUNET_SYSERR;
2364 GNUNET_free (p->fd[1]->oOverlapRead);
2365 GNUNET_free (p->fd[1]->oOverlapWrite);
2366 p->fd[1]->h = INVALID_HANDLE_VALUE;
2372 if (end == GNUNET_DISK_PIPE_END_READ)
2374 if (0 != close (p->fd[0]->fd))
2376 ret = GNUNET_SYSERR;
2381 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2383 if (0 != close (p->fd[1]->fd))
2385 ret = GNUNET_SYSERR;
2397 * Closes an interprocess channel
2399 * @param p pipe to close
2400 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2403 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2405 int ret = GNUNET_OK;
2409 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2411 if (!CloseHandle (p->fd[0]->h))
2413 SetErrnoFromWinError (GetLastError ());
2414 ret = GNUNET_SYSERR;
2416 GNUNET_free (p->fd[0]->oOverlapRead);
2417 GNUNET_free (p->fd[0]->oOverlapWrite);
2419 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2421 if (!CloseHandle (p->fd[1]->h))
2423 SetErrnoFromWinError (GetLastError ());
2424 ret = GNUNET_SYSERR;
2426 GNUNET_free (p->fd[1]->oOverlapRead);
2427 GNUNET_free (p->fd[1]->oOverlapWrite);
2432 if (p->fd[0]->fd != -1)
2434 if (0 != close (p->fd[0]->fd))
2436 ret = GNUNET_SYSERR;
2441 if (p->fd[1]->fd != -1)
2443 if (0 != close (p->fd[1]->fd))
2445 ret = GNUNET_SYSERR;
2457 * Get the handle to a particular pipe end
2460 * @param n end to access
2461 * @return handle for the respective end
2463 const struct GNUNET_DISK_FileHandle *
2464 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2465 enum GNUNET_DISK_PipeEnd n)
2469 case GNUNET_DISK_PIPE_END_READ:
2470 case GNUNET_DISK_PIPE_END_WRITE:
2480 * Retrieve OS file handle
2482 * @param fh GNUnet file descriptor
2483 * @param dst destination buffer
2484 * @param dst_len length of dst
2485 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2488 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2489 void *dst, size_t dst_len)
2492 if (dst_len < sizeof (HANDLE))
2493 return GNUNET_SYSERR;
2494 *((HANDLE *) dst) = fh->h;
2496 if (dst_len < sizeof (int))
2497 return GNUNET_SYSERR;
2498 *((int *) dst) = fh->fd;