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)
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;
273 LARGE_INTEGER li, new_pos;
276 static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
277 [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
279 li.QuadPart = offset;
281 b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
284 SetErrnoFromWinError (GetLastError ());
285 return GNUNET_SYSERR;
287 return (OFF_T) new_pos.QuadPart;
289 static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
290 [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
293 return lseek (h->fd, offset, t[whence]);
299 * Get the size of the file (or directory) of the given file (in
302 * @param filename name of the file or directory
303 * @param size set to the size of the file (or,
304 * in the case of directories, the sum
305 * of all sizes of files in the directory)
306 * @param includeSymLinks should symbolic links be
308 * @param singleFileMode GNUNET_YES to only get size of one file
309 * and return GNUNET_SYSERR for directories.
310 * @return GNUNET_SYSERR on error, GNUNET_OK on success
313 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
314 int includeSymLinks, int singleFileMode)
316 struct GetFileSizeData gfsd;
319 GNUNET_assert (size != NULL);
321 gfsd.include_sym_links = includeSymLinks;
322 gfsd.single_file_mode = singleFileMode;
323 ret = getSizeRec (&gfsd, filename);
330 * Obtain some unique identifiers for the given file
331 * that can be used to identify it in the local system.
332 * This function is used between GNUnet processes to
333 * quickly check if two files with the same absolute path
334 * are actually identical. The two processes represent
335 * the same peer but may communicate over the network
336 * (and the file may be on an NFS volume). This function
337 * may not be supported on all operating systems.
339 * @param filename name of the file
340 * @param dev set to the device ID
341 * @param ino set to the inode ID
342 * @return GNUNET_OK on success
345 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
352 if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf)))
354 *dev = (uint64_t) fbuf.f_fsid;
355 *ino = (uint64_t) sbuf.st_ino;
362 if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf)))
364 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
365 ((uint64_t) fbuf.f_fsid.val[1]);
366 *ino = (uint64_t) sbuf.st_ino;
370 // FIXME NILS: test this
371 struct GNUNET_DISK_FileHandle *fh;
372 BY_HANDLE_FILE_INFORMATION info;
375 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
377 return GNUNET_SYSERR;
378 succ = GetFileInformationByHandle (fh->h, &info);
379 GNUNET_DISK_file_close (fh);
382 *dev = info.dwVolumeSerialNumber;
383 *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
387 return GNUNET_SYSERR;
390 return GNUNET_SYSERR;
395 * Create an (empty) temporary file on disk. If the given name is not
396 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
397 * 6 random characters will be appended to the name to create a unique
400 * @param t component to use for the name;
401 * does NOT contain "XXXXXX" or "/tmp/".
402 * @return NULL on error, otherwise name of fresh
403 * file on disk in directory for temporary files
406 GNUNET_DISK_mktemp (const char *t)
413 if ((t[0] != '/') && (t[0] != '\\')
415 && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
419 /* FIXME: This uses system codepage on W32, not UTF-8 */
420 tmpdir = getenv ("TMPDIR");
421 tmpdir = tmpdir ? tmpdir : "/tmp";
422 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
426 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
429 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
430 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
440 /* FIXME: why is this not MKSTEMP()? This function is implemented in plibc.
441 * CG: really? If I put MKSTEMP here, I get a compilation error...
442 * It will assume that fn is UTF-8-encoded, if compiled with UTF-8 support.
447 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
452 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
458 * Get the number of blocks that are left on the partition that
459 * contains the given file (for normal users).
461 * @param part a file on the partition to check
462 * @return -1 on errors, otherwise the number of free blocks
465 GNUNET_DISK_get_blocks_available (const char *part)
470 if (0 != statvfs (part, &buf))
472 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
480 wchar_t wpath[MAX_PATH + 1];
483 path = GNUNET_STRINGS_filename_expand (part);
486 /* "part" was in UTF-8, and so is "path" */
487 if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath))
493 wcsncpy (szDrive, wpath, 3);
495 if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
497 LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"),
498 "GetDiskFreeSpace", szDrive, GetLastError ());
506 if (0 != statfs (part, &s))
508 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
517 * Test if "fil" is a directory.
518 * Will not print an error message if the directory
519 * does not exist. Will log errors if GNUNET_SYSERR is
520 * returned (i.e., a file exists with the same name).
522 * @param fil filename to test
523 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
527 GNUNET_DISK_directory_test (const char *fil)
529 struct stat filestat;
532 ret = STAT (fil, &filestat);
537 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
538 return GNUNET_SYSERR;
542 if (!S_ISDIR (filestat.st_mode))
544 if (ACCESS (fil, R_OK | X_OK) < 0)
546 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
547 return GNUNET_SYSERR;
554 * Check that fil corresponds to a filename
555 * (of a file that exists and that is not a directory).
557 * @param fil filename to check
558 * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
559 * else (will print an error message in that case, too).
562 GNUNET_DISK_file_test (const char *fil)
564 struct stat filestat;
568 rdir = GNUNET_STRINGS_filename_expand (fil);
570 return GNUNET_SYSERR;
572 ret = STAT (rdir, &filestat);
577 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
579 return GNUNET_SYSERR;
584 if (!S_ISREG (filestat.st_mode))
589 if (ACCESS (rdir, R_OK) < 0)
591 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
593 return GNUNET_SYSERR;
601 * Implementation of "mkdir -p"
602 * @param dir the directory to create
603 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
606 GNUNET_DISK_directory_create (const char *dir)
613 rdir = GNUNET_STRINGS_filename_expand (dir);
615 return GNUNET_SYSERR;
619 pos = 1; /* skip heading '/' */
621 /* Local or Network path? */
622 if (strncmp (rdir, "\\\\", 2) == 0)
627 if (rdir[pos] == '\\')
637 pos = 3; /* strlen("C:\\") */
642 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
645 ret = GNUNET_DISK_directory_test (rdir);
646 if (ret == GNUNET_SYSERR)
649 return GNUNET_SYSERR;
651 if (ret == GNUNET_NO)
654 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
656 wchar_t wrdir[MAX_PATH + 1];
657 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
658 ret = !CreateDirectoryW (wrdir, NULL);
662 if ((ret != 0) && (errno != EEXIST))
664 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
666 return GNUNET_SYSERR;
669 rdir[pos] = DIR_SEPARATOR;
679 * Create the directory structure for storing
682 * @param filename name of a file in the directory
683 * @returns GNUNET_OK on success,
684 * GNUNET_SYSERR on failure,
685 * GNUNET_NO if the directory
686 * exists but is not writeable for us
689 GNUNET_DISK_directory_create_for_file (const char *filename)
695 rdir = GNUNET_STRINGS_filename_expand (filename);
697 return GNUNET_SYSERR;
699 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
702 ret = GNUNET_DISK_directory_create (rdir);
703 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
711 * Read the contents of a binary file into a buffer.
712 * @param h handle to an open file
713 * @param result the buffer to write the result to
714 * @param len the maximum number of bytes to read
715 * @return the number of bytes read on success, GNUNET_SYSERR on failure
718 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
724 return GNUNET_SYSERR;
730 if (h->type != GNUNET_PIPE)
732 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
734 SetErrnoFromWinError (GetLastError ());
735 return GNUNET_SYSERR;
740 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
742 if (GetLastError () != ERROR_IO_PENDING)
744 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
745 SetErrnoFromWinError (GetLastError ());
746 return GNUNET_SYSERR;
748 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
749 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
751 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
755 return read (h->fd, result, len);
761 * Read the contents of a binary file into a buffer.
762 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
763 * when no data can be read).
765 * @param h handle to an open file
766 * @param result the buffer to write the result to
767 * @param len the maximum number of bytes to read
768 * @return the number of bytes read on success, GNUNET_SYSERR on failure
771 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
772 void *result, size_t len)
777 return GNUNET_SYSERR;
783 if (h->type != GNUNET_PIPE)
785 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
787 SetErrnoFromWinError (GetLastError ());
788 return GNUNET_SYSERR;
793 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
795 if (GetLastError () != ERROR_IO_PENDING)
797 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
798 SetErrnoFromWinError (GetLastError ());
799 return GNUNET_SYSERR;
803 LOG (GNUNET_ERROR_TYPE_DEBUG,
804 "ReadFile() queued a read, cancelling\n");
807 return GNUNET_SYSERR;
810 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
817 /* set to non-blocking, read, then set back */
818 flags = fcntl (h->fd, F_GETFL);
819 if (0 == (flags & O_NONBLOCK))
820 fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
821 ret = read (h->fd, result, len);
822 if (0 == (flags & O_NONBLOCK))
823 fcntl (h->fd, F_SETFL, flags);
830 * Read the contents of a binary file into a buffer.
832 * @param fn file name
833 * @param result the buffer to write the result to
834 * @param len the maximum number of bytes to read
835 * @return number of bytes read, GNUNET_SYSERR on failure
838 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
840 struct GNUNET_DISK_FileHandle *fh;
843 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
845 return GNUNET_SYSERR;
846 ret = GNUNET_DISK_file_read (fh, result, len);
847 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
854 * Write a buffer to a file.
855 * @param h handle to open file
856 * @param buffer the data to write
857 * @param n number of bytes to write
858 * @return number of bytes written on success, GNUNET_SYSERR on error
861 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
862 const void *buffer, size_t n)
867 return GNUNET_SYSERR;
873 if (h->type != GNUNET_PIPE)
875 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
877 SetErrnoFromWinError (GetLastError ());
878 return GNUNET_SYSERR;
883 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
884 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
886 if (GetLastError () != ERROR_IO_PENDING)
888 SetErrnoFromWinError (GetLastError ());
889 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
891 return GNUNET_SYSERR;
893 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
894 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
896 SetErrnoFromWinError (GetLastError ());
897 LOG (GNUNET_ERROR_TYPE_DEBUG,
898 "Error getting overlapped result while writing to pipe: %u\n",
900 return GNUNET_SYSERR;
906 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
908 LOG (GNUNET_ERROR_TYPE_DEBUG,
909 "Error getting control overlapped result while writing to pipe: %u\n",
914 LOG (GNUNET_ERROR_TYPE_DEBUG,
915 "Wrote %u bytes (ovr says %u), picking the greatest\n",
919 if (bytesWritten == 0)
923 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
925 return GNUNET_SYSERR;
928 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
932 return write (h->fd, buffer, n);
938 * Write a buffer to a file, blocking, if necessary.
939 * @param h handle to open file
940 * @param buffer the data to write
941 * @param n number of bytes to write
942 * @return number of bytes written on success, GNUNET_SYSERR on error
945 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
946 const void *buffer, size_t n)
951 return GNUNET_SYSERR;
956 /* We do a non-overlapped write, which is as blocking as it gets */
957 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
958 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
960 SetErrnoFromWinError (GetLastError ());
961 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
963 return GNUNET_SYSERR;
965 if (bytesWritten == 0 && n > 0)
967 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
968 WaitForSingleObject (h->h, INFINITE);
969 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
971 SetErrnoFromWinError (GetLastError ());
972 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
974 return GNUNET_SYSERR;
977 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
983 /* set to blocking, write, then set back */
984 flags = fcntl (h->fd, F_GETFL);
985 if (0 != (flags & O_NONBLOCK))
986 fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
987 ret = write (h->fd, buffer, n);
988 if (0 == (flags & O_NONBLOCK))
989 fcntl (h->fd, F_SETFL, flags);
996 * Write a buffer to a file. If the file is longer than the
997 * number of bytes that will be written, it will be truncated.
999 * @param fn file name
1000 * @param buffer the data to write
1001 * @param n number of bytes to write
1002 * @param mode file permissions
1003 * @return number of bytes written on success, GNUNET_SYSERR on error
1006 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1007 enum GNUNET_DISK_AccessPermissions mode)
1009 struct GNUNET_DISK_FileHandle *fh;
1012 fh = GNUNET_DISK_file_open (fn,
1013 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1014 | GNUNET_DISK_OPEN_CREATE, mode);
1016 return GNUNET_SYSERR;
1017 ret = GNUNET_DISK_file_write (fh, buffer, n);
1018 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1024 * Scan a directory for files.
1026 * @param dirName the name of the directory
1027 * @param callback the method to call for each file,
1028 * can be NULL, in that case, we only count
1029 * @param callback_cls closure for callback
1030 * @return the number of files found, GNUNET_SYSERR on error or
1031 * ieration aborted by callback returning GNUNET_SYSERR
1034 GNUNET_DISK_directory_scan (const char *dirName,
1035 GNUNET_FileNameCallback callback,
1039 struct dirent *finfo;
1044 unsigned int name_len;
1045 unsigned int n_size;
1047 GNUNET_assert (dirName != NULL);
1048 dname = GNUNET_STRINGS_filename_expand (dirName);
1050 return GNUNET_SYSERR;
1051 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1052 dname[strlen (dname) - 1] = '\0';
1053 if (0 != STAT (dname, &istat))
1055 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1056 GNUNET_free (dname);
1057 return GNUNET_SYSERR;
1059 if (!S_ISDIR (istat.st_mode))
1061 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1063 GNUNET_free (dname);
1064 return GNUNET_SYSERR;
1067 dinfo = OPENDIR (dname);
1068 if ((errno == EACCES) || (dinfo == NULL))
1070 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1073 GNUNET_free (dname);
1074 return GNUNET_SYSERR;
1077 n_size = strlen (dname) + name_len + 2;
1078 name = GNUNET_malloc (n_size);
1079 while ((finfo = READDIR (dinfo)) != NULL)
1081 if ((0 == strcmp (finfo->d_name, ".")) ||
1082 (0 == strcmp (finfo->d_name, "..")))
1084 if (callback != NULL)
1086 if (name_len < strlen (finfo->d_name))
1089 name_len = strlen (finfo->d_name);
1090 n_size = strlen (dname) + name_len + 2;
1091 name = GNUNET_malloc (n_size);
1093 /* dname can end in "/" only if dname == "/";
1094 * if dname does not end in "/", we need to add
1095 * a "/" (otherwise, we must not!) */
1096 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1097 (strcmp (dname, DIR_SEPARATOR_STR) ==
1098 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1099 if (GNUNET_OK != callback (callback_cls, name))
1103 GNUNET_free (dname);
1104 return GNUNET_SYSERR;
1111 GNUNET_free (dname);
1117 * Opaque handle used for iterating over a directory.
1119 struct GNUNET_DISK_DirectoryIterator
1123 * Function to call on directory entries.
1125 GNUNET_DISK_DirectoryIteratorCallback callback;
1128 * Closure for callback.
1133 * Reference to directory.
1143 * Next filename to process.
1150 enum GNUNET_SCHEDULER_Priority priority;
1156 * Task used by the directory iterator.
1159 directory_iterator_task (void *cls,
1160 const struct GNUNET_SCHEDULER_TaskContext *tc)
1162 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1165 name = iter->next_name;
1166 GNUNET_assert (name != NULL);
1167 iter->next_name = NULL;
1168 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1174 * This function must be called during the DiskIteratorCallback
1175 * (exactly once) to schedule the task to process the next
1176 * filename in the directory (if there is one).
1178 * @param iter opaque handle for the iterator
1179 * @param can set to GNUNET_YES to terminate the iteration early
1180 * @return GNUNET_YES if iteration will continue,
1181 * GNUNET_NO if this was the last entry (and iteration is complete),
1182 * GNUNET_SYSERR if abort was YES
1185 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1188 struct dirent *finfo;
1190 GNUNET_assert (iter->next_name == NULL);
1191 if (can == GNUNET_YES)
1193 CLOSEDIR (iter->directory);
1194 GNUNET_free (iter->dirname);
1196 return GNUNET_SYSERR;
1198 while (NULL != (finfo = READDIR (iter->directory)))
1200 if ((0 == strcmp (finfo->d_name, ".")) ||
1201 (0 == strcmp (finfo->d_name, "..")))
1203 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1204 DIR_SEPARATOR_STR, finfo->d_name);
1209 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1212 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1219 * Scan a directory for files using the scheduler to run a task for
1220 * each entry. The name of the directory must be expanded first (!).
1221 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1222 * may provide a simpler API.
1224 * @param prio priority to use
1225 * @param dirName the name of the directory
1226 * @param callback the method to call for each file
1227 * @param callback_cls closure for callback
1228 * @return GNUNET_YES if directory is not empty and 'callback'
1229 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1232 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1233 const char *dirName,
1234 GNUNET_DISK_DirectoryIteratorCallback
1235 callback, void *callback_cls)
1237 struct GNUNET_DISK_DirectoryIterator *di;
1239 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1240 di->callback = callback;
1241 di->callback_cls = callback_cls;
1242 di->directory = OPENDIR (dirName);
1243 if (di->directory == NULL)
1246 callback (callback_cls, NULL, NULL, NULL);
1247 return GNUNET_SYSERR;
1249 di->dirname = GNUNET_strdup (dirName);
1250 di->priority = prio;
1251 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1256 * Function that removes the given directory by calling
1257 * "GNUNET_DISK_directory_remove".
1259 * @param unused not used
1260 * @param fn directory to remove
1264 remove_helper (void *unused, const char *fn)
1266 (void) GNUNET_DISK_directory_remove (fn);
1272 * Remove all files in a directory (rm -rf). Call with
1276 * @param fileName the file to remove
1277 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1280 GNUNET_DISK_directory_remove (const char *fileName)
1284 if (0 != LSTAT (fileName, &istat))
1285 return GNUNET_NO; /* file may not exist... */
1286 CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR);
1287 if (UNLINK (fileName) == 0)
1289 if ((errno != EISDIR) &&
1290 /* EISDIR is not sufficient in all cases, e.g.
1291 * sticky /tmp directory may result in EPERM on BSD.
1292 * So we also explicitly check "isDirectory" */
1293 (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
1295 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1296 return GNUNET_SYSERR;
1298 if (GNUNET_SYSERR ==
1299 GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL))
1300 return GNUNET_SYSERR;
1301 if (0 != RMDIR (fileName))
1303 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
1304 return GNUNET_SYSERR;
1313 * @param src file to copy
1314 * @param dst destination file name
1315 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1318 GNUNET_DISK_file_copy (const char *src, const char *dst)
1324 struct GNUNET_DISK_FileHandle *in;
1325 struct GNUNET_DISK_FileHandle *out;
1327 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1328 return GNUNET_SYSERR;
1330 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1331 GNUNET_DISK_PERM_NONE);
1333 return GNUNET_SYSERR;
1335 GNUNET_DISK_file_open (dst,
1336 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1337 GNUNET_DISK_OPEN_FAILIFEXISTS,
1338 GNUNET_DISK_PERM_USER_READ |
1339 GNUNET_DISK_PERM_USER_WRITE |
1340 GNUNET_DISK_PERM_GROUP_READ |
1341 GNUNET_DISK_PERM_GROUP_WRITE);
1344 GNUNET_DISK_file_close (in);
1345 return GNUNET_SYSERR;
1347 buf = GNUNET_malloc (COPY_BLK_SIZE);
1350 len = COPY_BLK_SIZE;
1351 if (len > size - pos)
1353 if (len != GNUNET_DISK_file_read (in, buf, len))
1355 if (len != GNUNET_DISK_file_write (out, buf, len))
1360 GNUNET_DISK_file_close (in);
1361 GNUNET_DISK_file_close (out);
1365 GNUNET_DISK_file_close (in);
1366 GNUNET_DISK_file_close (out);
1367 return GNUNET_SYSERR;
1372 * @brief Removes special characters as ':' from a filename.
1373 * @param fn the filename to canonicalize
1376 GNUNET_DISK_filename_canonicalize (char *fn)
1386 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1387 c == '<' || c == '>' || c == '|')
1399 * @brief Change owner of a file
1401 * @param filename name of file to change the owner of
1402 * @param user name of the new owner
1403 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1406 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1411 pws = getpwnam (user);
1414 LOG (GNUNET_ERROR_TYPE_ERROR,
1415 _("Cannot obtain information about user `%s': %s\n"), user,
1417 return GNUNET_SYSERR;
1419 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1420 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1427 * Lock a part of a file
1428 * @param fh file handle
1429 * @param lockStart absolute position from where to lock
1430 * @param lockEnd absolute position until where to lock
1431 * @param excl GNUNET_YES for an exclusive lock
1432 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1435 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1436 OFF_T lockEnd, int excl)
1441 return GNUNET_SYSERR;
1447 memset (&fl, 0, sizeof (struct flock));
1448 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1449 fl.l_whence = SEEK_SET;
1450 fl.l_start = lockStart;
1453 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1456 OFF_T diff = lockEnd - lockStart;
1457 DWORD diff_low, diff_high;
1458 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1459 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1461 memset (&o, 0, sizeof (OVERLAPPED));
1462 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1463 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1466 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1467 0, diff_low, diff_high, &o))
1469 SetErrnoFromWinError (GetLastError ());
1470 return GNUNET_SYSERR;
1479 * Unlock a part of a file
1480 * @param fh file handle
1481 * @param unlockStart absolute position from where to unlock
1482 * @param unlockEnd absolute position until where to unlock
1483 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1486 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1492 return GNUNET_SYSERR;
1498 memset (&fl, 0, sizeof (struct flock));
1499 fl.l_type = F_UNLCK;
1500 fl.l_whence = SEEK_SET;
1501 fl.l_start = unlockStart;
1502 fl.l_len = unlockEnd;
1504 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1507 OFF_T diff = unlockEnd - unlockStart;
1508 DWORD diff_low, diff_high;
1509 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1510 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1512 memset (&o, 0, sizeof (OVERLAPPED));
1513 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1514 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1516 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1518 SetErrnoFromWinError (GetLastError ());
1519 return GNUNET_SYSERR;
1528 * Open a file. Note that the access permissions will only be
1529 * used if a new file is created and if the underlying operating
1530 * system supports the given permissions.
1532 * @param fn file name to be opened
1533 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1534 * @param perm permissions for the newly created file, use
1535 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1536 * call (because of flags)
1537 * @return IO handle on success, NULL on error
1539 struct GNUNET_DISK_FileHandle *
1540 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1541 enum GNUNET_DISK_AccessPermissions perm)
1544 struct GNUNET_DISK_FileHandle *ret;
1550 wchar_t wexpfn[MAX_PATH + 1];
1557 expfn = GNUNET_STRINGS_filename_expand (fn);
1562 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1563 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1564 else if (flags & GNUNET_DISK_OPEN_READ)
1566 else if (flags & GNUNET_DISK_OPEN_WRITE)
1571 GNUNET_free (expfn);
1574 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1575 oflags |= (O_CREAT | O_EXCL);
1576 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1578 if (flags & GNUNET_DISK_OPEN_APPEND)
1580 if (flags & GNUNET_DISK_OPEN_CREATE)
1582 (void) GNUNET_DISK_directory_create_for_file (expfn);
1584 mode = translate_unix_perms (perm);
1587 fd = open (expfn, oflags | O_LARGEFILE, mode);
1590 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1591 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1593 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1594 GNUNET_free (expfn);
1601 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1602 access = FILE_READ_DATA | FILE_WRITE_DATA;
1603 else if (flags & GNUNET_DISK_OPEN_READ)
1604 access = FILE_READ_DATA;
1605 else if (flags & GNUNET_DISK_OPEN_WRITE)
1606 access = FILE_WRITE_DATA;
1608 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1612 else if (flags & GNUNET_DISK_OPEN_CREATE)
1614 (void) GNUNET_DISK_directory_create_for_file (expfn);
1615 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1616 disp = CREATE_ALWAYS;
1620 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1622 disp = TRUNCATE_EXISTING;
1626 disp = OPEN_EXISTING;
1629 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1630 h = CreateFileW (wexpfn, access,
1631 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1632 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1634 h = INVALID_HANDLE_VALUE;
1635 if (h == INVALID_HANDLE_VALUE)
1637 SetErrnoFromWinError (GetLastError ());
1638 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1639 GNUNET_free (expfn);
1643 if (flags & GNUNET_DISK_OPEN_APPEND)
1644 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1646 SetErrnoFromWinError (GetLastError ());
1647 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1649 GNUNET_free (expfn);
1654 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1657 ret->type = GNUNET_DISK_FILE;
1661 GNUNET_free (expfn);
1667 * Close an open file
1668 * @param h file handle
1669 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1672 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1677 return GNUNET_SYSERR;
1681 if (!CloseHandle (h->h))
1683 SetErrnoFromWinError (GetLastError ());
1684 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1685 GNUNET_free (h->oOverlapRead);
1686 GNUNET_free (h->oOverlapWrite);
1688 return GNUNET_SYSERR;
1691 if (close (h->fd) != 0)
1693 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1695 return GNUNET_SYSERR;
1704 * Construct full path to a file inside of the private
1705 * directory used by GNUnet. Also creates the corresponding
1706 * directory. If the resulting name is supposed to be
1707 * a directory, end the last argument in '/' (or pass
1708 * DIR_SEPARATOR_STR as the last argument before NULL).
1710 * @param cfg configuration to use (determines HOME)
1711 * @param serviceName name of the service
1712 * @param ... is NULL-terminated list of
1713 * path components to append to the
1714 * private directory name.
1715 * @return the constructed filename
1718 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1719 const char *serviceName, ...)
1725 unsigned int needed;
1728 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1732 LOG (GNUNET_ERROR_TYPE_WARNING,
1733 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1737 needed = strlen (pfx) + 2;
1738 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1740 va_start (ap, serviceName);
1743 c = va_arg (ap, const char *);
1747 needed += strlen (c);
1748 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1752 ret = GNUNET_malloc (needed);
1755 va_start (ap, serviceName);
1758 c = va_arg (ap, const char *);
1762 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1763 strcat (ret, DIR_SEPARATOR_STR);
1767 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1768 (void) GNUNET_DISK_directory_create_for_file (ret);
1770 (void) GNUNET_DISK_directory_create (ret);
1776 * Handle for a memory-mapping operation.
1778 struct GNUNET_DISK_MapHandle
1781 * Address where the map is in memory.
1787 * Underlying OS handle.
1792 * Number of bytes mapped.
1800 #define MAP_FAILED ((void *) -1)
1804 * Map a file into memory
1806 * @param h open file handle
1807 * @param m handle to the new mapping
1808 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1809 * @param len size of the mapping
1810 * @return pointer to the mapped memory region, NULL on failure
1813 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1814 struct GNUNET_DISK_MapHandle **m,
1815 enum GNUNET_DISK_MapType access, size_t len)
1824 DWORD mapAccess, protect;
1826 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
1827 (access & GNUNET_DISK_MAP_TYPE_WRITE))
1829 protect = PAGE_READWRITE;
1830 mapAccess = FILE_MAP_ALL_ACCESS;
1832 else if (access & GNUNET_DISK_MAP_TYPE_READ)
1834 protect = PAGE_READONLY;
1835 mapAccess = FILE_MAP_READ;
1837 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1839 protect = PAGE_READWRITE;
1840 mapAccess = FILE_MAP_WRITE;
1848 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1849 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1850 if ((*m)->h == INVALID_HANDLE_VALUE)
1852 SetErrnoFromWinError (GetLastError ());
1857 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1860 SetErrnoFromWinError (GetLastError ());
1861 CloseHandle ((*m)->h);
1870 if (access & GNUNET_DISK_MAP_TYPE_READ)
1872 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1874 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
1875 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1876 GNUNET_assert (NULL != (*m)->addr);
1877 if (MAP_FAILED == (*m)->addr)
1889 * @param h mapping handle
1890 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1893 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1900 return GNUNET_SYSERR;
1904 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
1905 if (ret != GNUNET_OK)
1906 SetErrnoFromWinError (GetLastError ());
1907 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
1909 ret = GNUNET_SYSERR;
1910 SetErrnoFromWinError (GetLastError ());
1913 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1921 * Write file changes to disk
1922 * @param h handle to an open file
1923 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1926 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1931 return GNUNET_SYSERR;
1937 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1938 if (ret != GNUNET_OK)
1939 SetErrnoFromWinError (GetLastError ());
1941 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
1942 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1944 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1950 /* Copyright Bob Byrnes <byrnes <at> curl.com>
1951 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
1953 /* Create a pipe, and return handles to the read and write ends,
1954 just like CreatePipe, but ensure that the write end permits
1955 FILE_READ_ATTRIBUTES access, on later versions of win32 where
1956 this is supported. This access is needed by NtQueryInformationFile,
1957 which is used to implement select and nonblocking writes.
1958 Note that the return value is either NO_ERROR or GetLastError,
1959 unlike CreatePipe, which returns a bool for success or failure. */
1961 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
1962 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
1963 DWORD dwReadMode, DWORD dwWriteMode)
1965 /* Default to error. */
1966 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
1968 HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE;
1970 /* Ensure that there is enough pipe buffer space for atomic writes. */
1971 if (psize < PIPE_BUF)
1974 char pipename[MAX_PATH];
1976 /* Retry CreateNamedPipe as long as the pipe name is in use.
1977 * Retrying will probably never be necessary, but we want
1978 * to be as robust as possible. */
1981 static volatile LONG pipe_unique_id;
1983 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
1984 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
1985 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
1987 /* Use CreateNamedPipe instead of CreatePipe, because the latter
1988 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
1989 * access, on versions of win32 earlier than WinXP SP2.
1990 * CreatePipe also stupidly creates a full duplex pipe, which is
1991 * a waste, since only a single direction is actually used.
1992 * It's important to only allow a single instance, to ensure that
1993 * the pipe was not created earlier by some other process, even if
1994 * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
1995 * because that is only available for Win2k SP2 and WinXP. */
1996 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
1997 psize, /* output buffer size */
1998 psize, /* input buffer size */
1999 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2001 if (read_pipe != INVALID_HANDLE_VALUE)
2003 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2007 DWORD err = GetLastError ();
2011 case ERROR_PIPE_BUSY:
2012 /* The pipe is already open with compatible parameters.
2013 * Pick a new name and retry. */
2014 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2016 case ERROR_ACCESS_DENIED:
2017 /* The pipe is already open with incompatible parameters.
2018 * Pick a new name and retry. */
2019 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2021 case ERROR_CALL_NOT_IMPLEMENTED:
2022 /* We are on an older Win9x platform without named pipes.
2023 * Return an anonymous pipe as the best approximation. */
2024 LOG (GNUNET_ERROR_TYPE_DEBUG,
2025 "CreateNamedPipe not implemented, resorting to "
2026 "CreatePipe: size = %lu\n", psize);
2027 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2029 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2034 err = GetLastError ();
2035 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2038 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2043 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2045 /* Open the named pipe for writing.
2046 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2047 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2048 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2049 0); /* handle to template file */
2051 if (write_pipe == INVALID_HANDLE_VALUE)
2054 DWORD err = GetLastError ();
2056 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2057 CloseHandle (read_pipe);
2060 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2062 *read_pipe_ptr = read_pipe;
2063 *write_pipe_ptr = write_pipe;
2070 * Creates an interprocess channel
2072 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2073 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2074 * @param inherit_read inherit the parent processes stdin (only for windows)
2075 * @param inherit_write inherit the parent processes stdout (only for windows)
2076 * @return handle to the new pipe, NULL on error
2078 struct GNUNET_DISK_PipeHandle *
2079 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2090 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2094 return GNUNET_DISK_pipe_from_fd (blocking_read,
2098 struct GNUNET_DISK_PipeHandle *p;
2099 struct GNUNET_DISK_FileHandle *fds;
2104 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2105 2 * sizeof (struct GNUNET_DISK_FileHandle));
2106 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2110 /* All pipes are overlapped. If you want them to block - just
2111 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2114 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2115 FILE_FLAG_OVERLAPPED,
2116 FILE_FLAG_OVERLAPPED);
2120 SetErrnoFromWinError (GetLastError ());
2123 if (!DuplicateHandle
2124 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2125 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2127 SetErrnoFromWinError (GetLastError ());
2128 CloseHandle (p->fd[0]->h);
2129 CloseHandle (p->fd[1]->h);
2133 CloseHandle (p->fd[0]->h);
2134 p->fd[0]->h = tmp_handle;
2136 if (!DuplicateHandle
2137 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2138 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2140 SetErrnoFromWinError (GetLastError ());
2141 CloseHandle (p->fd[0]->h);
2142 CloseHandle (p->fd[1]->h);
2146 CloseHandle (p->fd[1]->h);
2147 p->fd[1]->h = tmp_handle;
2149 p->fd[0]->type = GNUNET_PIPE;
2150 p->fd[1]->type = GNUNET_PIPE;
2152 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2153 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2154 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2155 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2157 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2158 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2160 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2161 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2169 * Creates a pipe object from a couple of file descriptors.
2170 * Useful for wrapping existing pipe FDs.
2172 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2173 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2174 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2176 * @return handle to the new pipe, NULL on error
2178 struct GNUNET_DISK_PipeHandle *
2179 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2181 struct GNUNET_DISK_PipeHandle *p;
2182 struct GNUNET_DISK_FileHandle *fds;
2184 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
2185 2 * sizeof (struct GNUNET_DISK_FileHandle));
2186 fds = (struct GNUNET_DISK_FileHandle *) &p[1];
2192 int eno = 0; /* make gcc happy */
2194 p->fd[0]->fd = fd[0];
2195 p->fd[1]->fd = fd[1];
2201 flags = fcntl (fd[0], F_GETFL);
2202 flags |= O_NONBLOCK;
2203 if (0 > fcntl (fd[0], F_SETFL, flags))
2209 flags = fcntl (fd[0], F_GETFD);
2210 flags |= FD_CLOEXEC;
2211 if (0 > fcntl (fd[0], F_SETFD, flags))
2220 if (!blocking_write)
2222 flags = fcntl (fd[1], F_GETFL);
2223 flags |= O_NONBLOCK;
2224 if (0 > fcntl (fd[1], F_SETFL, flags))
2230 flags = fcntl (fd[1], F_GETFD);
2231 flags |= FD_CLOEXEC;
2232 if (0 > fcntl (fd[1], F_SETFD, flags))
2241 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2242 if (p->fd[0]->fd >= 0)
2243 GNUNET_break (0 == close (p->fd[0]->fd));
2244 if (p->fd[1]->fd >= 0)
2245 GNUNET_break (0 == close (p->fd[1]->fd));
2252 p->fd[0]->h = _get_osfhandle (fd[0]);
2254 p->fd[0]->h = INVALID_HANDLE_VALUE;
2256 p->fd[1]->h = _get_osfhandle (fd[1]);
2258 p->fd[1]->h = INVALID_HANDLE_VALUE;
2260 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2262 p->fd[0]->type = GNUNET_PIPE;
2263 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2264 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2265 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2266 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2269 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2271 p->fd[1]->type = GNUNET_PIPE;
2272 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2273 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2274 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2275 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2283 * Closes an interprocess channel
2285 * @param p pipe to close
2286 * @param end which end of the pipe to close
2287 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2290 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2291 enum GNUNET_DISK_PipeEnd end)
2293 int ret = GNUNET_OK;
2297 if (end == GNUNET_DISK_PIPE_END_READ)
2299 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2301 if (!CloseHandle (p->fd[0]->h))
2303 SetErrnoFromWinError (GetLastError ());
2304 ret = GNUNET_SYSERR;
2306 GNUNET_free (p->fd[0]->oOverlapRead);
2307 GNUNET_free (p->fd[0]->oOverlapWrite);
2308 p->fd[0]->h = INVALID_HANDLE_VALUE;
2311 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2313 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2315 if (!CloseHandle (p->fd[1]->h))
2317 SetErrnoFromWinError (GetLastError ());
2318 ret = GNUNET_SYSERR;
2320 GNUNET_free (p->fd[1]->oOverlapRead);
2321 GNUNET_free (p->fd[1]->oOverlapWrite);
2322 p->fd[1]->h = INVALID_HANDLE_VALUE;
2328 if (end == GNUNET_DISK_PIPE_END_READ)
2330 if (0 != close (p->fd[0]->fd))
2332 ret = GNUNET_SYSERR;
2337 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2339 if (0 != close (p->fd[1]->fd))
2341 ret = GNUNET_SYSERR;
2353 * Closes an interprocess channel
2355 * @param p pipe to close
2356 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2359 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2361 int ret = GNUNET_OK;
2365 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2367 if (!CloseHandle (p->fd[0]->h))
2369 SetErrnoFromWinError (GetLastError ());
2370 ret = GNUNET_SYSERR;
2372 GNUNET_free (p->fd[0]->oOverlapRead);
2373 GNUNET_free (p->fd[0]->oOverlapWrite);
2375 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2377 if (!CloseHandle (p->fd[1]->h))
2379 SetErrnoFromWinError (GetLastError ());
2380 ret = GNUNET_SYSERR;
2382 GNUNET_free (p->fd[1]->oOverlapRead);
2383 GNUNET_free (p->fd[1]->oOverlapWrite);
2388 if (p->fd[0]->fd != -1)
2390 if (0 != close (p->fd[0]->fd))
2392 ret = GNUNET_SYSERR;
2397 if (p->fd[1]->fd != -1)
2399 if (0 != close (p->fd[1]->fd))
2401 ret = GNUNET_SYSERR;
2413 * Get the handle to a particular pipe end
2416 * @param n end to access
2417 * @return handle for the respective end
2419 const struct GNUNET_DISK_FileHandle *
2420 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2421 enum GNUNET_DISK_PipeEnd n)
2425 case GNUNET_DISK_PIPE_END_READ:
2426 case GNUNET_DISK_PIPE_END_WRITE:
2436 * Retrieve OS file handle
2438 * @param fh GNUnet file descriptor
2439 * @param dst destination buffer
2440 * @param dst_len length of dst
2441 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2444 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2445 void *dst, size_t dst_len)
2448 if (dst_len < sizeof (HANDLE))
2449 return GNUNET_SYSERR;
2450 *((HANDLE *) dst) = fh->h;
2452 if (dst_len < sizeof (int))
2453 return GNUNET_SYSERR;
2454 *((int *) dst) = fh->fd;