2 This file is part of GNUnet.
3 (C) 2001--2013 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 3, 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_directories.h"
30 #include "gnunet_util_lib.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
35 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
37 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
40 * Block size for IO for copying files.
42 #define COPY_BLK_SIZE 65536
44 #include <sys/types.h>
49 #include <sys/param.h>
52 #include <sys/mount.h>
54 #if HAVE_SYS_STATVFS_H
55 #include <sys/statvfs.h>
59 #define _IFMT 0170000 /* type of file */
60 #define _IFLNK 0120000 /* symbolic link */
61 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
66 * Handle used to manage a pipe.
68 struct GNUNET_DISK_PipeHandle
71 * File descriptors for the pipe.
72 * One or both of them could be NULL.
74 struct GNUNET_DISK_FileHandle *fd[2];
79 * Closure for the recursion to determine the file size
82 struct GetFileSizeData
85 * Set to the total file size.
90 * GNUNET_YES if symbolic links should be included.
92 int include_sym_links;
95 * GNUNET_YES if mode is file-only (return total == -1 for directories).
103 * Translate GNUnet-internal permission bitmap to UNIX file
104 * access permission bitmap.
106 * @param perm file permissions, GNUnet style
107 * @return file permissions, UNIX style
110 translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
115 if (perm & GNUNET_DISK_PERM_USER_READ)
117 if (perm & GNUNET_DISK_PERM_USER_WRITE)
119 if (perm & GNUNET_DISK_PERM_USER_EXEC)
121 if (perm & GNUNET_DISK_PERM_GROUP_READ)
123 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
125 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
127 if (perm & GNUNET_DISK_PERM_OTHER_READ)
129 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
131 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
140 * Iterate over all files in the given directory and
141 * accumulate their size.
143 * @param cls closure of type "struct GetFileSizeData"
144 * @param fn current filename we are looking at
145 * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK
148 getSizeRec (void *cls, const char *fn)
150 struct GetFileSizeData *gfsd = cls;
159 if (0 != STAT64 (fn, &buf))
161 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
162 return GNUNET_SYSERR;
165 if (0 != STAT (fn, &buf))
167 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
168 return GNUNET_SYSERR;
171 if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
174 return GNUNET_SYSERR;
176 if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
177 gfsd->total += buf.st_size;
178 if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
179 ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
181 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
182 return GNUNET_SYSERR;
189 * Checks whether a handle is invalid
191 * @param h handle to check
192 * @return GNUNET_YES if invalid, GNUNET_NO if valid
195 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
198 return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
200 return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
205 * Get the size of an open file.
207 * @param fh open file handle
208 * @param size where to write size of the file
209 * @return GNUNET_OK on success, GNUNET_SYSERR on error
212 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
218 b = GetFileSizeEx (fh->h, &li);
221 SetErrnoFromWinError (GetLastError ());
222 return GNUNET_SYSERR;
224 *size = (OFF_T) li.QuadPart;
228 if (0 != FSTAT (fh->fd, &sbuf))
229 return GNUNET_SYSERR;
230 *size = sbuf.st_size;
237 * Move the read/write pointer in a file
239 * @param h handle of an open file
240 * @param offset position to move to
241 * @param whence specification to which position the offset parameter relates to
242 * @return the new position on success, GNUNET_SYSERR otherwise
245 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset,
246 enum GNUNET_DISK_Seek whence)
251 return GNUNET_SYSERR;
256 LARGE_INTEGER new_pos;
259 static DWORD t[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
260 li.QuadPart = offset;
262 b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
265 SetErrnoFromWinError (GetLastError ());
266 return GNUNET_SYSERR;
268 return (OFF_T) new_pos.QuadPart;
270 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
272 return lseek (h->fd, offset, t[whence]);
278 * Get the size of the file (or directory) of the given file (in
281 * @param filename name of the file or directory
282 * @param size set to the size of the file (or,
283 * in the case of directories, the sum
284 * of all sizes of files in the directory)
285 * @param include_symbolic_links should symbolic links be
287 * @param single_file_mode GNUNET_YES to only get size of one file
288 * and return GNUNET_SYSERR for directories.
289 * @return GNUNET_SYSERR on error, GNUNET_OK on success
292 GNUNET_DISK_file_size (const char *filename, uint64_t * size,
293 int include_symbolic_links, int single_file_mode)
295 struct GetFileSizeData gfsd;
298 GNUNET_assert (size != NULL);
300 gfsd.include_sym_links = include_symbolic_links;
301 gfsd.single_file_mode = single_file_mode;
302 ret = getSizeRec (&gfsd, filename);
309 * Obtain some unique identifiers for the given file
310 * that can be used to identify it in the local system.
311 * This function is used between GNUnet processes to
312 * quickly check if two files with the same absolute path
313 * are actually identical. The two processes represent
314 * the same peer but may communicate over the network
315 * (and the file may be on an NFS volume). This function
316 * may not be supported on all operating systems.
318 * @param filename name of the file
319 * @param dev set to the device ID
320 * @param ino set to the inode ID
321 * @return #GNUNET_OK on success
324 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
329 // FIXME NILS: test this
330 struct GNUNET_DISK_FileHandle *fh;
331 BY_HANDLE_FILE_INFORMATION info;
334 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
336 return GNUNET_SYSERR;
337 succ = GetFileInformationByHandle (fh->h, &info);
338 GNUNET_DISK_file_close (fh);
341 return GNUNET_SYSERR;
343 *dev = info.dwVolumeSerialNumber;
344 *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
351 if (0 != stat (filename, &sbuf))
353 return GNUNET_SYSERR;
355 *ino = (uint64_t) sbuf.st_ino;
364 if (0 != statvfs (filename, &fbuf))
366 return GNUNET_SYSERR;
368 *dev = (uint64_t) fbuf.f_fsid;
374 if (0 != statfs (filename, &fbuf))
376 return GNUNET_SYSERR;
378 *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
379 ((uint64_t) fbuf.f_fsid.val[1]);
384 #endif /* !WINDOWS */
390 * Create the name for a temporary file or directory from a template.
392 * @param t template (without XXXXX or "/tmp/")
393 * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
396 mktemp_name (const char *t)
402 if ((t[0] != '/') && (t[0] != '\\')
404 && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
408 /* FIXME: This uses system codepage on W32, not UTF-8 */
409 tmpdir = getenv ("TMPDIR");
411 tmpdir = getenv ("TMP");
413 tmpdir = getenv ("TEMP");
416 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
420 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
423 fn = (char *) GNUNET_malloc (MAX_PATH + 1);
424 if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
447 tfn = GNUNET_strdup (fn);
448 random_fn = _mktemp (tfn);
449 if (NULL == random_fn)
454 /* FIXME: assume fn to be UTF-8-encoded and do the right thing */
455 if (0 == CreateDirectoryA (tfn, NULL))
457 DWORD error = GetLastError ();
459 if (ERROR_ALREADY_EXISTS == error)
471 * Create an (empty) temporary directory on disk. If the given name is not
472 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
473 * 6 random characters will be appended to the name to create a unique
476 * @param t component to use for the name;
477 * does NOT contain "XXXXXX" or "/tmp/".
478 * @return NULL on error, otherwise name of fresh
479 * file on disk in directory for temporary files
482 GNUNET_DISK_mkdtemp (const char *t)
486 fn = mktemp_name (t);
487 if (fn != mkdtemp (fn))
489 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
498 * Move a file out of the way (create a backup) by
499 * renaming it to "orig.NUM~" where NUM is the smallest
500 * number that is not used yet.
502 * @param fil name of the file to back up
505 GNUNET_DISK_file_backup (const char *fil)
511 slen = strlen (fil) + 20;
512 target = GNUNET_malloc (slen);
516 GNUNET_snprintf (target, slen,
520 } while (0 == access (target, F_OK));
521 if (0 != rename (fil, target))
522 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
525 GNUNET_free (target);
530 * Create an (empty) temporary file on disk. If the given name is not
531 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
532 * 6 random characters will be appended to the name to create a unique
535 * @param t component to use for the name;
536 * does NOT contain "XXXXXX" or "/tmp/".
537 * @return NULL on error, otherwise name of fresh
538 * file on disk in directory for temporary files
541 GNUNET_DISK_mktemp (const char *t)
546 fn = mktemp_name (t);
547 if (-1 == (fd = mkstemp (fn)))
549 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
554 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
560 * Test if @a fil is a directory and listable. Optionally, also check if the
561 * directory is readable. Will not print an error message if the directory does
562 * not exist. Will log errors if #GNUNET_SYSERR is returned (i.e., a file exists
563 * with the same name).
565 * @param fil filename to test
566 * @param is_readable GNUNET_YES to additionally check if @a fil is readable;
567 * #GNUNET_NO to disable this check
568 * @return #GNUNET_YES if yes, #GNUNET_NO if not; #GNUNET_SYSERR if it
569 * does not exist or stat'ed
572 GNUNET_DISK_directory_test (const char *fil, int is_readable)
574 struct stat filestat;
577 ret = STAT (fil, &filestat);
581 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
582 return GNUNET_SYSERR;
584 if (!S_ISDIR (filestat.st_mode))
586 LOG (GNUNET_ERROR_TYPE_DEBUG,
587 "A file already exits with the same name %s\n", fil);
590 if (GNUNET_YES == is_readable)
591 ret = ACCESS (fil, R_OK | X_OK);
593 ret = ACCESS (fil, X_OK);
596 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
604 * Check that fil corresponds to a filename
605 * (of a file that exists and that is not a directory).
607 * @param fil filename to check
608 * @return #GNUNET_YES if yes, GNUNET_NO if not a file, #GNUNET_SYSERR if something
609 * else (will print an error message in that case, too).
612 GNUNET_DISK_file_test (const char *fil)
614 struct stat filestat;
618 rdir = GNUNET_STRINGS_filename_expand (fil);
620 return GNUNET_SYSERR;
622 ret = STAT (rdir, &filestat);
627 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
629 return GNUNET_SYSERR;
634 if (!S_ISREG (filestat.st_mode))
639 if (ACCESS (rdir, F_OK) < 0)
641 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
643 return GNUNET_SYSERR;
651 * Implementation of "mkdir -p"
653 * @param dir the directory to create
654 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
657 GNUNET_DISK_directory_create (const char *dir)
665 rdir = GNUNET_STRINGS_filename_expand (dir);
667 return GNUNET_SYSERR;
671 pos = 1; /* skip heading '/' */
673 /* Local or Network path? */
674 if (strncmp (rdir, "\\\\", 2) == 0)
679 if (rdir[pos] == '\\')
689 pos = 3; /* strlen("C:\\") */
692 /* Check which low level directories already exist */
694 rdir[len] = DIR_SEPARATOR;
697 if (DIR_SEPARATOR == rdir[pos2])
700 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
701 if (GNUNET_NO == ret)
704 return GNUNET_SYSERR;
706 rdir[pos2] = DIR_SEPARATOR;
707 if (GNUNET_YES == ret)
718 /* Start creating directories */
721 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
724 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
725 if (GNUNET_NO == ret)
728 return GNUNET_SYSERR;
730 if (GNUNET_SYSERR == ret)
733 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
735 wchar_t wrdir[MAX_PATH + 1];
736 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
737 ret = !CreateDirectoryW (wrdir, NULL);
741 if ((ret != 0) && (errno != EEXIST))
743 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
745 return GNUNET_SYSERR;
748 rdir[pos] = DIR_SEPARATOR;
758 * Create the directory structure for storing
761 * @param filename name of a file in the directory
762 * @returns #GNUNET_OK on success,
763 * #GNUNET_SYSERR on failure,
764 * #GNUNET_NO if the directory
765 * exists but is not writeable for us
768 GNUNET_DISK_directory_create_for_file (const char *filename)
774 rdir = GNUNET_STRINGS_filename_expand (filename);
776 return GNUNET_SYSERR;
778 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
781 ret = GNUNET_DISK_directory_create (rdir);
782 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
790 * Read the contents of a binary file into a buffer.
792 * @param h handle to an open file
793 * @param result the buffer to write the result to
794 * @param len the maximum number of bytes to read
795 * @return the number of bytes read on success, #GNUNET_SYSERR on failure
798 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
805 return GNUNET_SYSERR;
811 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
813 if (!ReadFile (h->h, result, len, &bytes_read, NULL))
815 SetErrnoFromWinError (GetLastError ());
816 return GNUNET_SYSERR;
821 if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
823 if (GetLastError () != ERROR_IO_PENDING)
825 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
826 SetErrnoFromWinError (GetLastError ());
827 return GNUNET_SYSERR;
829 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
830 GetOverlappedResult (h->h, h->oOverlapRead, &bytes_read, TRUE);
832 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytes_read);
836 return read (h->fd, result, len);
842 * Read the contents of a binary file into a buffer.
843 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
844 * when no data can be read).
846 * @param h handle to an open file
847 * @param result the buffer to write the result to
848 * @param len the maximum number of bytes to read
849 * @return the number of bytes read on success, #GNUNET_SYSERR on failure
852 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
859 return GNUNET_SYSERR;
865 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
867 if (!ReadFile (h->h, result, len, &bytes_read, NULL))
869 SetErrnoFromWinError (GetLastError ());
870 return GNUNET_SYSERR;
875 if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
877 if (GetLastError () != ERROR_IO_PENDING)
879 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
880 SetErrnoFromWinError (GetLastError ());
881 return GNUNET_SYSERR;
885 LOG (GNUNET_ERROR_TYPE_DEBUG,
886 "ReadFile() queued a read, cancelling\n");
889 return GNUNET_SYSERR;
892 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytes_read);
899 /* set to non-blocking, read, then set back */
900 flags = fcntl (h->fd, F_GETFL);
901 if (0 == (flags & O_NONBLOCK))
902 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
903 ret = read (h->fd, result, len);
904 if (0 == (flags & O_NONBLOCK))
907 (void) fcntl (h->fd, F_SETFL, flags);
916 * Read the contents of a binary file into a buffer.
918 * @param fn file name
919 * @param result the buffer to write the result to
920 * @param len the maximum number of bytes to read
921 * @return number of bytes read, #GNUNET_SYSERR on failure
924 GNUNET_DISK_fn_read (const char *fn,
928 struct GNUNET_DISK_FileHandle *fh;
931 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
933 return GNUNET_SYSERR;
934 ret = GNUNET_DISK_file_read (fh, result, len);
935 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
942 * Write a buffer to a file.
944 * @param h handle to open file
945 * @param buffer the data to write
946 * @param n number of bytes to write
947 * @return number of bytes written on success, #GNUNET_SYSERR on error
950 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
951 const void *buffer, size_t n)
956 return GNUNET_SYSERR;
962 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
964 if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
966 SetErrnoFromWinError (GetLastError ());
967 return GNUNET_SYSERR;
972 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
973 if (!WriteFile (h->h, buffer, n, &bytes_written, h->oOverlapWrite))
975 if (GetLastError () != ERROR_IO_PENDING)
977 SetErrnoFromWinError (GetLastError ());
978 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
980 return GNUNET_SYSERR;
982 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
983 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytes_written, TRUE))
985 SetErrnoFromWinError (GetLastError ());
986 LOG (GNUNET_ERROR_TYPE_DEBUG,
987 "Error getting overlapped result while writing to pipe: %u\n",
989 return GNUNET_SYSERR;
995 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
997 LOG (GNUNET_ERROR_TYPE_DEBUG,
998 "Error getting control overlapped result while writing to pipe: %u\n",
1003 LOG (GNUNET_ERROR_TYPE_DEBUG,
1004 "Wrote %u bytes (ovr says %u), picking the greatest\n",
1005 bytes_written, ovr);
1008 if (bytes_written == 0)
1012 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytes_written);
1014 return GNUNET_SYSERR;
1017 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytes_written);
1019 return bytes_written;
1021 return write (h->fd, buffer, n);
1027 * Write a buffer to a file, blocking, if necessary.
1029 * @param h handle to open file
1030 * @param buffer the data to write
1031 * @param n number of bytes to write
1032 * @return number of bytes written on success, #GNUNET_SYSERR on error
1035 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1042 return GNUNET_SYSERR;
1046 DWORD bytes_written;
1047 /* We do a non-overlapped write, which is as blocking as it gets */
1048 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1049 if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1051 SetErrnoFromWinError (GetLastError ());
1052 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1054 return GNUNET_SYSERR;
1056 if (bytes_written == 0 && n > 0)
1058 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1059 WaitForSingleObject (h->h, INFINITE);
1060 if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1062 SetErrnoFromWinError (GetLastError ());
1063 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1065 return GNUNET_SYSERR;
1068 LOG (GNUNET_ERROR_TYPE_DEBUG,
1071 return bytes_written;
1076 /* set to blocking, write, then set back */
1077 flags = fcntl (h->fd, F_GETFL);
1078 if (0 != (flags & O_NONBLOCK))
1079 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1080 ret = write (h->fd, buffer, n);
1081 if (0 == (flags & O_NONBLOCK))
1082 (void) fcntl (h->fd, F_SETFL, flags);
1089 * Write a buffer to a file. If the file is longer than the
1090 * number of bytes that will be written, it will be truncated.
1092 * @param fn file name
1093 * @param buffer the data to write
1094 * @param n number of bytes to write
1095 * @param mode file permissions
1096 * @return number of bytes written on success, #GNUNET_SYSERR on error
1099 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1100 enum GNUNET_DISK_AccessPermissions mode)
1102 struct GNUNET_DISK_FileHandle *fh;
1105 fh = GNUNET_DISK_file_open (fn,
1106 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1107 | GNUNET_DISK_OPEN_CREATE, mode);
1109 return GNUNET_SYSERR;
1110 ret = GNUNET_DISK_file_write (fh, buffer, n);
1111 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1117 * Scan a directory for files.
1119 * @param dir_name the name of the directory
1120 * @param callback the method to call for each file,
1121 * can be NULL, in that case, we only count
1122 * @param callback_cls closure for @a callback
1123 * @return the number of files found, #GNUNET_SYSERR on error or
1124 * ieration aborted by callback returning #GNUNET_SYSERR
1127 GNUNET_DISK_directory_scan (const char *dir_name,
1128 GNUNET_FileNameCallback callback,
1132 struct dirent *finfo;
1138 unsigned int name_len;
1139 unsigned int n_size;
1141 GNUNET_assert (dir_name != NULL);
1142 dname = GNUNET_STRINGS_filename_expand (dir_name);
1144 return GNUNET_SYSERR;
1145 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1146 dname[strlen (dname) - 1] = '\0';
1147 if (0 != STAT (dname, &istat))
1149 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1150 GNUNET_free (dname);
1151 return GNUNET_SYSERR;
1153 if (!S_ISDIR (istat.st_mode))
1155 LOG (GNUNET_ERROR_TYPE_WARNING,
1156 _("Expected `%s' to be a directory!\n"),
1158 GNUNET_free (dname);
1159 return GNUNET_SYSERR;
1162 dinfo = OPENDIR (dname);
1163 if ((errno == EACCES) || (dinfo == NULL))
1165 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1168 GNUNET_free (dname);
1169 return GNUNET_SYSERR;
1172 n_size = strlen (dname) + name_len + 2;
1173 name = GNUNET_malloc (n_size);
1174 while ((finfo = READDIR (dinfo)) != NULL)
1176 if ((0 == strcmp (finfo->d_name, ".")) ||
1177 (0 == strcmp (finfo->d_name, "..")))
1179 if (callback != NULL)
1181 if (name_len < strlen (finfo->d_name))
1184 name_len = strlen (finfo->d_name);
1185 n_size = strlen (dname) + name_len + 2;
1186 name = GNUNET_malloc (n_size);
1188 /* dname can end in "/" only if dname == "/";
1189 * if dname does not end in "/", we need to add
1190 * a "/" (otherwise, we must not!) */
1191 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1192 (strcmp (dname, DIR_SEPARATOR_STR) ==
1193 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1194 ret = callback (callback_cls, name);
1195 if (GNUNET_OK != ret)
1199 GNUNET_free (dname);
1200 if (GNUNET_NO == ret)
1202 return GNUNET_SYSERR;
1209 GNUNET_free (dname);
1215 * Opaque handle used for iterating over a directory.
1217 struct GNUNET_DISK_DirectoryIterator
1221 * Function to call on directory entries.
1223 GNUNET_DISK_DirectoryIteratorCallback callback;
1226 * Closure for callback.
1231 * Reference to directory.
1241 * Next filename to process.
1248 enum GNUNET_SCHEDULER_Priority priority;
1254 * Task used by the directory iterator.
1257 directory_iterator_task (void *cls,
1258 const struct GNUNET_SCHEDULER_TaskContext *tc)
1260 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1263 name = iter->next_name;
1264 GNUNET_assert (name != NULL);
1265 iter->next_name = NULL;
1266 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1272 * This function must be called during the DiskIteratorCallback
1273 * (exactly once) to schedule the task to process the next
1274 * filename in the directory (if there is one).
1276 * @param iter opaque handle for the iterator
1277 * @param can set to GNUNET_YES to terminate the iteration early
1278 * @return GNUNET_YES if iteration will continue,
1279 * GNUNET_NO if this was the last entry (and iteration is complete),
1280 * GNUNET_SYSERR if abort was YES
1283 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1286 struct dirent *finfo;
1288 GNUNET_assert (iter->next_name == NULL);
1289 if (can == GNUNET_YES)
1291 CLOSEDIR (iter->directory);
1292 GNUNET_free (iter->dirname);
1294 return GNUNET_SYSERR;
1296 while (NULL != (finfo = READDIR (iter->directory)))
1298 if ((0 == strcmp (finfo->d_name, ".")) ||
1299 (0 == strcmp (finfo->d_name, "..")))
1301 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1302 DIR_SEPARATOR_STR, finfo->d_name);
1307 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1310 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1317 * Scan a directory for files using the scheduler to run a task for
1318 * each entry. The name of the directory must be expanded first (!).
1319 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1320 * may provide a simpler API.
1322 * @param prio priority to use
1323 * @param dir_name the name of the directory
1324 * @param callback the method to call for each file
1325 * @param callback_cls closure for callback
1326 * @return GNUNET_YES if directory is not empty and 'callback'
1327 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1330 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1331 const char *dir_name,
1332 GNUNET_DISK_DirectoryIteratorCallback
1333 callback, void *callback_cls)
1335 struct GNUNET_DISK_DirectoryIterator *di;
1337 di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
1338 di->callback = callback;
1339 di->callback_cls = callback_cls;
1340 di->directory = OPENDIR (dir_name);
1341 if (di->directory == NULL)
1344 callback (callback_cls, NULL, NULL, NULL);
1345 return GNUNET_SYSERR;
1347 di->dirname = GNUNET_strdup (dir_name);
1348 di->priority = prio;
1349 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1354 * Function that removes the given directory by calling
1355 * "GNUNET_DISK_directory_remove".
1357 * @param unused not used
1358 * @param fn directory to remove
1362 remove_helper (void *unused, const char *fn)
1364 (void) GNUNET_DISK_directory_remove (fn);
1370 * Remove all files in a directory (rm -rf). Call with
1374 * @param filename the file to remove
1375 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1378 GNUNET_DISK_directory_remove (const char *filename)
1382 if (0 != LSTAT (filename, &istat))
1383 return GNUNET_NO; /* file may not exist... */
1384 (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1385 if (UNLINK (filename) == 0)
1387 if ((errno != EISDIR) &&
1388 /* EISDIR is not sufficient in all cases, e.g.
1389 * sticky /tmp directory may result in EPERM on BSD.
1390 * So we also explicitly check "isDirectory" */
1391 (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1393 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1394 return GNUNET_SYSERR;
1396 if (GNUNET_SYSERR ==
1397 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1398 return GNUNET_SYSERR;
1399 if (0 != RMDIR (filename))
1401 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1402 return GNUNET_SYSERR;
1411 * @param src file to copy
1412 * @param dst destination file name
1413 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1416 GNUNET_DISK_file_copy (const char *src,
1423 struct GNUNET_DISK_FileHandle *in;
1424 struct GNUNET_DISK_FileHandle *out;
1426 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1427 return GNUNET_SYSERR;
1429 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1430 GNUNET_DISK_PERM_NONE);
1432 return GNUNET_SYSERR;
1434 GNUNET_DISK_file_open (dst,
1435 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1436 GNUNET_DISK_OPEN_FAILIFEXISTS,
1437 GNUNET_DISK_PERM_USER_READ |
1438 GNUNET_DISK_PERM_USER_WRITE |
1439 GNUNET_DISK_PERM_GROUP_READ |
1440 GNUNET_DISK_PERM_GROUP_WRITE);
1443 GNUNET_DISK_file_close (in);
1444 return GNUNET_SYSERR;
1446 buf = GNUNET_malloc (COPY_BLK_SIZE);
1449 len = COPY_BLK_SIZE;
1450 if (len > size - pos)
1452 if (len != GNUNET_DISK_file_read (in, buf, len))
1454 if (len != GNUNET_DISK_file_write (out, buf, len))
1459 GNUNET_DISK_file_close (in);
1460 GNUNET_DISK_file_close (out);
1464 GNUNET_DISK_file_close (in);
1465 GNUNET_DISK_file_close (out);
1466 return GNUNET_SYSERR;
1471 * @brief Removes special characters as ':' from a filename.
1472 * @param fn the filename to canonicalize
1475 GNUNET_DISK_filename_canonicalize (char *fn)
1485 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1486 c == '<' || c == '>' || c == '|')
1498 * @brief Change owner of a file
1500 * @param filename name of file to change the owner of
1501 * @param user name of the new owner
1502 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1505 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1510 pws = getpwnam (user);
1513 LOG (GNUNET_ERROR_TYPE_ERROR,
1514 _("Cannot obtain information about user `%s': %s\n"), user,
1516 return GNUNET_SYSERR;
1518 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1519 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1526 * Lock a part of a file
1527 * @param fh file handle
1528 * @param lock_start absolute position from where to lock
1529 * @param lock_end absolute position until where to lock
1530 * @param excl GNUNET_YES for an exclusive lock
1531 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1534 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lock_start,
1535 OFF_T lock_end, int excl)
1540 return GNUNET_SYSERR;
1546 memset (&fl, 0, sizeof (struct flock));
1547 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1548 fl.l_whence = SEEK_SET;
1549 fl.l_start = lock_start;
1550 fl.l_len = lock_end;
1552 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1555 OFF_T diff = lock_end - lock_start;
1556 DWORD diff_low, diff_high;
1557 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1558 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1560 memset (&o, 0, sizeof (OVERLAPPED));
1561 o.Offset = (DWORD) (lock_start & 0xFFFFFFFF);;
1562 o.OffsetHigh = (DWORD) (((lock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1565 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1566 0, diff_low, diff_high, &o))
1568 SetErrnoFromWinError (GetLastError ());
1569 return GNUNET_SYSERR;
1578 * Unlock a part of a file
1579 * @param fh file handle
1580 * @param unlock_start absolute position from where to unlock
1581 * @param unlock_end absolute position until where to unlock
1582 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1585 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlock_start,
1591 return GNUNET_SYSERR;
1597 memset (&fl, 0, sizeof (struct flock));
1598 fl.l_type = F_UNLCK;
1599 fl.l_whence = SEEK_SET;
1600 fl.l_start = unlock_start;
1601 fl.l_len = unlock_end;
1603 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1606 OFF_T diff = unlock_end - unlock_start;
1607 DWORD diff_low, diff_high;
1608 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1609 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1611 memset (&o, 0, sizeof (OVERLAPPED));
1612 o.Offset = (DWORD) (unlock_start & 0xFFFFFFFF);;
1613 o.OffsetHigh = (DWORD) (((unlock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1615 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1617 SetErrnoFromWinError (GetLastError ());
1618 return GNUNET_SYSERR;
1627 * Open a file. Note that the access permissions will only be
1628 * used if a new file is created and if the underlying operating
1629 * system supports the given permissions.
1631 * @param fn file name to be opened
1632 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1633 * @param perm permissions for the newly created file, use
1634 * #GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1635 * call (because of flags)
1636 * @return IO handle on success, NULL on error
1638 struct GNUNET_DISK_FileHandle *
1639 GNUNET_DISK_file_open (const char *fn,
1640 enum GNUNET_DISK_OpenFlags flags,
1641 enum GNUNET_DISK_AccessPermissions perm)
1644 struct GNUNET_DISK_FileHandle *ret;
1650 wchar_t wexpfn[MAX_PATH + 1];
1657 expfn = GNUNET_STRINGS_filename_expand (fn);
1662 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1663 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1664 else if (flags & GNUNET_DISK_OPEN_READ)
1666 else if (flags & GNUNET_DISK_OPEN_WRITE)
1671 GNUNET_free (expfn);
1674 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1675 oflags |= (O_CREAT | O_EXCL);
1676 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1678 if (flags & GNUNET_DISK_OPEN_APPEND)
1680 if (flags & GNUNET_DISK_OPEN_CREATE)
1682 (void) GNUNET_DISK_directory_create_for_file (expfn);
1684 mode = translate_unix_perms (perm);
1687 fd = open (expfn, oflags
1691 | O_LARGEFILE, mode);
1694 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1695 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1697 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1698 GNUNET_free (expfn);
1705 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1706 access = FILE_READ_DATA | FILE_WRITE_DATA;
1707 else if (flags & GNUNET_DISK_OPEN_READ)
1708 access = FILE_READ_DATA;
1709 else if (flags & GNUNET_DISK_OPEN_WRITE)
1710 access = FILE_WRITE_DATA;
1712 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1716 else if (flags & GNUNET_DISK_OPEN_CREATE)
1718 (void) GNUNET_DISK_directory_create_for_file (expfn);
1719 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1720 disp = CREATE_ALWAYS;
1724 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1726 disp = TRUNCATE_EXISTING;
1730 disp = OPEN_EXISTING;
1733 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1734 h = CreateFileW (wexpfn, access,
1735 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1736 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1738 h = INVALID_HANDLE_VALUE;
1739 if (h == INVALID_HANDLE_VALUE)
1742 SetErrnoFromWinError (GetLastError ());
1744 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1745 GNUNET_free (expfn);
1750 if (flags & GNUNET_DISK_OPEN_APPEND)
1751 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1753 SetErrnoFromWinError (GetLastError ());
1754 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1756 GNUNET_free (expfn);
1761 ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1764 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1768 GNUNET_free (expfn);
1774 * Close an open file
1775 * @param h file handle
1776 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1779 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1785 return GNUNET_SYSERR;
1791 if (!CloseHandle (h->h))
1793 SetErrnoFromWinError (GetLastError ());
1794 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1795 ret = GNUNET_SYSERR;
1797 if (h->oOverlapRead)
1799 if (!CloseHandle (h->oOverlapRead->hEvent))
1801 SetErrnoFromWinError (GetLastError ());
1802 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1803 ret = GNUNET_SYSERR;
1805 GNUNET_free (h->oOverlapRead);
1807 if (h->oOverlapWrite)
1809 if (!CloseHandle (h->oOverlapWrite->hEvent))
1811 SetErrnoFromWinError (GetLastError ());
1812 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1813 ret = GNUNET_SYSERR;
1815 GNUNET_free (h->oOverlapWrite);
1818 if (close (h->fd) != 0)
1820 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1821 ret = GNUNET_SYSERR;
1830 * Get a GNUnet file handle from a W32 handle.
1832 * @param handle native handle
1833 * @return GNUnet file handle corresponding to the W32 handle
1835 struct GNUNET_DISK_FileHandle *
1836 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1838 struct GNUNET_DISK_FileHandle *fh;
1841 enum GNUNET_FILE_Type ftype;
1843 dwret = GetFileType (osfh);
1846 case FILE_TYPE_DISK:
1847 ftype = GNUNET_DISK_HANLDE_TYPE_FILE;
1849 case FILE_TYPE_PIPE:
1850 ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1856 fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1860 if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1863 * Note that we can't make it overlapped if it isn't already.
1864 * (ReOpenFile() is only available in 2003/Vista).
1865 * The process that opened this file in the first place (usually a parent
1866 * process, if this is stdin/stdout/stderr) must make it overlapped,
1867 * otherwise we're screwed, as selecting on non-overlapped handle
1870 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1871 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1872 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1873 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1881 * Get a handle from a native integer FD.
1883 * @param fno native integer file descriptor
1884 * @return file handle corresponding to the descriptor, NULL on error
1886 struct GNUNET_DISK_FileHandle *
1887 GNUNET_DISK_get_handle_from_int_fd (int fno)
1889 struct GNUNET_DISK_FileHandle *fh;
1891 if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1893 return NULL; /* invalid FD */
1896 fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1902 osfh = _get_osfhandle (fno);
1903 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1906 fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1914 * Get a handle from a native streaming FD.
1916 * @param fd native streaming file descriptor
1917 * @return file handle corresponding to the descriptor
1919 struct GNUNET_DISK_FileHandle *
1920 GNUNET_DISK_get_handle_from_native (FILE *fd)
1928 return GNUNET_DISK_get_handle_from_int_fd (fno);
1933 * Construct full path to a file inside of the private
1934 * directory used by GNUnet. Also creates the corresponding
1935 * directory. If the resulting name is supposed to be
1936 * a directory, end the last argument in '/' (or pass
1937 * DIR_SEPARATOR_STR as the last argument before NULL).
1939 * @param cfg configuration to use (determines HOME)
1940 * @param service_name name of the service
1941 * @param ... is NULL-terminated list of
1942 * path components to append to the
1943 * private directory name.
1944 * @return the constructed filename
1947 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1948 const char *service_name, ...)
1954 unsigned int needed;
1957 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "HOME", &pfx))
1961 LOG (GNUNET_ERROR_TYPE_WARNING,
1962 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1966 needed = strlen (pfx) + 2;
1967 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1969 va_start (ap, service_name);
1972 c = va_arg (ap, const char *);
1976 needed += strlen (c);
1977 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1981 ret = GNUNET_malloc (needed);
1984 va_start (ap, service_name);
1987 c = va_arg (ap, const char *);
1991 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1992 strcat (ret, DIR_SEPARATOR_STR);
1996 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1997 (void) GNUNET_DISK_directory_create_for_file (ret);
1999 (void) GNUNET_DISK_directory_create (ret);
2005 * Handle for a memory-mapping operation.
2007 struct GNUNET_DISK_MapHandle
2010 * Address where the map is in memory.
2016 * Underlying OS handle.
2021 * Number of bytes mapped.
2029 #define MAP_FAILED ((void *) -1)
2033 * Map a file into memory
2035 * @param h open file handle
2036 * @param m handle to the new mapping
2037 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
2038 * @param len size of the mapping
2039 * @return pointer to the mapped memory region, NULL on failure
2042 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
2043 struct GNUNET_DISK_MapHandle **m,
2044 enum GNUNET_DISK_MapType access, size_t len)
2053 DWORD mapAccess, protect;
2055 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2056 (access & GNUNET_DISK_MAP_TYPE_WRITE))
2058 protect = PAGE_READWRITE;
2059 mapAccess = FILE_MAP_ALL_ACCESS;
2061 else if (access & GNUNET_DISK_MAP_TYPE_READ)
2063 protect = PAGE_READONLY;
2064 mapAccess = FILE_MAP_READ;
2066 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2068 protect = PAGE_READWRITE;
2069 mapAccess = FILE_MAP_WRITE;
2077 *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2078 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2079 if ((*m)->h == INVALID_HANDLE_VALUE)
2081 SetErrnoFromWinError (GetLastError ());
2086 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2089 SetErrnoFromWinError (GetLastError ());
2090 CloseHandle ((*m)->h);
2099 if (access & GNUNET_DISK_MAP_TYPE_READ)
2101 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2103 *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2104 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2105 GNUNET_assert (NULL != (*m)->addr);
2106 if (MAP_FAILED == (*m)->addr)
2118 * @param h mapping handle
2119 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2122 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2129 return GNUNET_SYSERR;
2133 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2134 if (ret != GNUNET_OK)
2135 SetErrnoFromWinError (GetLastError ());
2136 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2138 ret = GNUNET_SYSERR;
2139 SetErrnoFromWinError (GetLastError ());
2142 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2150 * Write file changes to disk
2151 * @param h handle to an open file
2152 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2155 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2160 return GNUNET_SYSERR;
2166 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2167 if (ret != GNUNET_OK)
2168 SetErrnoFromWinError (GetLastError ());
2170 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2171 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2173 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2180 #define PIPE_BUF 512
2182 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2183 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2185 /* Create a pipe, and return handles to the read and write ends,
2186 just like CreatePipe, but ensure that the write end permits
2187 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2188 this is supported. This access is needed by NtQueryInformationFile,
2189 which is used to implement select and nonblocking writes.
2190 Note that the return value is either NO_ERROR or GetLastError,
2191 unlike CreatePipe, which returns a bool for success or failure. */
2193 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2194 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2195 DWORD dwReadMode, DWORD dwWriteMode)
2197 /* Default to error. */
2198 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2203 /* Ensure that there is enough pipe buffer space for atomic writes. */
2204 if (psize < PIPE_BUF)
2207 char pipename[MAX_PATH];
2209 /* Retry CreateNamedPipe as long as the pipe name is in use.
2210 * Retrying will probably never be necessary, but we want
2211 * to be as robust as possible. */
2214 static volatile LONG pipe_unique_id;
2216 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2217 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2218 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2220 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2221 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2222 * access, on versions of win32 earlier than WinXP SP2.
2223 * CreatePipe also stupidly creates a full duplex pipe, which is
2224 * a waste, since only a single direction is actually used.
2225 * It's important to only allow a single instance, to ensure that
2226 * the pipe was not created earlier by some other process, even if
2227 * the pid has been reused. */
2228 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2229 psize, /* output buffer size */
2230 psize, /* input buffer size */
2231 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2233 if (read_pipe != INVALID_HANDLE_VALUE)
2235 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2239 DWORD err = GetLastError ();
2243 case ERROR_PIPE_BUSY:
2244 /* The pipe is already open with compatible parameters.
2245 * Pick a new name and retry. */
2246 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2248 case ERROR_ACCESS_DENIED:
2249 /* The pipe is already open with incompatible parameters.
2250 * Pick a new name and retry. */
2251 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2253 case ERROR_CALL_NOT_IMPLEMENTED:
2254 /* We are on an older Win9x platform without named pipes.
2255 * Return an anonymous pipe as the best approximation. */
2256 LOG (GNUNET_ERROR_TYPE_DEBUG,
2257 "CreateNamedPipe not implemented, resorting to "
2258 "CreatePipe: size = %lu\n", psize);
2259 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2261 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2266 err = GetLastError ();
2267 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2270 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2275 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2277 /* Open the named pipe for writing.
2278 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2279 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2280 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2281 0); /* handle to template file */
2283 if (write_pipe == INVALID_HANDLE_VALUE)
2286 DWORD err = GetLastError ();
2288 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2289 CloseHandle (read_pipe);
2292 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2294 *read_pipe_ptr = read_pipe;
2295 *write_pipe_ptr = write_pipe;
2302 * Creates an interprocess channel
2304 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2305 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2306 * @param inherit_read inherit the parent processes stdin (only for windows)
2307 * @param inherit_write inherit the parent processes stdout (only for windows)
2308 * @return handle to the new pipe, NULL on error
2310 struct GNUNET_DISK_PipeHandle *
2311 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2322 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2326 return GNUNET_DISK_pipe_from_fd (blocking_read,
2330 struct GNUNET_DISK_PipeHandle *p;
2335 p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2336 p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2337 p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2339 /* All pipes are overlapped. If you want them to block - just
2340 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2341 * NOTE: calling with NULL overlapped pointer works only
2342 * for pipes, and doesn't seem to be a documented feature.
2343 * It will NOT work for files, because overlapped files need
2344 * to read offsets from the overlapped structure, regardless.
2345 * Pipes are not seekable, and need no offsets, which is
2346 * probably why it works for them.
2349 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2350 FILE_FLAG_OVERLAPPED,
2351 FILE_FLAG_OVERLAPPED);
2354 SetErrnoFromWinError (GetLastError ());
2356 GNUNET_free (p->fd[0]);
2357 GNUNET_free (p->fd[1]);
2362 if (!DuplicateHandle
2363 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2364 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2366 SetErrnoFromWinError (GetLastError ());
2368 CloseHandle (p->fd[0]->h);
2369 CloseHandle (p->fd[1]->h);
2370 GNUNET_free (p->fd[0]);
2371 GNUNET_free (p->fd[1]);
2376 CloseHandle (p->fd[0]->h);
2377 p->fd[0]->h = tmp_handle;
2379 if (!DuplicateHandle
2380 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2381 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2383 SetErrnoFromWinError (GetLastError ());
2385 CloseHandle (p->fd[0]->h);
2386 CloseHandle (p->fd[1]->h);
2387 GNUNET_free (p->fd[0]);
2388 GNUNET_free (p->fd[1]);
2393 CloseHandle (p->fd[1]->h);
2394 p->fd[1]->h = tmp_handle;
2396 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2397 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2399 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2400 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2401 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2402 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2404 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2405 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2407 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2408 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2416 * Creates a pipe object from a couple of file descriptors.
2417 * Useful for wrapping existing pipe FDs.
2419 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2420 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2421 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2423 * @return handle to the new pipe, NULL on error
2425 struct GNUNET_DISK_PipeHandle *
2426 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2428 struct GNUNET_DISK_PipeHandle *p;
2430 p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2435 int eno = 0; /* make gcc happy */
2440 p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2441 p->fd[0]->fd = fd[0];
2444 flags = fcntl (fd[0], F_GETFL);
2445 flags |= O_NONBLOCK;
2446 if (0 > fcntl (fd[0], F_SETFL, flags))
2452 flags = fcntl (fd[0], F_GETFD);
2453 flags |= FD_CLOEXEC;
2454 if (0 > fcntl (fd[0], F_SETFD, flags))
2463 p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2464 p->fd[1]->fd = fd[1];
2465 if (!blocking_write)
2467 flags = fcntl (fd[1], F_GETFL);
2468 flags |= O_NONBLOCK;
2469 if (0 > fcntl (fd[1], F_SETFL, flags))
2475 flags = fcntl (fd[1], F_GETFD);
2476 flags |= FD_CLOEXEC;
2477 if (0 > fcntl (fd[1], F_SETFD, flags))
2486 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2487 if (p->fd[0]->fd >= 0)
2488 GNUNET_break (0 == close (p->fd[0]->fd));
2489 if (p->fd[1]->fd >= 0)
2490 GNUNET_break (0 == close (p->fd[1]->fd));
2491 GNUNET_free_non_null (p->fd[0]);
2492 GNUNET_free_non_null (p->fd[1]);
2500 p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2501 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2502 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2504 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2505 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2506 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2507 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2508 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2512 GNUNET_free (p->fd[0]);
2518 p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2519 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2520 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2522 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2523 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2524 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2525 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2526 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2530 GNUNET_free (p->fd[1]);
2541 * Closes an interprocess channel
2543 * @param p pipe to close
2544 * @param end which end of the pipe to close
2545 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2548 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2549 enum GNUNET_DISK_PipeEnd end)
2551 int ret = GNUNET_OK;
2553 if (end == GNUNET_DISK_PIPE_END_READ)
2557 ret = GNUNET_DISK_file_close (p->fd[0]);
2561 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2565 ret = GNUNET_DISK_file_close (p->fd[1]);
2574 * Detaches one of the ends from the pipe.
2575 * Detached end is a fully-functional FileHandle, it will
2576 * not be affected by anything you do with the pipe afterwards.
2577 * Each end of a pipe can only be detched from it once (i.e.
2578 * it is not duplicated).
2580 * @param p pipe to detach an end from
2581 * @param end which end of the pipe to detach
2582 * @return Detached end on success, NULL on failure
2583 * (or if that end is not present or is closed).
2585 struct GNUNET_DISK_FileHandle *
2586 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2587 enum GNUNET_DISK_PipeEnd end)
2589 struct GNUNET_DISK_FileHandle *ret = NULL;
2591 if (end == GNUNET_DISK_PIPE_END_READ)
2599 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2613 * Closes an interprocess channel
2615 * @param p pipe to close
2616 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2619 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2621 int ret = GNUNET_OK;
2624 int write_end_close;
2625 int read_end_close_errno;
2626 int write_end_close_errno;
2628 read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2629 read_end_close_errno = errno;
2630 write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2631 write_end_close_errno = errno;
2634 if (GNUNET_OK != read_end_close)
2636 errno = read_end_close_errno;
2637 ret = read_end_close;
2639 else if (GNUNET_OK != write_end_close)
2641 errno = write_end_close_errno;
2642 ret = write_end_close;
2650 * Get the handle to a particular pipe end
2653 * @param n end to access
2654 * @return handle for the respective end
2656 const struct GNUNET_DISK_FileHandle *
2657 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2658 enum GNUNET_DISK_PipeEnd n)
2662 case GNUNET_DISK_PIPE_END_READ:
2663 case GNUNET_DISK_PIPE_END_WRITE:
2673 * Retrieve OS file handle
2675 * @param fh GNUnet file descriptor
2676 * @param dst destination buffer
2677 * @param dst_len length of dst
2678 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2681 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2682 void *dst, size_t dst_len)
2685 if (dst_len < sizeof (HANDLE))
2686 return GNUNET_SYSERR;
2687 *((HANDLE *) dst) = fh->h;
2689 if (dst_len < sizeof (int))
2690 return GNUNET_SYSERR;
2691 *((int *) dst) = fh->fd;