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[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
278 li.QuadPart = offset;
280 b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
283 SetErrnoFromWinError (GetLastError ());
284 return GNUNET_SYSERR;
286 return (OFF_T) new_pos.QuadPart;
288 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
290 return lseek (h->fd, offset, t[whence]);
296 * Get the size of the file (or directory) of the given file (in
299 * @param filename name of the file or directory
300 * @param size set to the size of the file (or,
301 * in the case of directories, the sum
302 * of all sizes of files in the directory)
303 * @param includeSymLinks should symbolic links be
305 * @param singleFileMode GNUNET_YES to only get size of one file
306 * and return GNUNET_SYSERR for directories.
307 * @return GNUNET_SYSERR on error, GNUNET_OK on success
310 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
311 int includeSymLinks, int singleFileMode)
313 struct GetFileSizeData gfsd;
316 GNUNET_assert (size != NULL);
318 gfsd.include_sym_links = includeSymLinks;
319 gfsd.single_file_mode = singleFileMode;
320 ret = getSizeRec (&gfsd, filename);
327 * Obtain some unique identifiers for the given file
328 * that can be used to identify it in the local system.
329 * This function is used between GNUnet processes to
330 * quickly check if two files with the same absolute path
331 * are actually identical. The two processes represent
332 * the same peer but may communicate over the network
333 * (and the file may be on an NFS volume). This function
334 * may not be supported on all operating systems.
336 * @param filename name of the file
337 * @param dev set to the device ID
338 * @param ino set to the inode ID
339 * @return GNUNET_OK on success
342 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
349 if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
351 *dev = (uint64_t) fbuf.f_fsid;
352 *ino = (uint64_t) sbuf.st_ino;
359 if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
361 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
362 ((uint64_t) fbuf.f_fsid.val[1]);
363 *ino = (uint64_t) sbuf.st_ino;
367 // FIXME NILS: test this
368 struct GNUNET_DISK_FileHandle *fh;
369 BY_HANDLE_FILE_INFORMATION info;
372 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
374 return GNUNET_SYSERR;
375 succ = GetFileInformationByHandle (fh->h, &info);
376 GNUNET_DISK_file_close (fh);
379 *dev = info.dwVolumeSerialNumber;
380 *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
384 return GNUNET_SYSERR;
387 return GNUNET_SYSERR;
392 * Create the name for a temporary file or directory from a template.
394 * @param t template (without XXXXX or "/tmp/")
395 * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
398 mktemp_name (const char *t)
404 if ((t[0] != '/') && (t[0] != '\\')
406 && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
410 /* FIXME: This uses system codepage on W32, not UTF-8 */
411 tmpdir = getenv ("TMPDIR");
413 tmpdir = getenv ("TMP");
415 tmpdir = getenv ("TEMP");
418 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
422 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
425 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
426 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
447 tfn = GNUNET_strdup (fn);
448 random_fn = _mktemp (tfn);
449 if (NULL == random_fn)
454 /* FIXME: assume fn to be UTF-8-encoded and do the right thing */
455 if (0 == CreateDirectoryA (tfn, NULL))
457 DWORD error = GetLastError ();
459 if (ERROR_ALREADY_EXISTS == error)
471 * Create an (empty) temporary directory on disk. If the given name is not
472 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
473 * 6 random characters will be appended to the name to create a unique
476 * @param t component to use for the name;
477 * does NOT contain "XXXXXX" or "/tmp/".
478 * @return NULL on error, otherwise name of fresh
479 * file on disk in directory for temporary files
482 GNUNET_DISK_mkdtemp (const char *t)
486 fn = mktemp_name (t);
487 if (fn != mkdtemp (fn))
489 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
498 * Create an (empty) temporary file on disk. If the given name is not
499 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
500 * 6 random characters will be appended to the name to create a unique
503 * @param t component to use for the name;
504 * does NOT contain "XXXXXX" or "/tmp/".
505 * @return NULL on error, otherwise name of fresh
506 * file on disk in directory for temporary files
509 GNUNET_DISK_mktemp (const char *t)
514 fn = mktemp_name (t);
515 if (-1 == (fd = mkstemp (fn)))
517 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
522 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
528 * Get the number of blocks that are left on the partition that
529 * contains the given file (for normal users).
531 * @param part a file on the partition to check
532 * @return -1 on errors, otherwise the number of free blocks
535 GNUNET_DISK_get_blocks_available (const char *part)
540 if (0 != statvfs (part, &buf))
542 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
550 wchar_t wpath[MAX_PATH + 1];
553 path = GNUNET_STRINGS_filename_expand (part);
556 /* "part" was in UTF-8, and so is "path" */
557 if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
563 wcsncpy (szDrive, wpath, 3);
565 if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
567 LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
568 "GetDiskFreeSpace", szDrive, GetLastError ());
576 if (0 != statfs (part, &s))
578 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
587 * Test if "fil" is a directory.
588 * Will not print an error message if the directory
589 * does not exist. Will log errors if GNUNET_SYSERR is
590 * returned (i.e., a file exists with the same name).
592 * @param fil filename to test
593 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
597 GNUNET_DISK_directory_test (const char *fil)
599 struct stat filestat;
602 ret = STAT (fil, &filestat);
607 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
608 return GNUNET_SYSERR;
612 if (!S_ISDIR (filestat.st_mode))
614 if (ACCESS (fil, R_OK | X_OK) < 0)
616 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
617 return GNUNET_SYSERR;
624 * Check that fil corresponds to a filename
625 * (of a file that exists and that is not a directory).
627 * @param fil filename to check
628 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
629 * else (will print an error message in that case, too).
632 GNUNET_DISK_file_test (const char *fil)
634 struct stat filestat;
638 rdir = GNUNET_STRINGS_filename_expand (fil);
640 return GNUNET_SYSERR;
642 ret = STAT (rdir, &filestat);
647 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
649 return GNUNET_SYSERR;
654 if (!S_ISREG (filestat.st_mode))
659 if (ACCESS (rdir, F_OK) < 0)
661 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
663 return GNUNET_SYSERR;
671 * Implementation of "mkdir -p"
672 * @param dir the directory to create
673 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
676 GNUNET_DISK_directory_create (const char *dir)
684 rdir = GNUNET_STRINGS_filename_expand (dir);
686 return GNUNET_SYSERR;
690 pos = 1; /* skip heading '/' */
692 /* Local or Network path? */
693 if (strncmp (rdir, "\\\\", 2) == 0)
698 if (rdir[pos] == '\\')
708 pos = 3; /* strlen("C:\\") */
711 /* Check which low level directories already exist */
713 rdir[len] = DIR_SEPARATOR;
716 if (DIR_SEPARATOR == rdir[pos2])
719 ret = GNUNET_DISK_directory_test (rdir);
720 if (GNUNET_SYSERR == ret)
723 return GNUNET_SYSERR;
725 rdir[pos2] = DIR_SEPARATOR;
726 if (GNUNET_YES == ret)
737 /* Start creating directories */
740 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
743 ret = GNUNET_DISK_directory_test (rdir);
744 if (ret == GNUNET_SYSERR)
747 return GNUNET_SYSERR;
749 if (ret == GNUNET_NO)
752 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
754 wchar_t wrdir[MAX_PATH + 1];
755 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
756 ret = !CreateDirectoryW (wrdir, NULL);
760 if ((ret != 0) && (errno != EEXIST))
762 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
764 return GNUNET_SYSERR;
767 rdir[pos] = DIR_SEPARATOR;
777 * Create the directory structure for storing
780 * @param filename name of a file in the directory
781 * @returns GNUNET_OK on success,
782 * GNUNET_SYSERR on failure,
783 * GNUNET_NO if the directory
784 * exists but is not writeable for us
787 GNUNET_DISK_directory_create_for_file (const char *filename)
793 rdir = GNUNET_STRINGS_filename_expand (filename);
795 return GNUNET_SYSERR;
797 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
800 ret = GNUNET_DISK_directory_create (rdir);
801 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
809 * Read the contents of a binary file into a buffer.
810 * @param h handle to an open file
811 * @param result the buffer to write the result to
812 * @param len the maximum number of bytes to read
813 * @return the number of bytes read on success, GNUNET_SYSERR on failure
816 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
822 return GNUNET_SYSERR;
828 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
830 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
832 SetErrnoFromWinError (GetLastError ());
833 return GNUNET_SYSERR;
838 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
840 if (GetLastError () != ERROR_IO_PENDING)
842 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
843 SetErrnoFromWinError (GetLastError ());
844 return GNUNET_SYSERR;
846 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
847 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
849 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
853 return read (h->fd, result, len);
859 * Read the contents of a binary file into a buffer.
860 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
861 * when no data can be read).
863 * @param h handle to an open file
864 * @param result the buffer to write the result to
865 * @param len the maximum number of bytes to read
866 * @return the number of bytes read on success, GNUNET_SYSERR on failure
869 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
876 return GNUNET_SYSERR;
882 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
884 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
886 SetErrnoFromWinError (GetLastError ());
887 return GNUNET_SYSERR;
892 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
894 if (GetLastError () != ERROR_IO_PENDING)
896 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
897 SetErrnoFromWinError (GetLastError ());
898 return GNUNET_SYSERR;
902 LOG (GNUNET_ERROR_TYPE_DEBUG,
903 "ReadFile() queued a read, cancelling\n");
906 return GNUNET_SYSERR;
909 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
916 /* set to non-blocking, read, then set back */
917 flags = fcntl (h->fd, F_GETFL);
918 if (0 == (flags & O_NONBLOCK))
919 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
920 ret = read (h->fd, result, len);
921 if (0 == (flags & O_NONBLOCK))
924 (void) fcntl (h->fd, F_SETFL, flags);
933 * Read the contents of a binary file into a buffer.
935 * @param fn file name
936 * @param result the buffer to write the result to
937 * @param len the maximum number of bytes to read
938 * @return number of bytes read, GNUNET_SYSERR on failure
941 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
943 struct GNUNET_DISK_FileHandle *fh;
946 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
948 return GNUNET_SYSERR;
949 ret = GNUNET_DISK_file_read (fh, result, len);
950 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
957 * Write a buffer to a file.
958 * @param h handle to open file
959 * @param buffer the data to write
960 * @param n number of bytes to write
961 * @return number of bytes written on success, GNUNET_SYSERR on error
964 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
965 const void *buffer, size_t n)
970 return GNUNET_SYSERR;
976 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
978 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
980 SetErrnoFromWinError (GetLastError ());
981 return GNUNET_SYSERR;
986 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
987 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
989 if (GetLastError () != ERROR_IO_PENDING)
991 SetErrnoFromWinError (GetLastError ());
992 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
994 return GNUNET_SYSERR;
996 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
997 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
999 SetErrnoFromWinError (GetLastError ());
1000 LOG (GNUNET_ERROR_TYPE_DEBUG,
1001 "Error getting overlapped result while writing to pipe: %u\n",
1003 return GNUNET_SYSERR;
1009 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1011 LOG (GNUNET_ERROR_TYPE_DEBUG,
1012 "Error getting control overlapped result while writing to pipe: %u\n",
1017 LOG (GNUNET_ERROR_TYPE_DEBUG,
1018 "Wrote %u bytes (ovr says %u), picking the greatest\n",
1022 if (bytesWritten == 0)
1026 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
1028 return GNUNET_SYSERR;
1031 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1033 return bytesWritten;
1035 return write (h->fd, buffer, n);
1041 * Write a buffer to a file, blocking, if necessary.
1042 * @param h handle to open file
1043 * @param buffer the data to write
1044 * @param n number of bytes to write
1045 * @return number of bytes written on success, GNUNET_SYSERR on error
1048 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1049 const void *buffer, size_t n)
1054 return GNUNET_SYSERR;
1059 /* We do a non-overlapped write, which is as blocking as it gets */
1060 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1061 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1063 SetErrnoFromWinError (GetLastError ());
1064 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1066 return GNUNET_SYSERR;
1068 if (bytesWritten == 0 && n > 0)
1070 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1071 WaitForSingleObject (h->h, INFINITE);
1072 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1074 SetErrnoFromWinError (GetLastError ());
1075 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1077 return GNUNET_SYSERR;
1080 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1081 return bytesWritten;
1086 /* set to blocking, write, then set back */
1087 flags = fcntl (h->fd, F_GETFL);
1088 if (0 != (flags & O_NONBLOCK))
1089 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1090 ret = write (h->fd, buffer, n);
1091 if (0 == (flags & O_NONBLOCK))
1092 (void) fcntl (h->fd, F_SETFL, flags);
1099 * Write a buffer to a file. If the file is longer than the
1100 * number of bytes that will be written, it will be truncated.
1102 * @param fn file name
1103 * @param buffer the data to write
1104 * @param n number of bytes to write
1105 * @param mode file permissions
1106 * @return number of bytes written on success, GNUNET_SYSERR on error
1109 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1110 enum GNUNET_DISK_AccessPermissions mode)
1112 struct GNUNET_DISK_FileHandle *fh;
1115 fh = GNUNET_DISK_file_open (fn,
1116 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1117 | GNUNET_DISK_OPEN_CREATE, mode);
1119 return GNUNET_SYSERR;
1120 ret = GNUNET_DISK_file_write (fh, buffer, n);
1121 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1127 * Scan a directory for files.
1129 * @param dirName the name of the directory
1130 * @param callback the method to call for each file,
1131 * can be NULL, in that case, we only count
1132 * @param callback_cls closure for callback
1133 * @return the number of files found, GNUNET_SYSERR on error or
1134 * ieration aborted by callback returning GNUNET_SYSERR
1137 GNUNET_DISK_directory_scan (const char *dirName,
1138 GNUNET_FileNameCallback callback,
1142 struct dirent *finfo;
1147 unsigned int name_len;
1148 unsigned int n_size;
1150 GNUNET_assert (dirName != NULL);
1151 dname = GNUNET_STRINGS_filename_expand (dirName);
1153 return GNUNET_SYSERR;
1154 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1155 dname[strlen (dname) - 1] = '\0';
1156 if (0 != STAT (dname, &istat))
1158 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1159 GNUNET_free (dname);
1160 return GNUNET_SYSERR;
1162 if (!S_ISDIR (istat.st_mode))
1164 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1166 GNUNET_free (dname);
1167 return GNUNET_SYSERR;
1170 dinfo = OPENDIR (dname);
1171 if ((errno == EACCES) || (dinfo == NULL))
1173 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1176 GNUNET_free (dname);
1177 return GNUNET_SYSERR;
1180 n_size = strlen (dname) + name_len + 2;
1181 name = GNUNET_malloc (n_size);
1182 while ((finfo = READDIR (dinfo)) != NULL)
1184 if ((0 == strcmp (finfo->d_name, ".")) ||
1185 (0 == strcmp (finfo->d_name, "..")))
1187 if (callback != NULL)
1189 if (name_len < strlen (finfo->d_name))
1192 name_len = strlen (finfo->d_name);
1193 n_size = strlen (dname) + name_len + 2;
1194 name = GNUNET_malloc (n_size);
1196 /* dname can end in "/" only if dname == "/";
1197 * if dname does not end in "/", we need to add
1198 * a "/" (otherwise, we must not!) */
1199 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1200 (strcmp (dname, DIR_SEPARATOR_STR) ==
1201 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1202 if (GNUNET_OK != callback (callback_cls, name))
1206 GNUNET_free (dname);
1207 return GNUNET_SYSERR;
1214 GNUNET_free (dname);
1220 * Opaque handle used for iterating over a directory.
1222 struct GNUNET_DISK_DirectoryIterator
1226 * Function to call on directory entries.
1228 GNUNET_DISK_DirectoryIteratorCallback callback;
1231 * Closure for callback.
1236 * Reference to directory.
1246 * Next filename to process.
1253 enum GNUNET_SCHEDULER_Priority priority;
1259 * Task used by the directory iterator.
1262 directory_iterator_task (void *cls,
1263 const struct GNUNET_SCHEDULER_TaskContext *tc)
1265 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1268 name = iter->next_name;
1269 GNUNET_assert (name != NULL);
1270 iter->next_name = NULL;
1271 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1277 * This function must be called during the DiskIteratorCallback
1278 * (exactly once) to schedule the task to process the next
1279 * filename in the directory (if there is one).
1281 * @param iter opaque handle for the iterator
1282 * @param can set to GNUNET_YES to terminate the iteration early
1283 * @return GNUNET_YES if iteration will continue,
1284 * GNUNET_NO if this was the last entry (and iteration is complete),
1285 * GNUNET_SYSERR if abort was YES
1288 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1291 struct dirent *finfo;
1293 GNUNET_assert (iter->next_name == NULL);
1294 if (can == GNUNET_YES)
1296 CLOSEDIR (iter->directory);
1297 GNUNET_free (iter->dirname);
1299 return GNUNET_SYSERR;
1301 while (NULL != (finfo = READDIR (iter->directory)))
1303 if ((0 == strcmp (finfo->d_name, ".")) ||
1304 (0 == strcmp (finfo->d_name, "..")))
1306 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1307 DIR_SEPARATOR_STR, finfo->d_name);
1312 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1315 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1322 * Scan a directory for files using the scheduler to run a task for
1323 * each entry. The name of the directory must be expanded first (!).
1324 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1325 * may provide a simpler API.
1327 * @param prio priority to use
1328 * @param dirName the name of the directory
1329 * @param callback the method to call for each file
1330 * @param callback_cls closure for callback
1331 * @return GNUNET_YES if directory is not empty and 'callback'
1332 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1335 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1336 const char *dirName,
1337 GNUNET_DISK_DirectoryIteratorCallback
1338 callback, void *callback_cls)
1340 struct GNUNET_DISK_DirectoryIterator *di;
1342 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1343 di->callback = callback;
1344 di->callback_cls = callback_cls;
1345 di->directory = OPENDIR (dirName);
1346 if (di->directory == NULL)
1349 callback (callback_cls, NULL, NULL, NULL);
1350 return GNUNET_SYSERR;
1352 di->dirname = GNUNET_strdup (dirName);
1353 di->priority = prio;
1354 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1359 * Function that removes the given directory by calling
1360 * "GNUNET_DISK_directory_remove".
1362 * @param unused not used
1363 * @param fn directory to remove
1367 remove_helper (void *unused, const char *fn)
1369 (void) GNUNET_DISK_directory_remove (fn);
1375 * Remove all files in a directory (rm -rf). Call with
1379 * @param filename the file to remove
1380 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1383 GNUNET_DISK_directory_remove (const char *filename)
1387 if (0 != LSTAT (filename, &istat))
1388 return GNUNET_NO; /* file may not exist... */
1389 (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1390 if (UNLINK (filename) == 0)
1392 if ((errno != EISDIR) &&
1393 /* EISDIR is not sufficient in all cases, e.g.
1394 * sticky /tmp directory may result in EPERM on BSD.
1395 * So we also explicitly check "isDirectory" */
1396 (GNUNET_YES != GNUNET_DISK_directory_test (filename)))
1398 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1399 return GNUNET_SYSERR;
1401 if (GNUNET_SYSERR ==
1402 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1403 return GNUNET_SYSERR;
1404 if (0 != RMDIR (filename))
1406 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1407 return GNUNET_SYSERR;
1416 * @param src file to copy
1417 * @param dst destination file name
1418 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1421 GNUNET_DISK_file_copy (const char *src, const char *dst)
1427 struct GNUNET_DISK_FileHandle *in;
1428 struct GNUNET_DISK_FileHandle *out;
1430 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1431 return GNUNET_SYSERR;
1433 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1434 GNUNET_DISK_PERM_NONE);
1436 return GNUNET_SYSERR;
1438 GNUNET_DISK_file_open (dst,
1439 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1440 GNUNET_DISK_OPEN_FAILIFEXISTS,
1441 GNUNET_DISK_PERM_USER_READ |
1442 GNUNET_DISK_PERM_USER_WRITE |
1443 GNUNET_DISK_PERM_GROUP_READ |
1444 GNUNET_DISK_PERM_GROUP_WRITE);
1447 GNUNET_DISK_file_close (in);
1448 return GNUNET_SYSERR;
1450 buf = GNUNET_malloc (COPY_BLK_SIZE);
1453 len = COPY_BLK_SIZE;
1454 if (len > size - pos)
1456 if (len != GNUNET_DISK_file_read (in, buf, len))
1458 if (len != GNUNET_DISK_file_write (out, buf, len))
1463 GNUNET_DISK_file_close (in);
1464 GNUNET_DISK_file_close (out);
1468 GNUNET_DISK_file_close (in);
1469 GNUNET_DISK_file_close (out);
1470 return GNUNET_SYSERR;
1475 * @brief Removes special characters as ':' from a filename.
1476 * @param fn the filename to canonicalize
1479 GNUNET_DISK_filename_canonicalize (char *fn)
1489 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1490 c == '<' || c == '>' || c == '|')
1502 * @brief Change owner of a file
1504 * @param filename name of file to change the owner of
1505 * @param user name of the new owner
1506 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1509 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1514 pws = getpwnam (user);
1517 LOG (GNUNET_ERROR_TYPE_ERROR,
1518 _("Cannot obtain information about user `%s': %s\n"), user,
1520 return GNUNET_SYSERR;
1522 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1523 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1530 * Lock a part of a file
1531 * @param fh file handle
1532 * @param lockStart absolute position from where to lock
1533 * @param lockEnd absolute position until where to lock
1534 * @param excl GNUNET_YES for an exclusive lock
1535 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1538 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1539 OFF_T lockEnd, int excl)
1544 return GNUNET_SYSERR;
1550 memset (&fl, 0, sizeof (struct flock));
1551 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1552 fl.l_whence = SEEK_SET;
1553 fl.l_start = lockStart;
1556 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1559 OFF_T diff = lockEnd - lockStart;
1560 DWORD diff_low, diff_high;
1561 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1562 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1564 memset (&o, 0, sizeof (OVERLAPPED));
1565 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1566 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1569 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1570 0, diff_low, diff_high, &o))
1572 SetErrnoFromWinError (GetLastError ());
1573 return GNUNET_SYSERR;
1582 * Unlock a part of a file
1583 * @param fh file handle
1584 * @param unlockStart absolute position from where to unlock
1585 * @param unlockEnd absolute position until where to unlock
1586 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1589 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1595 return GNUNET_SYSERR;
1601 memset (&fl, 0, sizeof (struct flock));
1602 fl.l_type = F_UNLCK;
1603 fl.l_whence = SEEK_SET;
1604 fl.l_start = unlockStart;
1605 fl.l_len = unlockEnd;
1607 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1610 OFF_T diff = unlockEnd - unlockStart;
1611 DWORD diff_low, diff_high;
1612 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1613 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1615 memset (&o, 0, sizeof (OVERLAPPED));
1616 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1617 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1619 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1621 SetErrnoFromWinError (GetLastError ());
1622 return GNUNET_SYSERR;
1631 * Open a file. Note that the access permissions will only be
1632 * used if a new file is created and if the underlying operating
1633 * system supports the given permissions.
1635 * @param fn file name to be opened
1636 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1637 * @param perm permissions for the newly created file, use
1638 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1639 * call (because of flags)
1640 * @return IO handle on success, NULL on error
1642 struct GNUNET_DISK_FileHandle *
1643 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1644 enum GNUNET_DISK_AccessPermissions perm)
1647 struct GNUNET_DISK_FileHandle *ret;
1653 wchar_t wexpfn[MAX_PATH + 1];
1660 expfn = GNUNET_STRINGS_filename_expand (fn);
1665 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1666 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1667 else if (flags & GNUNET_DISK_OPEN_READ)
1669 else if (flags & GNUNET_DISK_OPEN_WRITE)
1674 GNUNET_free (expfn);
1677 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1678 oflags |= (O_CREAT | O_EXCL);
1679 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1681 if (flags & GNUNET_DISK_OPEN_APPEND)
1683 if (flags & GNUNET_DISK_OPEN_CREATE)
1685 (void) GNUNET_DISK_directory_create_for_file (expfn);
1687 mode = translate_unix_perms (perm);
1690 fd = open (expfn, oflags | O_LARGEFILE, mode);
1693 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1694 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1696 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1697 GNUNET_free (expfn);
1704 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1705 access = FILE_READ_DATA | FILE_WRITE_DATA;
1706 else if (flags & GNUNET_DISK_OPEN_READ)
1707 access = FILE_READ_DATA;
1708 else if (flags & GNUNET_DISK_OPEN_WRITE)
1709 access = FILE_WRITE_DATA;
1711 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1715 else if (flags & GNUNET_DISK_OPEN_CREATE)
1717 (void) GNUNET_DISK_directory_create_for_file (expfn);
1718 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1719 disp = CREATE_ALWAYS;
1723 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1725 disp = TRUNCATE_EXISTING;
1729 disp = OPEN_EXISTING;
1732 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1733 h = CreateFileW (wexpfn, access,
1734 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1735 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1737 h = INVALID_HANDLE_VALUE;
1738 if (h == INVALID_HANDLE_VALUE)
1741 SetErrnoFromWinError (GetLastError ());
1743 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1744 GNUNET_free (expfn);
1749 if (flags & GNUNET_DISK_OPEN_APPEND)
1750 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1752 SetErrnoFromWinError (GetLastError ());
1753 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1755 GNUNET_free (expfn);
1760 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1763 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1767 GNUNET_free (expfn);
1773 * Close an open file
1774 * @param h file handle
1775 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1778 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1783 return GNUNET_SYSERR;
1787 if (!CloseHandle (h->h))
1789 SetErrnoFromWinError (GetLastError ());
1790 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1791 GNUNET_free (h->oOverlapRead);
1792 GNUNET_free (h->oOverlapWrite);
1794 return GNUNET_SYSERR;
1797 if (close (h->fd) != 0)
1799 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1801 return GNUNET_SYSERR;
1810 * Get a handle from a native FD.
1812 * @param fd native file descriptor
1813 * @return file handle corresponding to the descriptor
1815 struct GNUNET_DISK_FileHandle *
1816 GNUNET_DISK_get_handle_from_native (FILE *fd)
1818 struct GNUNET_DISK_FileHandle *fh;
1829 osfh = _get_osfhandle (fno);
1830 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1834 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1837 fh->h = (HANDLE) osfh;
1838 /* Assume it to be a pipe. TODO: use some kind of detection
1839 * function to figure out handle type.
1840 * Note that we can't make it overlapped if it isn't already.
1841 * (ReOpenFile() is only available in 2003/Vista).
1842 * The process that opened this file in the first place (usually a parent
1843 * process, if this is stdin/stdout/stderr) must make it overlapped,
1844 * otherwise we're screwed, as selecting on non-overlapped handle
1847 fh->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
1848 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1849 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1850 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1851 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1861 * Construct full path to a file inside of the private
1862 * directory used by GNUnet. Also creates the corresponding
1863 * directory. If the resulting name is supposed to be
1864 * a directory, end the last argument in '/' (or pass
1865 * DIR_SEPARATOR_STR as the last argument before NULL).
1867 * @param cfg configuration to use (determines HOME)
1868 * @param serviceName name of the service
1869 * @param ... is NULL-terminated list of
1870 * path components to append to the
1871 * private directory name.
1872 * @return the constructed filename
1875 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1876 const char *serviceName, ...)
1882 unsigned int needed;
1885 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1889 LOG (GNUNET_ERROR_TYPE_WARNING,
1890 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1894 needed = strlen (pfx) + 2;
1895 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1897 va_start (ap, serviceName);
1900 c = va_arg (ap, const char *);
1904 needed += strlen (c);
1905 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1909 ret = GNUNET_malloc (needed);
1912 va_start (ap, serviceName);
1915 c = va_arg (ap, const char *);
1919 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1920 strcat (ret, DIR_SEPARATOR_STR);
1924 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1925 (void) GNUNET_DISK_directory_create_for_file (ret);
1927 (void) GNUNET_DISK_directory_create (ret);
1933 * Handle for a memory-mapping operation.
1935 struct GNUNET_DISK_MapHandle
1938 * Address where the map is in memory.
1944 * Underlying OS handle.
1949 * Number of bytes mapped.
1957 #define MAP_FAILED ((void *) -1)
1961 * Map a file into memory
1963 * @param h open file handle
1964 * @param m handle to the new mapping
1965 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1966 * @param len size of the mapping
1967 * @return pointer to the mapped memory region, NULL on failure
1970 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1971 struct GNUNET_DISK_MapHandle **m,
1972 enum GNUNET_DISK_MapType access, size_t len)
1981 DWORD mapAccess, protect;
1983 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1984 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1986 protect = PAGE_READWRITE;
1987 mapAccess = FILE_MAP_ALL_ACCESS;
1989 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1991 protect = PAGE_READONLY;
1992 mapAccess = FILE_MAP_READ;
1994 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1996 protect = PAGE_READWRITE;
1997 mapAccess = FILE_MAP_WRITE;
2005 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2006 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2007 if ((*m)->h == INVALID_HANDLE_VALUE)
2009 SetErrnoFromWinError (GetLastError ());
2014 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2017 SetErrnoFromWinError (GetLastError ());
2018 CloseHandle ((*m)->h);
2027 if (access & GNUNET_DISK_MAP_TYPE_READ)
2029 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2031 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2032 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2033 GNUNET_assert (NULL != (*m)->addr);
2034 if (MAP_FAILED == (*m)->addr)
2046 * @param h mapping handle
2047 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2050 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2057 return GNUNET_SYSERR;
2061 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2062 if (ret != GNUNET_OK)
2063 SetErrnoFromWinError (GetLastError ());
2064 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2066 ret = GNUNET_SYSERR;
2067 SetErrnoFromWinError (GetLastError ());
2070 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2078 * Write file changes to disk
2079 * @param h handle to an open file
2080 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2083 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2088 return GNUNET_SYSERR;
2094 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2095 if (ret != GNUNET_OK)
2096 SetErrnoFromWinError (GetLastError ());
2098 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2099 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2101 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2107 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2108 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2110 /* Create a pipe, and return handles to the read and write ends,
2111 just like CreatePipe, but ensure that the write end permits
2112 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2113 this is supported. This access is needed by NtQueryInformationFile,
2114 which is used to implement select and nonblocking writes.
2115 Note that the return value is either NO_ERROR or GetLastError,
2116 unlike CreatePipe, which returns a bool for success or failure. */
2118 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2119 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2120 DWORD dwReadMode, DWORD dwWriteMode)
2122 /* Default to error. */
2123 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2125 HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
2127 /* Ensure that there is enough pipe buffer space for atomic writes. */
2128 if (psize < PIPE_BUF)
2131 char pipename[MAX_PATH];
2133 /* Retry CreateNamedPipe as long as the pipe name is in use.
2134 * Retrying will probably never be necessary, but we want
2135 * to be as robust as possible. */
2138 static volatile LONG pipe_unique_id;
2140 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2141 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2142 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2144 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2145 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2146 * access, on versions of win32 earlier than WinXP SP2.
2147 * CreatePipe also stupidly creates a full duplex pipe, which is
2148 * a waste, since only a single direction is actually used.
2149 * It's important to only allow a single instance, to ensure that
2150 * the pipe was not created earlier by some other process, even if
2151 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
2152 * because that is only available for Win2k SP2 and WinXP. */
2153 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2154 psize, /* output buffer size */
2155 psize, /* input buffer size */
2156 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2158 if (read_pipe != INVALID_HANDLE_VALUE)
2160 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2164 DWORD err = GetLastError ();
2168 case ERROR_PIPE_BUSY:
2169 /* The pipe is already open with compatible parameters.
2170 * Pick a new name and retry. */
2171 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2173 case ERROR_ACCESS_DENIED:
2174 /* The pipe is already open with incompatible parameters.
2175 * Pick a new name and retry. */
2176 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2178 case ERROR_CALL_NOT_IMPLEMENTED:
2179 /* We are on an older Win9x platform without named pipes.
2180 * Return an anonymous pipe as the best approximation. */
2181 LOG (GNUNET_ERROR_TYPE_DEBUG,
2182 "CreateNamedPipe not implemented, resorting to "
2183 "CreatePipe: size = %lu\n", psize);
2184 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2186 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2191 err = GetLastError ();
2192 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2195 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2200 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2202 /* Open the named pipe for writing.
2203 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2204 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2205 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2206 0); /* handle to template file */
2208 if (write_pipe == INVALID_HANDLE_VALUE)
2211 DWORD err = GetLastError ();
2213 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2214 CloseHandle (read_pipe);
2217 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2219 *read_pipe_ptr = read_pipe;
2220 *write_pipe_ptr = write_pipe;
2227 * Creates an interprocess channel
2229 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2230 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2231 * @param inherit_read inherit the parent processes stdin (only for windows)
2232 * @param inherit_write inherit the parent processes stdout (only for windows)
2233 * @return handle to the new pipe, NULL on error
2235 struct GNUNET_DISK_PipeHandle *
2236 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2247 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2251 return GNUNET_DISK_pipe_from_fd (blocking_read,
2255 struct GNUNET_DISK_PipeHandle *p;
2256 struct GNUNET_DISK_FileHandle *fds;
2261 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2262 2 * sizeof (struct GNUNET_DISK_FileHandle));
2263 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2267 /* All pipes are overlapped. If you want them to block - just
2268 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2271 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2272 FILE_FLAG_OVERLAPPED,
2273 FILE_FLAG_OVERLAPPED);
2277 SetErrnoFromWinError (GetLastError ());
2280 if (!DuplicateHandle
2281 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2282 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2284 SetErrnoFromWinError (GetLastError ());
2285 CloseHandle (p->fd[0]->h);
2286 CloseHandle (p->fd[1]->h);
2290 CloseHandle (p->fd[0]->h);
2291 p->fd[0]->h = tmp_handle;
2293 if (!DuplicateHandle
2294 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2295 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2297 SetErrnoFromWinError (GetLastError ());
2298 CloseHandle (p->fd[0]->h);
2299 CloseHandle (p->fd[1]->h);
2303 CloseHandle (p->fd[1]->h);
2304 p->fd[1]->h = tmp_handle;
2306 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2307 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2309 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2310 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2311 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2312 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2314 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2315 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2317 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2318 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2326 * Creates a pipe object from a couple of file descriptors.
2327 * Useful for wrapping existing pipe FDs.
2329 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2330 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2331 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2333 * @return handle to the new pipe, NULL on error
2335 struct GNUNET_DISK_PipeHandle *
2336 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2338 struct GNUNET_DISK_PipeHandle *p;
2339 struct GNUNET_DISK_FileHandle *fds;
2341 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2342 2 * sizeof (struct GNUNET_DISK_FileHandle));
2343 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2349 int eno = 0; /* make gcc happy */
2351 p->fd[0]->fd = fd[0];
2352 p->fd[1]->fd = fd[1];
2358 flags = fcntl (fd[0], F_GETFL);
2359 flags |= O_NONBLOCK;
2360 if (0 > fcntl (fd[0], F_SETFL, flags))
2366 flags = fcntl (fd[0], F_GETFD);
2367 flags |= FD_CLOEXEC;
2368 if (0 > fcntl (fd[0], F_SETFD, flags))
2377 if (!blocking_write)
2379 flags = fcntl (fd[1], F_GETFL);
2380 flags |= O_NONBLOCK;
2381 if (0 > fcntl (fd[1], F_SETFL, flags))
2387 flags = fcntl (fd[1], F_GETFD);
2388 flags |= FD_CLOEXEC;
2389 if (0 > fcntl (fd[1], F_SETFD, flags))
2398 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2399 if (p->fd[0]->fd >= 0)
2400 GNUNET_break (0 == close (p->fd[0]->fd));
2401 if (p->fd[1]->fd >= 0)
2402 GNUNET_break (0 == close (p->fd[1]->fd));
2409 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2411 p->fd[0]->h = INVALID_HANDLE_VALUE;
2413 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2415 p->fd[1]->h = INVALID_HANDLE_VALUE;
2417 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2419 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2420 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2421 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2422 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2423 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2426 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2428 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2429 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2430 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2431 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2432 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2440 * Closes an interprocess channel
2442 * @param p pipe to close
2443 * @param end which end of the pipe to close
2444 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2447 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2448 enum GNUNET_DISK_PipeEnd end)
2450 int ret = GNUNET_OK;
2454 if (end == GNUNET_DISK_PIPE_END_READ)
2456 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2458 if (!CloseHandle (p->fd[0]->h))
2460 SetErrnoFromWinError (GetLastError ());
2461 ret = GNUNET_SYSERR;
2463 GNUNET_free (p->fd[0]->oOverlapRead);
2464 GNUNET_free (p->fd[0]->oOverlapWrite);
2465 p->fd[0]->h = INVALID_HANDLE_VALUE;
2468 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2470 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2472 if (!CloseHandle (p->fd[1]->h))
2474 SetErrnoFromWinError (GetLastError ());
2475 ret = GNUNET_SYSERR;
2477 GNUNET_free (p->fd[1]->oOverlapRead);
2478 GNUNET_free (p->fd[1]->oOverlapWrite);
2479 p->fd[1]->h = INVALID_HANDLE_VALUE;
2485 if (end == GNUNET_DISK_PIPE_END_READ)
2487 if (0 != close (p->fd[0]->fd))
2489 ret = GNUNET_SYSERR;
2494 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2496 if (0 != close (p->fd[1]->fd))
2498 ret = GNUNET_SYSERR;
2510 * Closes an interprocess channel
2512 * @param p pipe to close
2513 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2516 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2518 int ret = GNUNET_OK;
2522 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2524 if (!CloseHandle (p->fd[0]->h))
2526 SetErrnoFromWinError (GetLastError ());
2527 ret = GNUNET_SYSERR;
2529 GNUNET_free (p->fd[0]->oOverlapRead);
2530 GNUNET_free (p->fd[0]->oOverlapWrite);
2532 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2534 if (!CloseHandle (p->fd[1]->h))
2536 SetErrnoFromWinError (GetLastError ());
2537 ret = GNUNET_SYSERR;
2539 GNUNET_free (p->fd[1]->oOverlapRead);
2540 GNUNET_free (p->fd[1]->oOverlapWrite);
2545 if (p->fd[0]->fd != -1)
2547 if (0 != close (p->fd[0]->fd))
2549 ret = GNUNET_SYSERR;
2554 if (p->fd[1]->fd != -1)
2556 if (0 != close (p->fd[1]->fd))
2558 ret = GNUNET_SYSERR;
2570 * Get the handle to a particular pipe end
2573 * @param n end to access
2574 * @return handle for the respective end
2576 const struct GNUNET_DISK_FileHandle *
2577 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2578 enum GNUNET_DISK_PipeEnd n)
2582 case GNUNET_DISK_PIPE_END_READ:
2583 case GNUNET_DISK_PIPE_END_WRITE:
2593 * Retrieve OS file handle
2595 * @param fh GNUnet file descriptor
2596 * @param dst destination buffer
2597 * @param dst_len length of dst
2598 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2601 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2602 void *dst, size_t dst_len)
2605 if (dst_len < sizeof (HANDLE))
2606 return GNUNET_SYSERR;
2607 *((HANDLE *) dst) = fh->h;
2609 if (dst_len < sizeof (int))
2610 return GNUNET_SYSERR;
2611 *((int *) dst) = fh->fd;