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 and listable. Optionally, also check if the
588 * directory is readable. Will not print an error message if the directory does
589 * not exist. Will log errors if GNUNET_SYSERR is returned (i.e., a file exists
590 * with the same name).
592 * @param fil filename to test
593 * @param is_readable GNUNET_YES to additionally check if "fil" is readable;
594 * GNUNET_NO to disable this check
595 * @return GNUNET_YES if yes, GNUNET_NO if not; GNUNET_SYSERR if it
596 * does not exist or stat'ed
599 GNUNET_DISK_directory_test (const char *fil, int is_readable)
601 struct stat filestat;
604 ret = STAT (fil, &filestat);
608 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
609 return GNUNET_SYSERR;
611 if (!S_ISDIR (filestat.st_mode))
613 LOG (GNUNET_ERROR_TYPE_WARNING,
614 "A file already exits with the same name %s\n", fil);
617 if (GNUNET_YES == is_readable)
618 ret = ACCESS (fil, R_OK | X_OK);
620 ret = ACCESS (fil, X_OK);
623 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
631 * Check that fil corresponds to a filename
632 * (of a file that exists and that is not a directory).
634 * @param fil filename to check
635 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
636 * else (will print an error message in that case, too).
639 GNUNET_DISK_file_test (const char *fil)
641 struct stat filestat;
645 rdir = GNUNET_STRINGS_filename_expand (fil);
647 return GNUNET_SYSERR;
649 ret = STAT (rdir, &filestat);
654 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
656 return GNUNET_SYSERR;
661 if (!S_ISREG (filestat.st_mode))
666 if (ACCESS (rdir, F_OK) < 0)
668 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
670 return GNUNET_SYSERR;
678 * Implementation of "mkdir -p"
679 * @param dir the directory to create
680 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
683 GNUNET_DISK_directory_create (const char *dir)
691 rdir = GNUNET_STRINGS_filename_expand (dir);
693 return GNUNET_SYSERR;
697 pos = 1; /* skip heading '/' */
699 /* Local or Network path? */
700 if (strncmp (rdir, "\\\\", 2) == 0)
705 if (rdir[pos] == '\\')
715 pos = 3; /* strlen("C:\\") */
718 /* Check which low level directories already exist */
720 rdir[len] = DIR_SEPARATOR;
723 if (DIR_SEPARATOR == rdir[pos2])
726 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
727 if (GNUNET_NO == ret)
730 return GNUNET_SYSERR;
732 rdir[pos2] = DIR_SEPARATOR;
733 if (GNUNET_YES == ret)
744 /* Start creating directories */
747 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
750 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
751 if (GNUNET_NO == ret)
754 return GNUNET_SYSERR;
756 if (GNUNET_SYSERR == ret)
759 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
761 wchar_t wrdir[MAX_PATH + 1];
762 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
763 ret = !CreateDirectoryW (wrdir, NULL);
767 if ((ret != 0) && (errno != EEXIST))
769 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
771 return GNUNET_SYSERR;
774 rdir[pos] = DIR_SEPARATOR;
784 * Create the directory structure for storing
787 * @param filename name of a file in the directory
788 * @returns GNUNET_OK on success,
789 * GNUNET_SYSERR on failure,
790 * GNUNET_NO if the directory
791 * exists but is not writeable for us
794 GNUNET_DISK_directory_create_for_file (const char *filename)
800 rdir = GNUNET_STRINGS_filename_expand (filename);
802 return GNUNET_SYSERR;
804 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
807 ret = GNUNET_DISK_directory_create (rdir);
808 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
816 * Read the contents of a binary file into a buffer.
817 * @param h handle to an open file
818 * @param result the buffer to write the result to
819 * @param len the maximum number of bytes to read
820 * @return the number of bytes read on success, GNUNET_SYSERR on failure
823 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
829 return GNUNET_SYSERR;
835 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
837 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
839 SetErrnoFromWinError (GetLastError ());
840 return GNUNET_SYSERR;
845 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
847 if (GetLastError () != ERROR_IO_PENDING)
849 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
850 SetErrnoFromWinError (GetLastError ());
851 return GNUNET_SYSERR;
853 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
854 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
856 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
860 return read (h->fd, result, len);
866 * Read the contents of a binary file into a buffer.
867 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
868 * when no data can be read).
870 * @param h handle to an open file
871 * @param result the buffer to write the result to
872 * @param len the maximum number of bytes to read
873 * @return the number of bytes read on success, GNUNET_SYSERR on failure
876 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
883 return GNUNET_SYSERR;
889 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
891 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
893 SetErrnoFromWinError (GetLastError ());
894 return GNUNET_SYSERR;
899 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
901 if (GetLastError () != ERROR_IO_PENDING)
903 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
904 SetErrnoFromWinError (GetLastError ());
905 return GNUNET_SYSERR;
909 LOG (GNUNET_ERROR_TYPE_DEBUG,
910 "ReadFile() queued a read, cancelling\n");
913 return GNUNET_SYSERR;
916 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
923 /* set to non-blocking, read, then set back */
924 flags = fcntl (h->fd, F_GETFL);
925 if (0 == (flags & O_NONBLOCK))
926 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
927 ret = read (h->fd, result, len);
928 if (0 == (flags & O_NONBLOCK))
931 (void) fcntl (h->fd, F_SETFL, flags);
940 * Read the contents of a binary file into a buffer.
942 * @param fn file name
943 * @param result the buffer to write the result to
944 * @param len the maximum number of bytes to read
945 * @return number of bytes read, GNUNET_SYSERR on failure
948 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
950 struct GNUNET_DISK_FileHandle *fh;
953 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
955 return GNUNET_SYSERR;
956 ret = GNUNET_DISK_file_read (fh, result, len);
957 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
964 * Write a buffer to a file.
965 * @param h handle to open file
966 * @param buffer the data to write
967 * @param n number of bytes to write
968 * @return number of bytes written on success, GNUNET_SYSERR on error
971 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
972 const void *buffer, size_t n)
977 return GNUNET_SYSERR;
983 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
985 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
987 SetErrnoFromWinError (GetLastError ());
988 return GNUNET_SYSERR;
993 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
994 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
996 if (GetLastError () != ERROR_IO_PENDING)
998 SetErrnoFromWinError (GetLastError ());
999 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1001 return GNUNET_SYSERR;
1003 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
1004 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
1006 SetErrnoFromWinError (GetLastError ());
1007 LOG (GNUNET_ERROR_TYPE_DEBUG,
1008 "Error getting overlapped result while writing to pipe: %u\n",
1010 return GNUNET_SYSERR;
1016 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "Error getting control overlapped result while writing to pipe: %u\n",
1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1025 "Wrote %u bytes (ovr says %u), picking the greatest\n",
1029 if (bytesWritten == 0)
1033 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
1035 return GNUNET_SYSERR;
1038 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1040 return bytesWritten;
1042 return write (h->fd, buffer, n);
1048 * Write a buffer to a file, blocking, if necessary.
1049 * @param h handle to open file
1050 * @param buffer the data to write
1051 * @param n number of bytes to write
1052 * @return number of bytes written on success, GNUNET_SYSERR on error
1055 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1056 const void *buffer, size_t n)
1061 return GNUNET_SYSERR;
1066 /* We do a non-overlapped write, which is as blocking as it gets */
1067 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1068 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1070 SetErrnoFromWinError (GetLastError ());
1071 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1073 return GNUNET_SYSERR;
1075 if (bytesWritten == 0 && n > 0)
1077 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1078 WaitForSingleObject (h->h, INFINITE);
1079 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1081 SetErrnoFromWinError (GetLastError ());
1082 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1084 return GNUNET_SYSERR;
1087 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1088 return bytesWritten;
1093 /* set to blocking, write, then set back */
1094 flags = fcntl (h->fd, F_GETFL);
1095 if (0 != (flags & O_NONBLOCK))
1096 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1097 ret = write (h->fd, buffer, n);
1098 if (0 == (flags & O_NONBLOCK))
1099 (void) fcntl (h->fd, F_SETFL, flags);
1106 * Write a buffer to a file. If the file is longer than the
1107 * number of bytes that will be written, it will be truncated.
1109 * @param fn file name
1110 * @param buffer the data to write
1111 * @param n number of bytes to write
1112 * @param mode file permissions
1113 * @return number of bytes written on success, GNUNET_SYSERR on error
1116 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1117 enum GNUNET_DISK_AccessPermissions mode)
1119 struct GNUNET_DISK_FileHandle *fh;
1122 fh = GNUNET_DISK_file_open (fn,
1123 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1124 | GNUNET_DISK_OPEN_CREATE, mode);
1126 return GNUNET_SYSERR;
1127 ret = GNUNET_DISK_file_write (fh, buffer, n);
1128 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1134 * Scan a directory for files.
1136 * @param dirName the name of the directory
1137 * @param callback the method to call for each file,
1138 * can be NULL, in that case, we only count
1139 * @param callback_cls closure for callback
1140 * @return the number of files found, GNUNET_SYSERR on error or
1141 * ieration aborted by callback returning GNUNET_SYSERR
1144 GNUNET_DISK_directory_scan (const char *dirName,
1145 GNUNET_FileNameCallback callback,
1149 struct dirent *finfo;
1154 unsigned int name_len;
1155 unsigned int n_size;
1157 GNUNET_assert (dirName != NULL);
1158 dname = GNUNET_STRINGS_filename_expand (dirName);
1160 return GNUNET_SYSERR;
1161 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1162 dname[strlen (dname) - 1] = '\0';
1163 if (0 != STAT (dname, &istat))
1165 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1166 GNUNET_free (dname);
1167 return GNUNET_SYSERR;
1169 if (!S_ISDIR (istat.st_mode))
1171 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1173 GNUNET_free (dname);
1174 return GNUNET_SYSERR;
1177 dinfo = OPENDIR (dname);
1178 if ((errno == EACCES) || (dinfo == NULL))
1180 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1183 GNUNET_free (dname);
1184 return GNUNET_SYSERR;
1187 n_size = strlen (dname) + name_len + 2;
1188 name = GNUNET_malloc (n_size);
1189 while ((finfo = READDIR (dinfo)) != NULL)
1191 if ((0 == strcmp (finfo->d_name, ".")) ||
1192 (0 == strcmp (finfo->d_name, "..")))
1194 if (callback != NULL)
1196 if (name_len < strlen (finfo->d_name))
1199 name_len = strlen (finfo->d_name);
1200 n_size = strlen (dname) + name_len + 2;
1201 name = GNUNET_malloc (n_size);
1203 /* dname can end in "/" only if dname == "/";
1204 * if dname does not end in "/", we need to add
1205 * a "/" (otherwise, we must not!) */
1206 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1207 (strcmp (dname, DIR_SEPARATOR_STR) ==
1208 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1209 if (GNUNET_OK != callback (callback_cls, name))
1213 GNUNET_free (dname);
1214 return GNUNET_SYSERR;
1221 GNUNET_free (dname);
1227 * Opaque handle used for iterating over a directory.
1229 struct GNUNET_DISK_DirectoryIterator
1233 * Function to call on directory entries.
1235 GNUNET_DISK_DirectoryIteratorCallback callback;
1238 * Closure for callback.
1243 * Reference to directory.
1253 * Next filename to process.
1260 enum GNUNET_SCHEDULER_Priority priority;
1266 * Task used by the directory iterator.
1269 directory_iterator_task (void *cls,
1270 const struct GNUNET_SCHEDULER_TaskContext *tc)
1272 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1275 name = iter->next_name;
1276 GNUNET_assert (name != NULL);
1277 iter->next_name = NULL;
1278 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1284 * This function must be called during the DiskIteratorCallback
1285 * (exactly once) to schedule the task to process the next
1286 * filename in the directory (if there is one).
1288 * @param iter opaque handle for the iterator
1289 * @param can set to GNUNET_YES to terminate the iteration early
1290 * @return GNUNET_YES if iteration will continue,
1291 * GNUNET_NO if this was the last entry (and iteration is complete),
1292 * GNUNET_SYSERR if abort was YES
1295 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1298 struct dirent *finfo;
1300 GNUNET_assert (iter->next_name == NULL);
1301 if (can == GNUNET_YES)
1303 CLOSEDIR (iter->directory);
1304 GNUNET_free (iter->dirname);
1306 return GNUNET_SYSERR;
1308 while (NULL != (finfo = READDIR (iter->directory)))
1310 if ((0 == strcmp (finfo->d_name, ".")) ||
1311 (0 == strcmp (finfo->d_name, "..")))
1313 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1314 DIR_SEPARATOR_STR, finfo->d_name);
1319 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1322 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1329 * Scan a directory for files using the scheduler to run a task for
1330 * each entry. The name of the directory must be expanded first (!).
1331 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1332 * may provide a simpler API.
1334 * @param prio priority to use
1335 * @param dirName the name of the directory
1336 * @param callback the method to call for each file
1337 * @param callback_cls closure for callback
1338 * @return GNUNET_YES if directory is not empty and 'callback'
1339 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1342 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1343 const char *dirName,
1344 GNUNET_DISK_DirectoryIteratorCallback
1345 callback, void *callback_cls)
1347 struct GNUNET_DISK_DirectoryIterator *di;
1349 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1350 di->callback = callback;
1351 di->callback_cls = callback_cls;
1352 di->directory = OPENDIR (dirName);
1353 if (di->directory == NULL)
1356 callback (callback_cls, NULL, NULL, NULL);
1357 return GNUNET_SYSERR;
1359 di->dirname = GNUNET_strdup (dirName);
1360 di->priority = prio;
1361 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1366 * Function that removes the given directory by calling
1367 * "GNUNET_DISK_directory_remove".
1369 * @param unused not used
1370 * @param fn directory to remove
1374 remove_helper (void *unused, const char *fn)
1376 (void) GNUNET_DISK_directory_remove (fn);
1382 * Remove all files in a directory (rm -rf). Call with
1386 * @param filename the file to remove
1387 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1390 GNUNET_DISK_directory_remove (const char *filename)
1394 if (0 != LSTAT (filename, &istat))
1395 return GNUNET_NO; /* file may not exist... */
1396 (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1397 if (UNLINK (filename) == 0)
1399 if ((errno != EISDIR) &&
1400 /* EISDIR is not sufficient in all cases, e.g.
1401 * sticky /tmp directory may result in EPERM on BSD.
1402 * So we also explicitly check "isDirectory" */
1403 (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1405 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1406 return GNUNET_SYSERR;
1408 if (GNUNET_SYSERR ==
1409 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1410 return GNUNET_SYSERR;
1411 if (0 != RMDIR (filename))
1413 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1414 return GNUNET_SYSERR;
1423 * @param src file to copy
1424 * @param dst destination file name
1425 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1428 GNUNET_DISK_file_copy (const char *src, const char *dst)
1434 struct GNUNET_DISK_FileHandle *in;
1435 struct GNUNET_DISK_FileHandle *out;
1437 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1438 return GNUNET_SYSERR;
1440 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1441 GNUNET_DISK_PERM_NONE);
1443 return GNUNET_SYSERR;
1445 GNUNET_DISK_file_open (dst,
1446 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1447 GNUNET_DISK_OPEN_FAILIFEXISTS,
1448 GNUNET_DISK_PERM_USER_READ |
1449 GNUNET_DISK_PERM_USER_WRITE |
1450 GNUNET_DISK_PERM_GROUP_READ |
1451 GNUNET_DISK_PERM_GROUP_WRITE);
1454 GNUNET_DISK_file_close (in);
1455 return GNUNET_SYSERR;
1457 buf = GNUNET_malloc (COPY_BLK_SIZE);
1460 len = COPY_BLK_SIZE;
1461 if (len > size - pos)
1463 if (len != GNUNET_DISK_file_read (in, buf, len))
1465 if (len != GNUNET_DISK_file_write (out, buf, len))
1470 GNUNET_DISK_file_close (in);
1471 GNUNET_DISK_file_close (out);
1475 GNUNET_DISK_file_close (in);
1476 GNUNET_DISK_file_close (out);
1477 return GNUNET_SYSERR;
1482 * @brief Removes special characters as ':' from a filename.
1483 * @param fn the filename to canonicalize
1486 GNUNET_DISK_filename_canonicalize (char *fn)
1496 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1497 c == '<' || c == '>' || c == '|')
1509 * @brief Change owner of a file
1511 * @param filename name of file to change the owner of
1512 * @param user name of the new owner
1513 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1516 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1521 pws = getpwnam (user);
1524 LOG (GNUNET_ERROR_TYPE_ERROR,
1525 _("Cannot obtain information about user `%s': %s\n"), user,
1527 return GNUNET_SYSERR;
1529 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1530 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1537 * Lock a part of a file
1538 * @param fh file handle
1539 * @param lockStart absolute position from where to lock
1540 * @param lockEnd absolute position until where to lock
1541 * @param excl GNUNET_YES for an exclusive lock
1542 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1545 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1546 OFF_T lockEnd, int excl)
1551 return GNUNET_SYSERR;
1557 memset (&fl, 0, sizeof (struct flock));
1558 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1559 fl.l_whence = SEEK_SET;
1560 fl.l_start = lockStart;
1563 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1566 OFF_T diff = lockEnd - lockStart;
1567 DWORD diff_low, diff_high;
1568 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1569 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1571 memset (&o, 0, sizeof (OVERLAPPED));
1572 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1573 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1576 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1577 0, diff_low, diff_high, &o))
1579 SetErrnoFromWinError (GetLastError ());
1580 return GNUNET_SYSERR;
1589 * Unlock a part of a file
1590 * @param fh file handle
1591 * @param unlockStart absolute position from where to unlock
1592 * @param unlockEnd absolute position until where to unlock
1593 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1596 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1602 return GNUNET_SYSERR;
1608 memset (&fl, 0, sizeof (struct flock));
1609 fl.l_type = F_UNLCK;
1610 fl.l_whence = SEEK_SET;
1611 fl.l_start = unlockStart;
1612 fl.l_len = unlockEnd;
1614 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1617 OFF_T diff = unlockEnd - unlockStart;
1618 DWORD diff_low, diff_high;
1619 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1620 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1622 memset (&o, 0, sizeof (OVERLAPPED));
1623 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1624 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1626 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1628 SetErrnoFromWinError (GetLastError ());
1629 return GNUNET_SYSERR;
1638 * Open a file. Note that the access permissions will only be
1639 * used if a new file is created and if the underlying operating
1640 * system supports the given permissions.
1642 * @param fn file name to be opened
1643 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1644 * @param perm permissions for the newly created file, use
1645 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1646 * call (because of flags)
1647 * @return IO handle on success, NULL on error
1649 struct GNUNET_DISK_FileHandle *
1650 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1651 enum GNUNET_DISK_AccessPermissions perm)
1654 struct GNUNET_DISK_FileHandle *ret;
1660 wchar_t wexpfn[MAX_PATH + 1];
1667 expfn = GNUNET_STRINGS_filename_expand (fn);
1672 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1673 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1674 else if (flags & GNUNET_DISK_OPEN_READ)
1676 else if (flags & GNUNET_DISK_OPEN_WRITE)
1681 GNUNET_free (expfn);
1684 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1685 oflags |= (O_CREAT | O_EXCL);
1686 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1688 if (flags & GNUNET_DISK_OPEN_APPEND)
1690 if (flags & GNUNET_DISK_OPEN_CREATE)
1692 (void) GNUNET_DISK_directory_create_for_file (expfn);
1694 mode = translate_unix_perms (perm);
1697 fd = open (expfn, oflags | O_LARGEFILE, mode);
1700 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1701 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1703 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1704 GNUNET_free (expfn);
1711 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1712 access = FILE_READ_DATA | FILE_WRITE_DATA;
1713 else if (flags & GNUNET_DISK_OPEN_READ)
1714 access = FILE_READ_DATA;
1715 else if (flags & GNUNET_DISK_OPEN_WRITE)
1716 access = FILE_WRITE_DATA;
1718 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1722 else if (flags & GNUNET_DISK_OPEN_CREATE)
1724 (void) GNUNET_DISK_directory_create_for_file (expfn);
1725 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1726 disp = CREATE_ALWAYS;
1730 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1732 disp = TRUNCATE_EXISTING;
1736 disp = OPEN_EXISTING;
1739 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1740 h = CreateFileW (wexpfn, access,
1741 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1742 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1744 h = INVALID_HANDLE_VALUE;
1745 if (h == INVALID_HANDLE_VALUE)
1748 SetErrnoFromWinError (GetLastError ());
1750 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1751 GNUNET_free (expfn);
1756 if (flags & GNUNET_DISK_OPEN_APPEND)
1757 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1759 SetErrnoFromWinError (GetLastError ());
1760 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1762 GNUNET_free (expfn);
1767 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1770 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1774 GNUNET_free (expfn);
1780 * Close an open file
1781 * @param h file handle
1782 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1785 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1790 return GNUNET_SYSERR;
1794 if (!CloseHandle (h->h))
1796 SetErrnoFromWinError (GetLastError ());
1797 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1798 GNUNET_free (h->oOverlapRead);
1799 GNUNET_free (h->oOverlapWrite);
1801 return GNUNET_SYSERR;
1804 if (close (h->fd) != 0)
1806 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1808 return GNUNET_SYSERR;
1817 * Get a handle from a native FD.
1819 * @param fd native file descriptor
1820 * @return file handle corresponding to the descriptor
1822 struct GNUNET_DISK_FileHandle *
1823 GNUNET_DISK_get_handle_from_native (FILE *fd)
1825 struct GNUNET_DISK_FileHandle *fh;
1836 osfh = _get_osfhandle (fno);
1837 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1841 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1844 fh->h = (HANDLE) osfh;
1845 /* Assume it to be a pipe. TODO: use some kind of detection
1846 * function to figure out handle type.
1847 * Note that we can't make it overlapped if it isn't already.
1848 * (ReOpenFile() is only available in 2003/Vista).
1849 * The process that opened this file in the first place (usually a parent
1850 * process, if this is stdin/stdout/stderr) must make it overlapped,
1851 * otherwise we're screwed, as selecting on non-overlapped handle
1854 fh->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
1855 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1856 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1857 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1858 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1868 * Construct full path to a file inside of the private
1869 * directory used by GNUnet. Also creates the corresponding
1870 * directory. If the resulting name is supposed to be
1871 * a directory, end the last argument in '/' (or pass
1872 * DIR_SEPARATOR_STR as the last argument before NULL).
1874 * @param cfg configuration to use (determines HOME)
1875 * @param serviceName name of the service
1876 * @param ... is NULL-terminated list of
1877 * path components to append to the
1878 * private directory name.
1879 * @return the constructed filename
1882 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1883 const char *serviceName, ...)
1889 unsigned int needed;
1892 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1896 LOG (GNUNET_ERROR_TYPE_WARNING,
1897 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1901 needed = strlen (pfx) + 2;
1902 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1904 va_start (ap, serviceName);
1907 c = va_arg (ap, const char *);
1911 needed += strlen (c);
1912 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1916 ret = GNUNET_malloc (needed);
1919 va_start (ap, serviceName);
1922 c = va_arg (ap, const char *);
1926 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1927 strcat (ret, DIR_SEPARATOR_STR);
1931 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1932 (void) GNUNET_DISK_directory_create_for_file (ret);
1934 (void) GNUNET_DISK_directory_create (ret);
1940 * Handle for a memory-mapping operation.
1942 struct GNUNET_DISK_MapHandle
1945 * Address where the map is in memory.
1951 * Underlying OS handle.
1956 * Number of bytes mapped.
1964 #define MAP_FAILED ((void *) -1)
1968 * Map a file into memory
1970 * @param h open file handle
1971 * @param m handle to the new mapping
1972 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1973 * @param len size of the mapping
1974 * @return pointer to the mapped memory region, NULL on failure
1977 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1978 struct GNUNET_DISK_MapHandle **m,
1979 enum GNUNET_DISK_MapType access, size_t len)
1988 DWORD mapAccess, protect;
1990 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1991 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1993 protect = PAGE_READWRITE;
1994 mapAccess = FILE_MAP_ALL_ACCESS;
1996 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1998 protect = PAGE_READONLY;
1999 mapAccess = FILE_MAP_READ;
2001 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2003 protect = PAGE_READWRITE;
2004 mapAccess = FILE_MAP_WRITE;
2012 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2013 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2014 if ((*m)->h == INVALID_HANDLE_VALUE)
2016 SetErrnoFromWinError (GetLastError ());
2021 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2024 SetErrnoFromWinError (GetLastError ());
2025 CloseHandle ((*m)->h);
2034 if (access & GNUNET_DISK_MAP_TYPE_READ)
2036 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2038 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2039 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2040 GNUNET_assert (NULL != (*m)->addr);
2041 if (MAP_FAILED == (*m)->addr)
2053 * @param h mapping handle
2054 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2057 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2064 return GNUNET_SYSERR;
2068 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2069 if (ret != GNUNET_OK)
2070 SetErrnoFromWinError (GetLastError ());
2071 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2073 ret = GNUNET_SYSERR;
2074 SetErrnoFromWinError (GetLastError ());
2077 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2085 * Write file changes to disk
2086 * @param h handle to an open file
2087 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2090 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2095 return GNUNET_SYSERR;
2101 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2102 if (ret != GNUNET_OK)
2103 SetErrnoFromWinError (GetLastError ());
2105 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2106 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2108 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2114 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2115 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2117 /* Create a pipe, and return handles to the read and write ends,
2118 just like CreatePipe, but ensure that the write end permits
2119 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2120 this is supported. This access is needed by NtQueryInformationFile,
2121 which is used to implement select and nonblocking writes.
2122 Note that the return value is either NO_ERROR or GetLastError,
2123 unlike CreatePipe, which returns a bool for success or failure. */
2125 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2126 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2127 DWORD dwReadMode, DWORD dwWriteMode)
2129 /* Default to error. */
2130 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2132 HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
2134 /* Ensure that there is enough pipe buffer space for atomic writes. */
2135 if (psize < PIPE_BUF)
2138 char pipename[MAX_PATH];
2140 /* Retry CreateNamedPipe as long as the pipe name is in use.
2141 * Retrying will probably never be necessary, but we want
2142 * to be as robust as possible. */
2145 static volatile LONG pipe_unique_id;
2147 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2148 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2149 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2151 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2152 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2153 * access, on versions of win32 earlier than WinXP SP2.
2154 * CreatePipe also stupidly creates a full duplex pipe, which is
2155 * a waste, since only a single direction is actually used.
2156 * It's important to only allow a single instance, to ensure that
2157 * the pipe was not created earlier by some other process, even if
2158 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
2159 * because that is only available for Win2k SP2 and WinXP. */
2160 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2161 psize, /* output buffer size */
2162 psize, /* input buffer size */
2163 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2165 if (read_pipe != INVALID_HANDLE_VALUE)
2167 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2171 DWORD err = GetLastError ();
2175 case ERROR_PIPE_BUSY:
2176 /* The pipe is already open with compatible parameters.
2177 * Pick a new name and retry. */
2178 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2180 case ERROR_ACCESS_DENIED:
2181 /* The pipe is already open with incompatible parameters.
2182 * Pick a new name and retry. */
2183 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2185 case ERROR_CALL_NOT_IMPLEMENTED:
2186 /* We are on an older Win9x platform without named pipes.
2187 * Return an anonymous pipe as the best approximation. */
2188 LOG (GNUNET_ERROR_TYPE_DEBUG,
2189 "CreateNamedPipe not implemented, resorting to "
2190 "CreatePipe: size = %lu\n", psize);
2191 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2193 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2198 err = GetLastError ();
2199 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2202 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2207 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2209 /* Open the named pipe for writing.
2210 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2211 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2212 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2213 0); /* handle to template file */
2215 if (write_pipe == INVALID_HANDLE_VALUE)
2218 DWORD err = GetLastError ();
2220 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2221 CloseHandle (read_pipe);
2224 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2226 *read_pipe_ptr = read_pipe;
2227 *write_pipe_ptr = write_pipe;
2234 * Creates an interprocess channel
2236 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2237 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2238 * @param inherit_read inherit the parent processes stdin (only for windows)
2239 * @param inherit_write inherit the parent processes stdout (only for windows)
2240 * @return handle to the new pipe, NULL on error
2242 struct GNUNET_DISK_PipeHandle *
2243 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2254 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2258 return GNUNET_DISK_pipe_from_fd (blocking_read,
2262 struct GNUNET_DISK_PipeHandle *p;
2263 struct GNUNET_DISK_FileHandle *fds;
2268 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2269 2 * sizeof (struct GNUNET_DISK_FileHandle));
2270 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2274 /* All pipes are overlapped. If you want them to block - just
2275 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2278 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2279 FILE_FLAG_OVERLAPPED,
2280 FILE_FLAG_OVERLAPPED);
2284 SetErrnoFromWinError (GetLastError ());
2287 if (!DuplicateHandle
2288 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2289 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2291 SetErrnoFromWinError (GetLastError ());
2292 CloseHandle (p->fd[0]->h);
2293 CloseHandle (p->fd[1]->h);
2297 CloseHandle (p->fd[0]->h);
2298 p->fd[0]->h = tmp_handle;
2300 if (!DuplicateHandle
2301 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2302 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2304 SetErrnoFromWinError (GetLastError ());
2305 CloseHandle (p->fd[0]->h);
2306 CloseHandle (p->fd[1]->h);
2310 CloseHandle (p->fd[1]->h);
2311 p->fd[1]->h = tmp_handle;
2313 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2314 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2316 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2317 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2318 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2319 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2321 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2322 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2324 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2325 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2333 * Creates a pipe object from a couple of file descriptors.
2334 * Useful for wrapping existing pipe FDs.
2336 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2337 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2338 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2340 * @return handle to the new pipe, NULL on error
2342 struct GNUNET_DISK_PipeHandle *
2343 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2345 struct GNUNET_DISK_PipeHandle *p;
2346 struct GNUNET_DISK_FileHandle *fds;
2348 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2349 2 * sizeof (struct GNUNET_DISK_FileHandle));
2350 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2356 int eno = 0; /* make gcc happy */
2358 p->fd[0]->fd = fd[0];
2359 p->fd[1]->fd = fd[1];
2365 flags = fcntl (fd[0], F_GETFL);
2366 flags |= O_NONBLOCK;
2367 if (0 > fcntl (fd[0], F_SETFL, flags))
2373 flags = fcntl (fd[0], F_GETFD);
2374 flags |= FD_CLOEXEC;
2375 if (0 > fcntl (fd[0], F_SETFD, flags))
2384 if (!blocking_write)
2386 flags = fcntl (fd[1], F_GETFL);
2387 flags |= O_NONBLOCK;
2388 if (0 > fcntl (fd[1], F_SETFL, flags))
2394 flags = fcntl (fd[1], F_GETFD);
2395 flags |= FD_CLOEXEC;
2396 if (0 > fcntl (fd[1], F_SETFD, flags))
2405 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2406 if (p->fd[0]->fd >= 0)
2407 GNUNET_break (0 == close (p->fd[0]->fd));
2408 if (p->fd[1]->fd >= 0)
2409 GNUNET_break (0 == close (p->fd[1]->fd));
2416 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2418 p->fd[0]->h = INVALID_HANDLE_VALUE;
2420 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2422 p->fd[1]->h = INVALID_HANDLE_VALUE;
2424 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2426 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2427 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2428 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2429 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2430 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2433 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2435 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2436 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2437 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2438 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2439 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2447 * Closes an interprocess channel
2449 * @param p pipe to close
2450 * @param end which end of the pipe to close
2451 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2454 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2455 enum GNUNET_DISK_PipeEnd end)
2457 int ret = GNUNET_OK;
2461 if (end == GNUNET_DISK_PIPE_END_READ)
2463 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2465 if (!CloseHandle (p->fd[0]->h))
2467 SetErrnoFromWinError (GetLastError ());
2468 ret = GNUNET_SYSERR;
2470 GNUNET_free (p->fd[0]->oOverlapRead);
2471 GNUNET_free (p->fd[0]->oOverlapWrite);
2472 p->fd[0]->h = INVALID_HANDLE_VALUE;
2475 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2477 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2479 if (!CloseHandle (p->fd[1]->h))
2481 SetErrnoFromWinError (GetLastError ());
2482 ret = GNUNET_SYSERR;
2484 GNUNET_free (p->fd[1]->oOverlapRead);
2485 GNUNET_free (p->fd[1]->oOverlapWrite);
2486 p->fd[1]->h = INVALID_HANDLE_VALUE;
2492 if (end == GNUNET_DISK_PIPE_END_READ)
2494 if (0 != close (p->fd[0]->fd))
2496 ret = GNUNET_SYSERR;
2501 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2503 if (0 != close (p->fd[1]->fd))
2505 ret = GNUNET_SYSERR;
2517 * Closes an interprocess channel
2519 * @param p pipe to close
2520 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2523 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2525 int ret = GNUNET_OK;
2529 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2531 if (!CloseHandle (p->fd[0]->h))
2533 SetErrnoFromWinError (GetLastError ());
2534 ret = GNUNET_SYSERR;
2536 GNUNET_free (p->fd[0]->oOverlapRead);
2537 GNUNET_free (p->fd[0]->oOverlapWrite);
2539 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2541 if (!CloseHandle (p->fd[1]->h))
2543 SetErrnoFromWinError (GetLastError ());
2544 ret = GNUNET_SYSERR;
2546 GNUNET_free (p->fd[1]->oOverlapRead);
2547 GNUNET_free (p->fd[1]->oOverlapWrite);
2552 if (p->fd[0]->fd != -1)
2554 if (0 != close (p->fd[0]->fd))
2556 ret = GNUNET_SYSERR;
2561 if (p->fd[1]->fd != -1)
2563 if (0 != close (p->fd[1]->fd))
2565 ret = GNUNET_SYSERR;
2577 * Get the handle to a particular pipe end
2580 * @param n end to access
2581 * @return handle for the respective end
2583 const struct GNUNET_DISK_FileHandle *
2584 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2585 enum GNUNET_DISK_PipeEnd n)
2589 case GNUNET_DISK_PIPE_END_READ:
2590 case GNUNET_DISK_PIPE_END_WRITE:
2600 * Retrieve OS file handle
2602 * @param fh GNUnet file descriptor
2603 * @param dst destination buffer
2604 * @param dst_len length of dst
2605 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2608 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2609 void *dst, size_t dst_len)
2612 if (dst_len < sizeof (HANDLE))
2613 return GNUNET_SYSERR;
2614 *((HANDLE *) dst) = fh->h;
2616 if (dst_len < sizeof (int))
2617 return GNUNET_SYSERR;
2618 *((int *) dst) = fh->fd;