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))
449 tfn = GNUNET_strdup (fn);
450 random_fn = _mktemp (tfn);
451 if (NULL == random_fn)
456 /* FIXME: assume fn to be UTF-8-encoded and do the right thing */
457 if (0 == CreateDirectoryA (tfn, NULL))
459 DWORD error = GetLastError ();
461 if (ERROR_ALREADY_EXISTS == error)
473 * Create an (empty) temporary directory on disk. If the given name is not
474 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
475 * 6 random characters will be appended to the name to create a unique
478 * @param t component to use for the name;
479 * does NOT contain "XXXXXX" or "/tmp/".
480 * @return NULL on error, otherwise name of fresh
481 * file on disk in directory for temporary files
484 GNUNET_DISK_mkdtemp (const char *t)
488 fn = mktemp_name (t);
489 if (fn != mkdtemp (fn))
491 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
500 * Move a file out of the way (create a backup) by
501 * renaming it to "orig.NUM~" where NUM is the smallest
502 * number that is not used yet.
504 * @param fil name of the file to back up
507 GNUNET_DISK_file_backup (const char *fil)
513 slen = strlen (fil) + 20;
514 target = GNUNET_malloc (slen);
518 GNUNET_snprintf (target, slen,
522 } while (0 == access (target, F_OK));
523 if (0 != rename (fil, target))
524 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
527 GNUNET_free (target);
532 * Create an (empty) temporary file on disk. If the given name is not
533 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
534 * 6 random characters will be appended to the name to create a unique
537 * @param t component to use for the name;
538 * does NOT contain "XXXXXX" or "/tmp/".
539 * @return NULL on error, otherwise name of fresh
540 * file on disk in directory for temporary files
543 GNUNET_DISK_mktemp (const char *t)
548 fn = mktemp_name (t);
549 if (-1 == (fd = mkstemp (fn)))
551 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
556 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
562 * Get the number of blocks that are left on the partition that
563 * contains the given file (for normal users).
565 * @param part a file on the partition to check
566 * @return -1 on errors, otherwise the number of free blocks
569 GNUNET_DISK_get_blocks_available (const char *part)
574 if (0 != statvfs (part, &buf))
576 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
584 wchar_t wpath[MAX_PATH + 1];
587 path = GNUNET_STRINGS_filename_expand (part);
590 /* "part" was in UTF-8, and so is "path" */
591 if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
597 wcsncpy (szDrive, wpath, 3);
599 if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
601 LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
602 "GetDiskFreeSpace", szDrive, GetLastError ());
610 if (0 != statfs (part, &s))
612 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
621 * Test if "fil" is a directory and listable. Optionally, also check if the
622 * directory is readable. Will not print an error message if the directory does
623 * not exist. Will log errors if GNUNET_SYSERR is returned (i.e., a file exists
624 * with the same name).
626 * @param fil filename to test
627 * @param is_readable GNUNET_YES to additionally check if "fil" is readable;
628 * GNUNET_NO to disable this check
629 * @return GNUNET_YES if yes, GNUNET_NO if not; GNUNET_SYSERR if it
630 * does not exist or stat'ed
633 GNUNET_DISK_directory_test (const char *fil, int is_readable)
635 struct stat filestat;
638 ret = STAT (fil, &filestat);
642 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
643 return GNUNET_SYSERR;
645 if (!S_ISDIR (filestat.st_mode))
647 LOG (GNUNET_ERROR_TYPE_WARNING,
648 "A file already exits with the same name %s\n", fil);
651 if (GNUNET_YES == is_readable)
652 ret = ACCESS (fil, R_OK | X_OK);
654 ret = ACCESS (fil, X_OK);
657 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
665 * Check that fil corresponds to a filename
666 * (of a file that exists and that is not a directory).
668 * @param fil filename to check
669 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
670 * else (will print an error message in that case, too).
673 GNUNET_DISK_file_test (const char *fil)
675 struct stat filestat;
679 rdir = GNUNET_STRINGS_filename_expand (fil);
681 return GNUNET_SYSERR;
683 ret = STAT (rdir, &filestat);
688 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
690 return GNUNET_SYSERR;
695 if (!S_ISREG (filestat.st_mode))
700 if (ACCESS (rdir, F_OK) < 0)
702 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
704 return GNUNET_SYSERR;
712 * Implementation of "mkdir -p"
713 * @param dir the directory to create
714 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
717 GNUNET_DISK_directory_create (const char *dir)
725 rdir = GNUNET_STRINGS_filename_expand (dir);
727 return GNUNET_SYSERR;
731 pos = 1; /* skip heading '/' */
733 /* Local or Network path? */
734 if (strncmp (rdir, "\\\\", 2) == 0)
739 if (rdir[pos] == '\\')
749 pos = 3; /* strlen("C:\\") */
752 /* Check which low level directories already exist */
754 rdir[len] = DIR_SEPARATOR;
757 if (DIR_SEPARATOR == rdir[pos2])
760 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
761 if (GNUNET_NO == ret)
764 return GNUNET_SYSERR;
766 rdir[pos2] = DIR_SEPARATOR;
767 if (GNUNET_YES == ret)
778 /* Start creating directories */
781 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
784 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
785 if (GNUNET_NO == ret)
788 return GNUNET_SYSERR;
790 if (GNUNET_SYSERR == ret)
793 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
795 wchar_t wrdir[MAX_PATH + 1];
796 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
797 ret = !CreateDirectoryW (wrdir, NULL);
801 if ((ret != 0) && (errno != EEXIST))
803 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
805 return GNUNET_SYSERR;
808 rdir[pos] = DIR_SEPARATOR;
818 * Create the directory structure for storing
821 * @param filename name of a file in the directory
822 * @returns GNUNET_OK on success,
823 * GNUNET_SYSERR on failure,
824 * GNUNET_NO if the directory
825 * exists but is not writeable for us
828 GNUNET_DISK_directory_create_for_file (const char *filename)
834 rdir = GNUNET_STRINGS_filename_expand (filename);
836 return GNUNET_SYSERR;
838 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
841 ret = GNUNET_DISK_directory_create (rdir);
842 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
850 * Read the contents of a binary file into a buffer.
851 * @param h handle to an open file
852 * @param result the buffer to write the result to
853 * @param len the maximum number of bytes to read
854 * @return the number of bytes read on success, GNUNET_SYSERR on failure
857 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
863 return GNUNET_SYSERR;
869 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
871 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
873 SetErrnoFromWinError (GetLastError ());
874 return GNUNET_SYSERR;
879 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
881 if (GetLastError () != ERROR_IO_PENDING)
883 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
884 SetErrnoFromWinError (GetLastError ());
885 return GNUNET_SYSERR;
887 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
888 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
890 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
894 return read (h->fd, result, len);
900 * Read the contents of a binary file into a buffer.
901 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
902 * when no data can be read).
904 * @param h handle to an open file
905 * @param result the buffer to write the result to
906 * @param len the maximum number of bytes to read
907 * @return the number of bytes read on success, GNUNET_SYSERR on failure
910 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
917 return GNUNET_SYSERR;
923 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
925 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
927 SetErrnoFromWinError (GetLastError ());
928 return GNUNET_SYSERR;
933 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
935 if (GetLastError () != ERROR_IO_PENDING)
937 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
938 SetErrnoFromWinError (GetLastError ());
939 return GNUNET_SYSERR;
943 LOG (GNUNET_ERROR_TYPE_DEBUG,
944 "ReadFile() queued a read, cancelling\n");
947 return GNUNET_SYSERR;
950 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
957 /* set to non-blocking, read, then set back */
958 flags = fcntl (h->fd, F_GETFL);
959 if (0 == (flags & O_NONBLOCK))
960 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
961 ret = read (h->fd, result, len);
962 if (0 == (flags & O_NONBLOCK))
965 (void) fcntl (h->fd, F_SETFL, flags);
974 * Read the contents of a binary file into a buffer.
976 * @param fn file name
977 * @param result the buffer to write the result to
978 * @param len the maximum number of bytes to read
979 * @return number of bytes read, GNUNET_SYSERR on failure
982 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
984 struct GNUNET_DISK_FileHandle *fh;
987 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
989 return GNUNET_SYSERR;
990 ret = GNUNET_DISK_file_read (fh, result, len);
991 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
998 * Write a buffer to a file.
999 * @param h handle to open file
1000 * @param buffer the data to write
1001 * @param n number of bytes to write
1002 * @return number of bytes written on success, GNUNET_SYSERR on error
1005 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
1006 const void *buffer, size_t n)
1011 return GNUNET_SYSERR;
1017 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
1019 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1021 SetErrnoFromWinError (GetLastError ());
1022 return GNUNET_SYSERR;
1027 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
1028 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
1030 if (GetLastError () != ERROR_IO_PENDING)
1032 SetErrnoFromWinError (GetLastError ());
1033 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1035 return GNUNET_SYSERR;
1037 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
1038 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
1040 SetErrnoFromWinError (GetLastError ());
1041 LOG (GNUNET_ERROR_TYPE_DEBUG,
1042 "Error getting overlapped result while writing to pipe: %u\n",
1044 return GNUNET_SYSERR;
1050 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1052 LOG (GNUNET_ERROR_TYPE_DEBUG,
1053 "Error getting control overlapped result while writing to pipe: %u\n",
1058 LOG (GNUNET_ERROR_TYPE_DEBUG,
1059 "Wrote %u bytes (ovr says %u), picking the greatest\n",
1063 if (bytesWritten == 0)
1067 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
1069 return GNUNET_SYSERR;
1072 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1074 return bytesWritten;
1076 return write (h->fd, buffer, n);
1082 * Write a buffer to a file, blocking, if necessary.
1083 * @param h handle to open file
1084 * @param buffer the data to write
1085 * @param n number of bytes to write
1086 * @return number of bytes written on success, GNUNET_SYSERR on error
1089 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1090 const void *buffer, size_t n)
1095 return GNUNET_SYSERR;
1100 /* We do a non-overlapped write, which is as blocking as it gets */
1101 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1102 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1104 SetErrnoFromWinError (GetLastError ());
1105 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1107 return GNUNET_SYSERR;
1109 if (bytesWritten == 0 && n > 0)
1111 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1112 WaitForSingleObject (h->h, INFINITE);
1113 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1115 SetErrnoFromWinError (GetLastError ());
1116 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1118 return GNUNET_SYSERR;
1121 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1122 return bytesWritten;
1127 /* set to blocking, write, then set back */
1128 flags = fcntl (h->fd, F_GETFL);
1129 if (0 != (flags & O_NONBLOCK))
1130 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1131 ret = write (h->fd, buffer, n);
1132 if (0 == (flags & O_NONBLOCK))
1133 (void) fcntl (h->fd, F_SETFL, flags);
1140 * Write a buffer to a file. If the file is longer than the
1141 * number of bytes that will be written, it will be truncated.
1143 * @param fn file name
1144 * @param buffer the data to write
1145 * @param n number of bytes to write
1146 * @param mode file permissions
1147 * @return number of bytes written on success, GNUNET_SYSERR on error
1150 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1151 enum GNUNET_DISK_AccessPermissions mode)
1153 struct GNUNET_DISK_FileHandle *fh;
1156 fh = GNUNET_DISK_file_open (fn,
1157 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1158 | GNUNET_DISK_OPEN_CREATE, mode);
1160 return GNUNET_SYSERR;
1161 ret = GNUNET_DISK_file_write (fh, buffer, n);
1162 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1168 * Scan a directory for files.
1170 * @param dirName the name of the directory
1171 * @param callback the method to call for each file,
1172 * can be NULL, in that case, we only count
1173 * @param callback_cls closure for callback
1174 * @return the number of files found, GNUNET_SYSERR on error or
1175 * ieration aborted by callback returning GNUNET_SYSERR
1178 GNUNET_DISK_directory_scan (const char *dirName,
1179 GNUNET_FileNameCallback callback,
1183 struct dirent *finfo;
1188 unsigned int name_len;
1189 unsigned int n_size;
1191 GNUNET_assert (dirName != NULL);
1192 dname = GNUNET_STRINGS_filename_expand (dirName);
1194 return GNUNET_SYSERR;
1195 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1196 dname[strlen (dname) - 1] = '\0';
1197 if (0 != STAT (dname, &istat))
1199 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1200 GNUNET_free (dname);
1201 return GNUNET_SYSERR;
1203 if (!S_ISDIR (istat.st_mode))
1205 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1207 GNUNET_free (dname);
1208 return GNUNET_SYSERR;
1211 dinfo = OPENDIR (dname);
1212 if ((errno == EACCES) || (dinfo == NULL))
1214 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1217 GNUNET_free (dname);
1218 return GNUNET_SYSERR;
1221 n_size = strlen (dname) + name_len + 2;
1222 name = GNUNET_malloc (n_size);
1223 while ((finfo = READDIR (dinfo)) != NULL)
1225 if ((0 == strcmp (finfo->d_name, ".")) ||
1226 (0 == strcmp (finfo->d_name, "..")))
1228 if (callback != NULL)
1230 if (name_len < strlen (finfo->d_name))
1233 name_len = strlen (finfo->d_name);
1234 n_size = strlen (dname) + name_len + 2;
1235 name = GNUNET_malloc (n_size);
1237 /* dname can end in "/" only if dname == "/";
1238 * if dname does not end in "/", we need to add
1239 * a "/" (otherwise, we must not!) */
1240 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1241 (strcmp (dname, DIR_SEPARATOR_STR) ==
1242 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1243 if (GNUNET_OK != callback (callback_cls, name))
1247 GNUNET_free (dname);
1248 return GNUNET_SYSERR;
1255 GNUNET_free (dname);
1261 * Opaque handle used for iterating over a directory.
1263 struct GNUNET_DISK_DirectoryIterator
1267 * Function to call on directory entries.
1269 GNUNET_DISK_DirectoryIteratorCallback callback;
1272 * Closure for callback.
1277 * Reference to directory.
1287 * Next filename to process.
1294 enum GNUNET_SCHEDULER_Priority priority;
1300 * Task used by the directory iterator.
1303 directory_iterator_task (void *cls,
1304 const struct GNUNET_SCHEDULER_TaskContext *tc)
1306 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1309 name = iter->next_name;
1310 GNUNET_assert (name != NULL);
1311 iter->next_name = NULL;
1312 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1318 * This function must be called during the DiskIteratorCallback
1319 * (exactly once) to schedule the task to process the next
1320 * filename in the directory (if there is one).
1322 * @param iter opaque handle for the iterator
1323 * @param can set to GNUNET_YES to terminate the iteration early
1324 * @return GNUNET_YES if iteration will continue,
1325 * GNUNET_NO if this was the last entry (and iteration is complete),
1326 * GNUNET_SYSERR if abort was YES
1329 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1332 struct dirent *finfo;
1334 GNUNET_assert (iter->next_name == NULL);
1335 if (can == GNUNET_YES)
1337 CLOSEDIR (iter->directory);
1338 GNUNET_free (iter->dirname);
1340 return GNUNET_SYSERR;
1342 while (NULL != (finfo = READDIR (iter->directory)))
1344 if ((0 == strcmp (finfo->d_name, ".")) ||
1345 (0 == strcmp (finfo->d_name, "..")))
1347 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1348 DIR_SEPARATOR_STR, finfo->d_name);
1353 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1356 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1363 * Scan a directory for files using the scheduler to run a task for
1364 * each entry. The name of the directory must be expanded first (!).
1365 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1366 * may provide a simpler API.
1368 * @param prio priority to use
1369 * @param dirName the name of the directory
1370 * @param callback the method to call for each file
1371 * @param callback_cls closure for callback
1372 * @return GNUNET_YES if directory is not empty and 'callback'
1373 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1376 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1377 const char *dirName,
1378 GNUNET_DISK_DirectoryIteratorCallback
1379 callback, void *callback_cls)
1381 struct GNUNET_DISK_DirectoryIterator *di;
1383 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1384 di->callback = callback;
1385 di->callback_cls = callback_cls;
1386 di->directory = OPENDIR (dirName);
1387 if (di->directory == NULL)
1390 callback (callback_cls, NULL, NULL, NULL);
1391 return GNUNET_SYSERR;
1393 di->dirname = GNUNET_strdup (dirName);
1394 di->priority = prio;
1395 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1400 * Function that removes the given directory by calling
1401 * "GNUNET_DISK_directory_remove".
1403 * @param unused not used
1404 * @param fn directory to remove
1408 remove_helper (void *unused, const char *fn)
1410 (void) GNUNET_DISK_directory_remove (fn);
1416 * Remove all files in a directory (rm -rf). Call with
1420 * @param filename the file to remove
1421 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1424 GNUNET_DISK_directory_remove (const char *filename)
1428 if (0 != LSTAT (filename, &istat))
1429 return GNUNET_NO; /* file may not exist... */
1430 (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1431 if (UNLINK (filename) == 0)
1433 if ((errno != EISDIR) &&
1434 /* EISDIR is not sufficient in all cases, e.g.
1435 * sticky /tmp directory may result in EPERM on BSD.
1436 * So we also explicitly check "isDirectory" */
1437 (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1439 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1440 return GNUNET_SYSERR;
1442 if (GNUNET_SYSERR ==
1443 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1444 return GNUNET_SYSERR;
1445 if (0 != RMDIR (filename))
1447 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1448 return GNUNET_SYSERR;
1457 * @param src file to copy
1458 * @param dst destination file name
1459 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1462 GNUNET_DISK_file_copy (const char *src, const char *dst)
1468 struct GNUNET_DISK_FileHandle *in;
1469 struct GNUNET_DISK_FileHandle *out;
1471 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1472 return GNUNET_SYSERR;
1474 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1475 GNUNET_DISK_PERM_NONE);
1477 return GNUNET_SYSERR;
1479 GNUNET_DISK_file_open (dst,
1480 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1481 GNUNET_DISK_OPEN_FAILIFEXISTS,
1482 GNUNET_DISK_PERM_USER_READ |
1483 GNUNET_DISK_PERM_USER_WRITE |
1484 GNUNET_DISK_PERM_GROUP_READ |
1485 GNUNET_DISK_PERM_GROUP_WRITE);
1488 GNUNET_DISK_file_close (in);
1489 return GNUNET_SYSERR;
1491 buf = GNUNET_malloc (COPY_BLK_SIZE);
1494 len = COPY_BLK_SIZE;
1495 if (len > size - pos)
1497 if (len != GNUNET_DISK_file_read (in, buf, len))
1499 if (len != GNUNET_DISK_file_write (out, buf, len))
1504 GNUNET_DISK_file_close (in);
1505 GNUNET_DISK_file_close (out);
1509 GNUNET_DISK_file_close (in);
1510 GNUNET_DISK_file_close (out);
1511 return GNUNET_SYSERR;
1516 * @brief Removes special characters as ':' from a filename.
1517 * @param fn the filename to canonicalize
1520 GNUNET_DISK_filename_canonicalize (char *fn)
1530 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1531 c == '<' || c == '>' || c == '|')
1543 * @brief Change owner of a file
1545 * @param filename name of file to change the owner of
1546 * @param user name of the new owner
1547 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1550 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1555 pws = getpwnam (user);
1558 LOG (GNUNET_ERROR_TYPE_ERROR,
1559 _("Cannot obtain information about user `%s': %s\n"), user,
1561 return GNUNET_SYSERR;
1563 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1564 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1571 * Lock a part of a file
1572 * @param fh file handle
1573 * @param lockStart absolute position from where to lock
1574 * @param lockEnd absolute position until where to lock
1575 * @param excl GNUNET_YES for an exclusive lock
1576 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1579 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1580 OFF_T lockEnd, int excl)
1585 return GNUNET_SYSERR;
1591 memset (&fl, 0, sizeof (struct flock));
1592 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1593 fl.l_whence = SEEK_SET;
1594 fl.l_start = lockStart;
1597 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1600 OFF_T diff = lockEnd - lockStart;
1601 DWORD diff_low, diff_high;
1602 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1603 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1605 memset (&o, 0, sizeof (OVERLAPPED));
1606 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1607 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1610 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1611 0, diff_low, diff_high, &o))
1613 SetErrnoFromWinError (GetLastError ());
1614 return GNUNET_SYSERR;
1623 * Unlock a part of a file
1624 * @param fh file handle
1625 * @param unlockStart absolute position from where to unlock
1626 * @param unlockEnd absolute position until where to unlock
1627 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1630 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1636 return GNUNET_SYSERR;
1642 memset (&fl, 0, sizeof (struct flock));
1643 fl.l_type = F_UNLCK;
1644 fl.l_whence = SEEK_SET;
1645 fl.l_start = unlockStart;
1646 fl.l_len = unlockEnd;
1648 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1651 OFF_T diff = unlockEnd - unlockStart;
1652 DWORD diff_low, diff_high;
1653 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1654 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1656 memset (&o, 0, sizeof (OVERLAPPED));
1657 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1658 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1660 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1662 SetErrnoFromWinError (GetLastError ());
1663 return GNUNET_SYSERR;
1672 * Open a file. Note that the access permissions will only be
1673 * used if a new file is created and if the underlying operating
1674 * system supports the given permissions.
1676 * @param fn file name to be opened
1677 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1678 * @param perm permissions for the newly created file, use
1679 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1680 * call (because of flags)
1681 * @return IO handle on success, NULL on error
1683 struct GNUNET_DISK_FileHandle *
1684 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1685 enum GNUNET_DISK_AccessPermissions perm)
1688 struct GNUNET_DISK_FileHandle *ret;
1694 wchar_t wexpfn[MAX_PATH + 1];
1701 expfn = GNUNET_STRINGS_filename_expand (fn);
1706 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1707 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1708 else if (flags & GNUNET_DISK_OPEN_READ)
1710 else if (flags & GNUNET_DISK_OPEN_WRITE)
1715 GNUNET_free (expfn);
1718 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1719 oflags |= (O_CREAT | O_EXCL);
1720 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1722 if (flags & GNUNET_DISK_OPEN_APPEND)
1724 if (flags & GNUNET_DISK_OPEN_CREATE)
1726 (void) GNUNET_DISK_directory_create_for_file (expfn);
1728 mode = translate_unix_perms (perm);
1731 fd = open (expfn, oflags | O_LARGEFILE, mode);
1734 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1735 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1737 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1738 GNUNET_free (expfn);
1745 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1746 access = FILE_READ_DATA | FILE_WRITE_DATA;
1747 else if (flags & GNUNET_DISK_OPEN_READ)
1748 access = FILE_READ_DATA;
1749 else if (flags & GNUNET_DISK_OPEN_WRITE)
1750 access = FILE_WRITE_DATA;
1752 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1756 else if (flags & GNUNET_DISK_OPEN_CREATE)
1758 (void) GNUNET_DISK_directory_create_for_file (expfn);
1759 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1760 disp = CREATE_ALWAYS;
1764 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1766 disp = TRUNCATE_EXISTING;
1770 disp = OPEN_EXISTING;
1773 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1774 h = CreateFileW (wexpfn, access,
1775 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1776 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1778 h = INVALID_HANDLE_VALUE;
1779 if (h == INVALID_HANDLE_VALUE)
1782 SetErrnoFromWinError (GetLastError ());
1784 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1785 GNUNET_free (expfn);
1790 if (flags & GNUNET_DISK_OPEN_APPEND)
1791 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1793 SetErrnoFromWinError (GetLastError ());
1794 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1796 GNUNET_free (expfn);
1801 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1804 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1808 GNUNET_free (expfn);
1814 * Close an open file
1815 * @param h file handle
1816 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1819 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1824 return GNUNET_SYSERR;
1828 if (!CloseHandle (h->h))
1830 SetErrnoFromWinError (GetLastError ());
1831 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1832 GNUNET_free (h->oOverlapRead);
1833 GNUNET_free (h->oOverlapWrite);
1835 return GNUNET_SYSERR;
1838 if (close (h->fd) != 0)
1840 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1842 return GNUNET_SYSERR;
1851 * Get a handle from a native FD.
1853 * @param fd native file descriptor
1854 * @return file handle corresponding to the descriptor
1856 struct GNUNET_DISK_FileHandle *
1857 GNUNET_DISK_get_handle_from_native (FILE *fd)
1859 struct GNUNET_DISK_FileHandle *fh;
1870 osfh = _get_osfhandle (fno);
1871 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1875 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1878 fh->h = (HANDLE) osfh;
1879 /* Assume it to be a pipe. TODO: use some kind of detection
1880 * function to figure out handle type.
1881 * Note that we can't make it overlapped if it isn't already.
1882 * (ReOpenFile() is only available in 2003/Vista).
1883 * The process that opened this file in the first place (usually a parent
1884 * process, if this is stdin/stdout/stderr) must make it overlapped,
1885 * otherwise we're screwed, as selecting on non-overlapped handle
1888 fh->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
1889 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1890 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1891 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1892 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1902 * Construct full path to a file inside of the private
1903 * directory used by GNUnet. Also creates the corresponding
1904 * directory. If the resulting name is supposed to be
1905 * a directory, end the last argument in '/' (or pass
1906 * DIR_SEPARATOR_STR as the last argument before NULL).
1908 * @param cfg configuration to use (determines HOME)
1909 * @param serviceName name of the service
1910 * @param ... is NULL-terminated list of
1911 * path components to append to the
1912 * private directory name.
1913 * @return the constructed filename
1916 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1917 const char *serviceName, ...)
1923 unsigned int needed;
1926 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1930 LOG (GNUNET_ERROR_TYPE_WARNING,
1931 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1935 needed = strlen (pfx) + 2;
1936 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1938 va_start (ap, serviceName);
1941 c = va_arg (ap, const char *);
1945 needed += strlen (c);
1946 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1950 ret = GNUNET_malloc (needed);
1953 va_start (ap, serviceName);
1956 c = va_arg (ap, const char *);
1960 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1961 strcat (ret, DIR_SEPARATOR_STR);
1965 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1966 (void) GNUNET_DISK_directory_create_for_file (ret);
1968 (void) GNUNET_DISK_directory_create (ret);
1974 * Handle for a memory-mapping operation.
1976 struct GNUNET_DISK_MapHandle
1979 * Address where the map is in memory.
1985 * Underlying OS handle.
1990 * Number of bytes mapped.
1998 #define MAP_FAILED ((void *) -1)
2002 * Map a file into memory
2004 * @param h open file handle
2005 * @param m handle to the new mapping
2006 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
2007 * @param len size of the mapping
2008 * @return pointer to the mapped memory region, NULL on failure
2011 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
2012 struct GNUNET_DISK_MapHandle **m,
2013 enum GNUNET_DISK_MapType access, size_t len)
2022 DWORD mapAccess, protect;
2024 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2025 (access & GNUNET_DISK_MAP_TYPE_WRITE))
2027 protect = PAGE_READWRITE;
2028 mapAccess = FILE_MAP_ALL_ACCESS;
2030 else if (access & GNUNET_DISK_MAP_TYPE_READ)
2032 protect = PAGE_READONLY;
2033 mapAccess = FILE_MAP_READ;
2035 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2037 protect = PAGE_READWRITE;
2038 mapAccess = FILE_MAP_WRITE;
2046 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2047 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2048 if ((*m)->h == INVALID_HANDLE_VALUE)
2050 SetErrnoFromWinError (GetLastError ());
2055 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2058 SetErrnoFromWinError (GetLastError ());
2059 CloseHandle ((*m)->h);
2068 if (access & GNUNET_DISK_MAP_TYPE_READ)
2070 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2072 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2073 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2074 GNUNET_assert (NULL != (*m)->addr);
2075 if (MAP_FAILED == (*m)->addr)
2087 * @param h mapping handle
2088 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2091 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2098 return GNUNET_SYSERR;
2102 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2103 if (ret != GNUNET_OK)
2104 SetErrnoFromWinError (GetLastError ());
2105 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2107 ret = GNUNET_SYSERR;
2108 SetErrnoFromWinError (GetLastError ());
2111 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2119 * Write file changes to disk
2120 * @param h handle to an open file
2121 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2124 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2129 return GNUNET_SYSERR;
2135 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2136 if (ret != GNUNET_OK)
2137 SetErrnoFromWinError (GetLastError ());
2139 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2140 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2142 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2148 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2149 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2151 /* Create a pipe, and return handles to the read and write ends,
2152 just like CreatePipe, but ensure that the write end permits
2153 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2154 this is supported. This access is needed by NtQueryInformationFile,
2155 which is used to implement select and nonblocking writes.
2156 Note that the return value is either NO_ERROR or GetLastError,
2157 unlike CreatePipe, which returns a bool for success or failure. */
2159 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2160 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2161 DWORD dwReadMode, DWORD dwWriteMode)
2163 /* Default to error. */
2164 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2169 /* Ensure that there is enough pipe buffer space for atomic writes. */
2170 if (psize < PIPE_BUF)
2173 char pipename[MAX_PATH];
2175 /* Retry CreateNamedPipe as long as the pipe name is in use.
2176 * Retrying will probably never be necessary, but we want
2177 * to be as robust as possible. */
2180 static volatile LONG pipe_unique_id;
2182 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2183 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2184 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2186 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2187 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2188 * access, on versions of win32 earlier than WinXP SP2.
2189 * CreatePipe also stupidly creates a full duplex pipe, which is
2190 * a waste, since only a single direction is actually used.
2191 * It's important to only allow a single instance, to ensure that
2192 * the pipe was not created earlier by some other process, even if
2193 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
2194 * because that is only available for Win2k SP2 and WinXP. */
2195 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2196 psize, /* output buffer size */
2197 psize, /* input buffer size */
2198 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2200 if (read_pipe != INVALID_HANDLE_VALUE)
2202 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2206 DWORD err = GetLastError ();
2210 case ERROR_PIPE_BUSY:
2211 /* The pipe is already open with compatible parameters.
2212 * Pick a new name and retry. */
2213 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2215 case ERROR_ACCESS_DENIED:
2216 /* The pipe is already open with incompatible parameters.
2217 * Pick a new name and retry. */
2218 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2220 case ERROR_CALL_NOT_IMPLEMENTED:
2221 /* We are on an older Win9x platform without named pipes.
2222 * Return an anonymous pipe as the best approximation. */
2223 LOG (GNUNET_ERROR_TYPE_DEBUG,
2224 "CreateNamedPipe not implemented, resorting to "
2225 "CreatePipe: size = %lu\n", psize);
2226 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2228 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2233 err = GetLastError ();
2234 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2237 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2242 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2244 /* Open the named pipe for writing.
2245 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2246 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2247 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2248 0); /* handle to template file */
2250 if (write_pipe == INVALID_HANDLE_VALUE)
2253 DWORD err = GetLastError ();
2255 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2256 CloseHandle (read_pipe);
2259 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2261 *read_pipe_ptr = read_pipe;
2262 *write_pipe_ptr = write_pipe;
2269 * Creates an interprocess channel
2271 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2272 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2273 * @param inherit_read inherit the parent processes stdin (only for windows)
2274 * @param inherit_write inherit the parent processes stdout (only for windows)
2275 * @return handle to the new pipe, NULL on error
2277 struct GNUNET_DISK_PipeHandle *
2278 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2289 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2293 return GNUNET_DISK_pipe_from_fd (blocking_read,
2297 struct GNUNET_DISK_PipeHandle *p;
2298 struct GNUNET_DISK_FileHandle *fds;
2303 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2304 2 * sizeof (struct GNUNET_DISK_FileHandle));
2305 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2309 /* All pipes are overlapped. If you want them to block - just
2310 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2313 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2314 FILE_FLAG_OVERLAPPED,
2315 FILE_FLAG_OVERLAPPED);
2319 SetErrnoFromWinError (GetLastError ());
2322 if (!DuplicateHandle
2323 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2324 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2326 SetErrnoFromWinError (GetLastError ());
2327 CloseHandle (p->fd[0]->h);
2328 CloseHandle (p->fd[1]->h);
2332 CloseHandle (p->fd[0]->h);
2333 p->fd[0]->h = tmp_handle;
2335 if (!DuplicateHandle
2336 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2337 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2339 SetErrnoFromWinError (GetLastError ());
2340 CloseHandle (p->fd[0]->h);
2341 CloseHandle (p->fd[1]->h);
2345 CloseHandle (p->fd[1]->h);
2346 p->fd[1]->h = tmp_handle;
2348 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2349 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2351 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2352 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2353 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2354 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2356 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2357 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2359 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2360 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2368 * Creates a pipe object from a couple of file descriptors.
2369 * Useful for wrapping existing pipe FDs.
2371 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2372 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2373 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2375 * @return handle to the new pipe, NULL on error
2377 struct GNUNET_DISK_PipeHandle *
2378 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2380 struct GNUNET_DISK_PipeHandle *p;
2381 struct GNUNET_DISK_FileHandle *fds;
2383 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2384 2 * sizeof (struct GNUNET_DISK_FileHandle));
2385 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2391 int eno = 0; /* make gcc happy */
2393 p->fd[0]->fd = fd[0];
2394 p->fd[1]->fd = fd[1];
2400 flags = fcntl (fd[0], F_GETFL);
2401 flags |= O_NONBLOCK;
2402 if (0 > fcntl (fd[0], F_SETFL, flags))
2408 flags = fcntl (fd[0], F_GETFD);
2409 flags |= FD_CLOEXEC;
2410 if (0 > fcntl (fd[0], F_SETFD, flags))
2419 if (!blocking_write)
2421 flags = fcntl (fd[1], F_GETFL);
2422 flags |= O_NONBLOCK;
2423 if (0 > fcntl (fd[1], F_SETFL, flags))
2429 flags = fcntl (fd[1], F_GETFD);
2430 flags |= FD_CLOEXEC;
2431 if (0 > fcntl (fd[1], F_SETFD, flags))
2440 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2441 if (p->fd[0]->fd >= 0)
2442 GNUNET_break (0 == close (p->fd[0]->fd));
2443 if (p->fd[1]->fd >= 0)
2444 GNUNET_break (0 == close (p->fd[1]->fd));
2451 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2453 p->fd[0]->h = INVALID_HANDLE_VALUE;
2455 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2457 p->fd[1]->h = INVALID_HANDLE_VALUE;
2459 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2461 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2462 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2463 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2464 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2465 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2468 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2470 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2471 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2472 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2473 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2474 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2482 * Closes an interprocess channel
2484 * @param p pipe to close
2485 * @param end which end of the pipe to close
2486 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2489 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2490 enum GNUNET_DISK_PipeEnd end)
2492 int ret = GNUNET_OK;
2496 if (end == GNUNET_DISK_PIPE_END_READ)
2498 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2500 if (!CloseHandle (p->fd[0]->h))
2502 SetErrnoFromWinError (GetLastError ());
2503 ret = GNUNET_SYSERR;
2505 GNUNET_free (p->fd[0]->oOverlapRead);
2506 GNUNET_free (p->fd[0]->oOverlapWrite);
2507 p->fd[0]->h = INVALID_HANDLE_VALUE;
2510 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2512 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2514 if (!CloseHandle (p->fd[1]->h))
2516 SetErrnoFromWinError (GetLastError ());
2517 ret = GNUNET_SYSERR;
2519 GNUNET_free (p->fd[1]->oOverlapRead);
2520 GNUNET_free (p->fd[1]->oOverlapWrite);
2521 p->fd[1]->h = INVALID_HANDLE_VALUE;
2527 if (end == GNUNET_DISK_PIPE_END_READ)
2529 if (0 != close (p->fd[0]->fd))
2531 ret = GNUNET_SYSERR;
2536 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2538 if (0 != close (p->fd[1]->fd))
2540 ret = GNUNET_SYSERR;
2552 * Closes an interprocess channel
2554 * @param p pipe to close
2555 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2558 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2560 int ret = GNUNET_OK;
2564 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2566 if (!CloseHandle (p->fd[0]->h))
2568 SetErrnoFromWinError (GetLastError ());
2569 ret = GNUNET_SYSERR;
2571 GNUNET_free (p->fd[0]->oOverlapRead);
2572 GNUNET_free (p->fd[0]->oOverlapWrite);
2574 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2576 if (!CloseHandle (p->fd[1]->h))
2578 SetErrnoFromWinError (GetLastError ());
2579 ret = GNUNET_SYSERR;
2581 GNUNET_free (p->fd[1]->oOverlapRead);
2582 GNUNET_free (p->fd[1]->oOverlapWrite);
2587 if (p->fd[0]->fd != -1)
2589 if (0 != close (p->fd[0]->fd))
2591 ret = GNUNET_SYSERR;
2596 if (p->fd[1]->fd != -1)
2598 if (0 != close (p->fd[1]->fd))
2600 ret = GNUNET_SYSERR;
2612 * Get the handle to a particular pipe end
2615 * @param n end to access
2616 * @return handle for the respective end
2618 const struct GNUNET_DISK_FileHandle *
2619 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2620 enum GNUNET_DISK_PipeEnd n)
2624 case GNUNET_DISK_PIPE_END_READ:
2625 case GNUNET_DISK_PIPE_END_WRITE:
2635 * Retrieve OS file handle
2637 * @param fh GNUnet file descriptor
2638 * @param dst destination buffer
2639 * @param dst_len length of dst
2640 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2643 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2644 void *dst, size_t dst_len)
2647 if (dst_len < sizeof (HANDLE))
2648 return GNUNET_SYSERR;
2649 *((HANDLE *) dst) = fh->h;
2651 if (dst_len < sizeof (int))
2652 return GNUNET_SYSERR;
2653 *((int *) dst) = fh->fd;