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 includeSymLinks should symbolic links be
287 * @param singleFileMode 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 includeSymLinks, int singleFileMode)
295 struct GetFileSizeData gfsd;
298 GNUNET_assert (size != NULL);
300 gfsd.include_sym_links = includeSymLinks;
301 gfsd.single_file_mode = singleFileMode;
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 "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 "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 * @returns 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.
791 * @param h handle to an open file
792 * @param result the buffer to write the result to
793 * @param len the maximum number of bytes to read
794 * @return the number of bytes read on success, GNUNET_SYSERR on failure
797 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
803 return GNUNET_SYSERR;
809 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
811 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
813 SetErrnoFromWinError (GetLastError ());
814 return GNUNET_SYSERR;
819 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
821 if (GetLastError () != ERROR_IO_PENDING)
823 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
824 SetErrnoFromWinError (GetLastError ());
825 return GNUNET_SYSERR;
827 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
828 GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE);
830 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead);
834 return read (h->fd, result, len);
840 * Read the contents of a binary file into a buffer.
841 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
842 * when no data can be read).
844 * @param h handle to an open file
845 * @param result the buffer to write the result to
846 * @param len the maximum number of bytes to read
847 * @return the number of bytes read on success, GNUNET_SYSERR on failure
850 GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h,
857 return GNUNET_SYSERR;
863 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
865 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
867 SetErrnoFromWinError (GetLastError ());
868 return GNUNET_SYSERR;
873 if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead))
875 if (GetLastError () != ERROR_IO_PENDING)
877 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
878 SetErrnoFromWinError (GetLastError ());
879 return GNUNET_SYSERR;
883 LOG (GNUNET_ERROR_TYPE_DEBUG,
884 "ReadFile() queued a read, cancelling\n");
887 return GNUNET_SYSERR;
890 LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead);
897 /* set to non-blocking, read, then set back */
898 flags = fcntl (h->fd, F_GETFL);
899 if (0 == (flags & O_NONBLOCK))
900 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
901 ret = read (h->fd, result, len);
902 if (0 == (flags & O_NONBLOCK))
905 (void) fcntl (h->fd, F_SETFL, flags);
914 * Read the contents of a binary file into a buffer.
916 * @param fn file name
917 * @param result the buffer to write the result to
918 * @param len the maximum number of bytes to read
919 * @return number of bytes read, GNUNET_SYSERR on failure
922 GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
924 struct GNUNET_DISK_FileHandle *fh;
927 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
929 return GNUNET_SYSERR;
930 ret = GNUNET_DISK_file_read (fh, result, len);
931 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
938 * Write a buffer to a file.
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 (const struct GNUNET_DISK_FileHandle * h,
946 const void *buffer, size_t n)
951 return GNUNET_SYSERR;
957 if (h->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
959 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
961 SetErrnoFromWinError (GetLastError ());
962 return GNUNET_SYSERR;
967 LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
968 if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite))
970 if (GetLastError () != ERROR_IO_PENDING)
972 SetErrnoFromWinError (GetLastError ());
973 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
975 return GNUNET_SYSERR;
977 LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
978 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE))
980 SetErrnoFromWinError (GetLastError ());
981 LOG (GNUNET_ERROR_TYPE_DEBUG,
982 "Error getting overlapped result while writing to pipe: %u\n",
984 return GNUNET_SYSERR;
990 if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
992 LOG (GNUNET_ERROR_TYPE_DEBUG,
993 "Error getting control overlapped result while writing to pipe: %u\n",
998 LOG (GNUNET_ERROR_TYPE_DEBUG,
999 "Wrote %u bytes (ovr says %u), picking the greatest\n",
1003 if (bytesWritten == 0)
1007 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten);
1009 return GNUNET_SYSERR;
1012 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1014 return bytesWritten;
1016 return write (h->fd, buffer, n);
1022 * Write a buffer to a file, blocking, if necessary.
1023 * @param h handle to open file
1024 * @param buffer the data to write
1025 * @param n number of bytes to write
1026 * @return number of bytes written on success, GNUNET_SYSERR on error
1029 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h,
1030 const void *buffer, size_t n)
1035 return GNUNET_SYSERR;
1040 /* We do a non-overlapped write, which is as blocking as it gets */
1041 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1042 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1044 SetErrnoFromWinError (GetLastError ());
1045 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1047 return GNUNET_SYSERR;
1049 if (bytesWritten == 0 && n > 0)
1051 LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1052 WaitForSingleObject (h->h, INFINITE);
1053 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
1055 SetErrnoFromWinError (GetLastError ());
1056 LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1058 return GNUNET_SYSERR;
1061 LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten);
1062 return bytesWritten;
1067 /* set to blocking, write, then set back */
1068 flags = fcntl (h->fd, F_GETFL);
1069 if (0 != (flags & O_NONBLOCK))
1070 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1071 ret = write (h->fd, buffer, n);
1072 if (0 == (flags & O_NONBLOCK))
1073 (void) fcntl (h->fd, F_SETFL, flags);
1080 * Write a buffer to a file. If the file is longer than the
1081 * number of bytes that will be written, it will be truncated.
1083 * @param fn file name
1084 * @param buffer the data to write
1085 * @param n number of bytes to write
1086 * @param mode file permissions
1087 * @return number of bytes written on success, GNUNET_SYSERR on error
1090 GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n,
1091 enum GNUNET_DISK_AccessPermissions mode)
1093 struct GNUNET_DISK_FileHandle *fh;
1096 fh = GNUNET_DISK_file_open (fn,
1097 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1098 | GNUNET_DISK_OPEN_CREATE, mode);
1100 return GNUNET_SYSERR;
1101 ret = GNUNET_DISK_file_write (fh, buffer, n);
1102 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1108 * Scan a directory for files.
1110 * @param dir_name the name of the directory
1111 * @param callback the method to call for each file,
1112 * can be NULL, in that case, we only count
1113 * @param callback_cls closure for callback
1114 * @return the number of files found, GNUNET_SYSERR on error or
1115 * ieration aborted by callback returning GNUNET_SYSERR
1118 GNUNET_DISK_directory_scan (const char *dir_name,
1119 GNUNET_FileNameCallback callback,
1123 struct dirent *finfo;
1129 unsigned int name_len;
1130 unsigned int n_size;
1132 GNUNET_assert (dir_name != NULL);
1133 dname = GNUNET_STRINGS_filename_expand (dir_name);
1135 return GNUNET_SYSERR;
1136 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
1137 dname[strlen (dname) - 1] = '\0';
1138 if (0 != STAT (dname, &istat))
1140 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
1141 GNUNET_free (dname);
1142 return GNUNET_SYSERR;
1144 if (!S_ISDIR (istat.st_mode))
1146 LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"),
1148 GNUNET_free (dname);
1149 return GNUNET_SYSERR;
1152 dinfo = OPENDIR (dname);
1153 if ((errno == EACCES) || (dinfo == NULL))
1155 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
1158 GNUNET_free (dname);
1159 return GNUNET_SYSERR;
1162 n_size = strlen (dname) + name_len + 2;
1163 name = GNUNET_malloc (n_size);
1164 while ((finfo = READDIR (dinfo)) != NULL)
1166 if ((0 == strcmp (finfo->d_name, ".")) ||
1167 (0 == strcmp (finfo->d_name, "..")))
1169 if (callback != NULL)
1171 if (name_len < strlen (finfo->d_name))
1174 name_len = strlen (finfo->d_name);
1175 n_size = strlen (dname) + name_len + 2;
1176 name = GNUNET_malloc (n_size);
1178 /* dname can end in "/" only if dname == "/";
1179 * if dname does not end in "/", we need to add
1180 * a "/" (otherwise, we must not!) */
1181 GNUNET_snprintf (name, n_size, "%s%s%s", dname,
1182 (strcmp (dname, DIR_SEPARATOR_STR) ==
1183 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
1184 ret = callback (callback_cls, name);
1185 if (GNUNET_OK != ret)
1189 GNUNET_free (dname);
1190 if (GNUNET_NO == ret)
1192 return GNUNET_SYSERR;
1199 GNUNET_free (dname);
1205 * Opaque handle used for iterating over a directory.
1207 struct GNUNET_DISK_DirectoryIterator
1211 * Function to call on directory entries.
1213 GNUNET_DISK_DirectoryIteratorCallback callback;
1216 * Closure for callback.
1221 * Reference to directory.
1231 * Next filename to process.
1238 enum GNUNET_SCHEDULER_Priority priority;
1244 * Task used by the directory iterator.
1247 directory_iterator_task (void *cls,
1248 const struct GNUNET_SCHEDULER_TaskContext *tc)
1250 struct GNUNET_DISK_DirectoryIterator *iter = cls;
1253 name = iter->next_name;
1254 GNUNET_assert (name != NULL);
1255 iter->next_name = NULL;
1256 iter->callback (iter->callback_cls, iter, name, iter->dirname);
1262 * This function must be called during the DiskIteratorCallback
1263 * (exactly once) to schedule the task to process the next
1264 * filename in the directory (if there is one).
1266 * @param iter opaque handle for the iterator
1267 * @param can set to GNUNET_YES to terminate the iteration early
1268 * @return GNUNET_YES if iteration will continue,
1269 * GNUNET_NO if this was the last entry (and iteration is complete),
1270 * GNUNET_SYSERR if abort was YES
1273 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
1276 struct dirent *finfo;
1278 GNUNET_assert (iter->next_name == NULL);
1279 if (can == GNUNET_YES)
1281 CLOSEDIR (iter->directory);
1282 GNUNET_free (iter->dirname);
1284 return GNUNET_SYSERR;
1286 while (NULL != (finfo = READDIR (iter->directory)))
1288 if ((0 == strcmp (finfo->d_name, ".")) ||
1289 (0 == strcmp (finfo->d_name, "..")))
1291 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
1292 DIR_SEPARATOR_STR, finfo->d_name);
1297 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
1300 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
1307 * Scan a directory for files using the scheduler to run a task for
1308 * each entry. The name of the directory must be expanded first (!).
1309 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
1310 * may provide a simpler API.
1312 * @param prio priority to use
1313 * @param dir_name the name of the directory
1314 * @param callback the method to call for each file
1315 * @param callback_cls closure for callback
1316 * @return GNUNET_YES if directory is not empty and 'callback'
1317 * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error.
1320 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
1321 const char *dir_name,
1322 GNUNET_DISK_DirectoryIteratorCallback
1323 callback, void *callback_cls)
1325 struct GNUNET_DISK_DirectoryIterator *di;
1327 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
1328 di->callback = callback;
1329 di->callback_cls = callback_cls;
1330 di->directory = OPENDIR (dir_name);
1331 if (di->directory == NULL)
1334 callback (callback_cls, NULL, NULL, NULL);
1335 return GNUNET_SYSERR;
1337 di->dirname = GNUNET_strdup (dir_name);
1338 di->priority = prio;
1339 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
1344 * Function that removes the given directory by calling
1345 * "GNUNET_DISK_directory_remove".
1347 * @param unused not used
1348 * @param fn directory to remove
1352 remove_helper (void *unused, const char *fn)
1354 (void) GNUNET_DISK_directory_remove (fn);
1360 * Remove all files in a directory (rm -rf). Call with
1364 * @param filename the file to remove
1365 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1368 GNUNET_DISK_directory_remove (const char *filename)
1372 if (0 != LSTAT (filename, &istat))
1373 return GNUNET_NO; /* file may not exist... */
1374 (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR);
1375 if (UNLINK (filename) == 0)
1377 if ((errno != EISDIR) &&
1378 /* EISDIR is not sufficient in all cases, e.g.
1379 * sticky /tmp directory may result in EPERM on BSD.
1380 * So we also explicitly check "isDirectory" */
1381 (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES)))
1383 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1384 return GNUNET_SYSERR;
1386 if (GNUNET_SYSERR ==
1387 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1388 return GNUNET_SYSERR;
1389 if (0 != RMDIR (filename))
1391 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1392 return GNUNET_SYSERR;
1401 * @param src file to copy
1402 * @param dst destination file name
1403 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1406 GNUNET_DISK_file_copy (const char *src,
1413 struct GNUNET_DISK_FileHandle *in;
1414 struct GNUNET_DISK_FileHandle *out;
1416 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1417 return GNUNET_SYSERR;
1419 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1420 GNUNET_DISK_PERM_NONE);
1422 return GNUNET_SYSERR;
1424 GNUNET_DISK_file_open (dst,
1425 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1426 GNUNET_DISK_OPEN_FAILIFEXISTS,
1427 GNUNET_DISK_PERM_USER_READ |
1428 GNUNET_DISK_PERM_USER_WRITE |
1429 GNUNET_DISK_PERM_GROUP_READ |
1430 GNUNET_DISK_PERM_GROUP_WRITE);
1433 GNUNET_DISK_file_close (in);
1434 return GNUNET_SYSERR;
1436 buf = GNUNET_malloc (COPY_BLK_SIZE);
1439 len = COPY_BLK_SIZE;
1440 if (len > size - pos)
1442 if (len != GNUNET_DISK_file_read (in, buf, len))
1444 if (len != GNUNET_DISK_file_write (out, buf, len))
1449 GNUNET_DISK_file_close (in);
1450 GNUNET_DISK_file_close (out);
1454 GNUNET_DISK_file_close (in);
1455 GNUNET_DISK_file_close (out);
1456 return GNUNET_SYSERR;
1461 * @brief Removes special characters as ':' from a filename.
1462 * @param fn the filename to canonicalize
1465 GNUNET_DISK_filename_canonicalize (char *fn)
1475 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1476 c == '<' || c == '>' || c == '|')
1488 * @brief Change owner of a file
1490 * @param filename name of file to change the owner of
1491 * @param user name of the new owner
1492 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1495 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1500 pws = getpwnam (user);
1503 LOG (GNUNET_ERROR_TYPE_ERROR,
1504 _("Cannot obtain information about user `%s': %s\n"), user,
1506 return GNUNET_SYSERR;
1508 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1509 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1516 * Lock a part of a file
1517 * @param fh file handle
1518 * @param lock_start absolute position from where to lock
1519 * @param lock_end absolute position until where to lock
1520 * @param excl GNUNET_YES for an exclusive lock
1521 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1524 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lock_start,
1525 OFF_T lock_end, int excl)
1530 return GNUNET_SYSERR;
1536 memset (&fl, 0, sizeof (struct flock));
1537 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1538 fl.l_whence = SEEK_SET;
1539 fl.l_start = lock_start;
1540 fl.l_len = lock_end;
1542 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1545 OFF_T diff = lock_end - lock_start;
1546 DWORD diff_low, diff_high;
1547 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1548 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1550 memset (&o, 0, sizeof (OVERLAPPED));
1551 o.Offset = (DWORD) (lock_start & 0xFFFFFFFF);;
1552 o.OffsetHigh = (DWORD) (((lock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1555 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1556 0, diff_low, diff_high, &o))
1558 SetErrnoFromWinError (GetLastError ());
1559 return GNUNET_SYSERR;
1568 * Unlock a part of a file
1569 * @param fh file handle
1570 * @param unlock_start absolute position from where to unlock
1571 * @param unlock_end absolute position until where to unlock
1572 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1575 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlock_start,
1581 return GNUNET_SYSERR;
1587 memset (&fl, 0, sizeof (struct flock));
1588 fl.l_type = F_UNLCK;
1589 fl.l_whence = SEEK_SET;
1590 fl.l_start = unlock_start;
1591 fl.l_len = unlock_end;
1593 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1596 OFF_T diff = unlock_end - unlock_start;
1597 DWORD diff_low, diff_high;
1598 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1599 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1601 memset (&o, 0, sizeof (OVERLAPPED));
1602 o.Offset = (DWORD) (unlock_start & 0xFFFFFFFF);;
1603 o.OffsetHigh = (DWORD) (((unlock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1605 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1607 SetErrnoFromWinError (GetLastError ());
1608 return GNUNET_SYSERR;
1617 * Open a file. Note that the access permissions will only be
1618 * used if a new file is created and if the underlying operating
1619 * system supports the given permissions.
1621 * @param fn file name to be opened
1622 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1623 * @param perm permissions for the newly created file, use
1624 * #GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1625 * call (because of flags)
1626 * @return IO handle on success, NULL on error
1628 struct GNUNET_DISK_FileHandle *
1629 GNUNET_DISK_file_open (const char *fn,
1630 enum GNUNET_DISK_OpenFlags flags,
1631 enum GNUNET_DISK_AccessPermissions perm)
1634 struct GNUNET_DISK_FileHandle *ret;
1640 wchar_t wexpfn[MAX_PATH + 1];
1647 expfn = GNUNET_STRINGS_filename_expand (fn);
1652 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1653 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1654 else if (flags & GNUNET_DISK_OPEN_READ)
1656 else if (flags & GNUNET_DISK_OPEN_WRITE)
1661 GNUNET_free (expfn);
1664 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1665 oflags |= (O_CREAT | O_EXCL);
1666 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1668 if (flags & GNUNET_DISK_OPEN_APPEND)
1670 if (flags & GNUNET_DISK_OPEN_CREATE)
1672 (void) GNUNET_DISK_directory_create_for_file (expfn);
1674 mode = translate_unix_perms (perm);
1677 fd = open (expfn, oflags
1681 | O_LARGEFILE, mode);
1684 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1685 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1687 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1688 GNUNET_free (expfn);
1695 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1696 access = FILE_READ_DATA | FILE_WRITE_DATA;
1697 else if (flags & GNUNET_DISK_OPEN_READ)
1698 access = FILE_READ_DATA;
1699 else if (flags & GNUNET_DISK_OPEN_WRITE)
1700 access = FILE_WRITE_DATA;
1702 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1706 else if (flags & GNUNET_DISK_OPEN_CREATE)
1708 (void) GNUNET_DISK_directory_create_for_file (expfn);
1709 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1710 disp = CREATE_ALWAYS;
1714 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1716 disp = TRUNCATE_EXISTING;
1720 disp = OPEN_EXISTING;
1723 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1724 h = CreateFileW (wexpfn, access,
1725 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1726 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1728 h = INVALID_HANDLE_VALUE;
1729 if (h == INVALID_HANDLE_VALUE)
1732 SetErrnoFromWinError (GetLastError ());
1734 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1735 GNUNET_free (expfn);
1740 if (flags & GNUNET_DISK_OPEN_APPEND)
1741 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1743 SetErrnoFromWinError (GetLastError ());
1744 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1746 GNUNET_free (expfn);
1751 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1754 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1758 GNUNET_free (expfn);
1764 * Close an open file
1765 * @param h file handle
1766 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1769 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1775 return GNUNET_SYSERR;
1781 if (!CloseHandle (h->h))
1783 SetErrnoFromWinError (GetLastError ());
1784 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1785 ret = GNUNET_SYSERR;
1787 if (h->oOverlapRead)
1789 if (!CloseHandle (h->oOverlapRead->hEvent))
1791 SetErrnoFromWinError (GetLastError ());
1792 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1793 ret = GNUNET_SYSERR;
1795 GNUNET_free (h->oOverlapRead);
1797 if (h->oOverlapWrite)
1799 if (!CloseHandle (h->oOverlapWrite->hEvent))
1801 SetErrnoFromWinError (GetLastError ());
1802 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1803 ret = GNUNET_SYSERR;
1805 GNUNET_free (h->oOverlapWrite);
1808 if (close (h->fd) != 0)
1810 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1811 ret = GNUNET_SYSERR;
1820 * Get a GNUnet file handle from a W32 handle.
1822 * @param handle native handle
1823 * @return GNUnet file handle corresponding to the W32 handle
1825 struct GNUNET_DISK_FileHandle *
1826 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1828 struct GNUNET_DISK_FileHandle *fh;
1831 enum GNUNET_FILE_Type ftype;
1833 dwret = GetFileType (osfh);
1836 case FILE_TYPE_DISK:
1837 ftype = GNUNET_DISK_HANLDE_TYPE_FILE;
1839 case FILE_TYPE_PIPE:
1840 ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1846 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1850 if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1853 * Note that we can't make it overlapped if it isn't already.
1854 * (ReOpenFile() is only available in 2003/Vista).
1855 * The process that opened this file in the first place (usually a parent
1856 * process, if this is stdin/stdout/stderr) must make it overlapped,
1857 * otherwise we're screwed, as selecting on non-overlapped handle
1860 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1861 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1862 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1863 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1871 * Get a handle from a native integer FD.
1873 * @param fno native integer file descriptor
1874 * @return file handle corresponding to the descriptor, NULL on error
1876 struct GNUNET_DISK_FileHandle *
1877 GNUNET_DISK_get_handle_from_int_fd (int fno)
1879 struct GNUNET_DISK_FileHandle *fh;
1881 if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1883 return NULL; /* invalid FD */
1886 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1892 osfh = _get_osfhandle (fno);
1893 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1896 fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1904 * Get a handle from a native streaming FD.
1906 * @param fd native streaming file descriptor
1907 * @return file handle corresponding to the descriptor
1909 struct GNUNET_DISK_FileHandle *
1910 GNUNET_DISK_get_handle_from_native (FILE *fd)
1918 return GNUNET_DISK_get_handle_from_int_fd (fno);
1923 * Construct full path to a file inside of the private
1924 * directory used by GNUnet. Also creates the corresponding
1925 * directory. If the resulting name is supposed to be
1926 * a directory, end the last argument in '/' (or pass
1927 * DIR_SEPARATOR_STR as the last argument before NULL).
1929 * @param cfg configuration to use (determines HOME)
1930 * @param service_name name of the service
1931 * @param ... is NULL-terminated list of
1932 * path components to append to the
1933 * private directory name.
1934 * @return the constructed filename
1937 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1938 const char *service_name, ...)
1944 unsigned int needed;
1947 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "HOME", &pfx))
1951 LOG (GNUNET_ERROR_TYPE_WARNING,
1952 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1956 needed = strlen (pfx) + 2;
1957 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1959 va_start (ap, service_name);
1962 c = va_arg (ap, const char *);
1966 needed += strlen (c);
1967 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1971 ret = GNUNET_malloc (needed);
1974 va_start (ap, service_name);
1977 c = va_arg (ap, const char *);
1981 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1982 strcat (ret, DIR_SEPARATOR_STR);
1986 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1987 (void) GNUNET_DISK_directory_create_for_file (ret);
1989 (void) GNUNET_DISK_directory_create (ret);
1995 * Handle for a memory-mapping operation.
1997 struct GNUNET_DISK_MapHandle
2000 * Address where the map is in memory.
2006 * Underlying OS handle.
2011 * Number of bytes mapped.
2019 #define MAP_FAILED ((void *) -1)
2023 * Map a file into memory
2025 * @param h open file handle
2026 * @param m handle to the new mapping
2027 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
2028 * @param len size of the mapping
2029 * @return pointer to the mapped memory region, NULL on failure
2032 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
2033 struct GNUNET_DISK_MapHandle **m,
2034 enum GNUNET_DISK_MapType access, size_t len)
2043 DWORD mapAccess, protect;
2045 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2046 (access & GNUNET_DISK_MAP_TYPE_WRITE))
2048 protect = PAGE_READWRITE;
2049 mapAccess = FILE_MAP_ALL_ACCESS;
2051 else if (access & GNUNET_DISK_MAP_TYPE_READ)
2053 protect = PAGE_READONLY;
2054 mapAccess = FILE_MAP_READ;
2056 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2058 protect = PAGE_READWRITE;
2059 mapAccess = FILE_MAP_WRITE;
2067 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2068 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2069 if ((*m)->h == INVALID_HANDLE_VALUE)
2071 SetErrnoFromWinError (GetLastError ());
2076 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2079 SetErrnoFromWinError (GetLastError ());
2080 CloseHandle ((*m)->h);
2089 if (access & GNUNET_DISK_MAP_TYPE_READ)
2091 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2093 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2094 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2095 GNUNET_assert (NULL != (*m)->addr);
2096 if (MAP_FAILED == (*m)->addr)
2108 * @param h mapping handle
2109 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2112 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2119 return GNUNET_SYSERR;
2123 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2124 if (ret != GNUNET_OK)
2125 SetErrnoFromWinError (GetLastError ());
2126 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2128 ret = GNUNET_SYSERR;
2129 SetErrnoFromWinError (GetLastError ());
2132 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2140 * Write file changes to disk
2141 * @param h handle to an open file
2142 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2145 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2150 return GNUNET_SYSERR;
2156 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2157 if (ret != GNUNET_OK)
2158 SetErrnoFromWinError (GetLastError ());
2160 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2161 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2163 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2170 #define PIPE_BUF 512
2172 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2173 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2175 /* Create a pipe, and return handles to the read and write ends,
2176 just like CreatePipe, but ensure that the write end permits
2177 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2178 this is supported. This access is needed by NtQueryInformationFile,
2179 which is used to implement select and nonblocking writes.
2180 Note that the return value is either NO_ERROR or GetLastError,
2181 unlike CreatePipe, which returns a bool for success or failure. */
2183 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2184 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2185 DWORD dwReadMode, DWORD dwWriteMode)
2187 /* Default to error. */
2188 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2193 /* Ensure that there is enough pipe buffer space for atomic writes. */
2194 if (psize < PIPE_BUF)
2197 char pipename[MAX_PATH];
2199 /* Retry CreateNamedPipe as long as the pipe name is in use.
2200 * Retrying will probably never be necessary, but we want
2201 * to be as robust as possible. */
2204 static volatile LONG pipe_unique_id;
2206 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2207 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2208 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2210 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2211 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2212 * access, on versions of win32 earlier than WinXP SP2.
2213 * CreatePipe also stupidly creates a full duplex pipe, which is
2214 * a waste, since only a single direction is actually used.
2215 * It's important to only allow a single instance, to ensure that
2216 * the pipe was not created earlier by some other process, even if
2217 * the pid has been reused. */
2218 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2219 psize, /* output buffer size */
2220 psize, /* input buffer size */
2221 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2223 if (read_pipe != INVALID_HANDLE_VALUE)
2225 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2229 DWORD err = GetLastError ();
2233 case ERROR_PIPE_BUSY:
2234 /* The pipe is already open with compatible parameters.
2235 * Pick a new name and retry. */
2236 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2238 case ERROR_ACCESS_DENIED:
2239 /* The pipe is already open with incompatible parameters.
2240 * Pick a new name and retry. */
2241 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2243 case ERROR_CALL_NOT_IMPLEMENTED:
2244 /* We are on an older Win9x platform without named pipes.
2245 * Return an anonymous pipe as the best approximation. */
2246 LOG (GNUNET_ERROR_TYPE_DEBUG,
2247 "CreateNamedPipe not implemented, resorting to "
2248 "CreatePipe: size = %lu\n", psize);
2249 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2251 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2256 err = GetLastError ();
2257 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2260 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2265 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2267 /* Open the named pipe for writing.
2268 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2269 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2270 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2271 0); /* handle to template file */
2273 if (write_pipe == INVALID_HANDLE_VALUE)
2276 DWORD err = GetLastError ();
2278 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2279 CloseHandle (read_pipe);
2282 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2284 *read_pipe_ptr = read_pipe;
2285 *write_pipe_ptr = write_pipe;
2292 * Creates an interprocess channel
2294 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2295 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2296 * @param inherit_read inherit the parent processes stdin (only for windows)
2297 * @param inherit_write inherit the parent processes stdout (only for windows)
2298 * @return handle to the new pipe, NULL on error
2300 struct GNUNET_DISK_PipeHandle *
2301 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2312 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2316 return GNUNET_DISK_pipe_from_fd (blocking_read,
2320 struct GNUNET_DISK_PipeHandle *p;
2325 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2326 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2327 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2329 /* All pipes are overlapped. If you want them to block - just
2330 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2331 * NOTE: calling with NULL overlapped pointer works only
2332 * for pipes, and doesn't seem to be a documented feature.
2333 * It will NOT work for files, because overlapped files need
2334 * to read offsets from the overlapped structure, regardless.
2335 * Pipes are not seekable, and need no offsets, which is
2336 * probably why it works for them.
2339 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2340 FILE_FLAG_OVERLAPPED,
2341 FILE_FLAG_OVERLAPPED);
2344 SetErrnoFromWinError (GetLastError ());
2346 GNUNET_free (p->fd[0]);
2347 GNUNET_free (p->fd[1]);
2352 if (!DuplicateHandle
2353 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2354 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2356 SetErrnoFromWinError (GetLastError ());
2358 CloseHandle (p->fd[0]->h);
2359 CloseHandle (p->fd[1]->h);
2360 GNUNET_free (p->fd[0]);
2361 GNUNET_free (p->fd[1]);
2366 CloseHandle (p->fd[0]->h);
2367 p->fd[0]->h = tmp_handle;
2369 if (!DuplicateHandle
2370 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2371 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2373 SetErrnoFromWinError (GetLastError ());
2375 CloseHandle (p->fd[0]->h);
2376 CloseHandle (p->fd[1]->h);
2377 GNUNET_free (p->fd[0]);
2378 GNUNET_free (p->fd[1]);
2383 CloseHandle (p->fd[1]->h);
2384 p->fd[1]->h = tmp_handle;
2386 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2387 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2389 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2390 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2391 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2392 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2394 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2395 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2397 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2398 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2406 * Creates a pipe object from a couple of file descriptors.
2407 * Useful for wrapping existing pipe FDs.
2409 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2410 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2411 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2413 * @return handle to the new pipe, NULL on error
2415 struct GNUNET_DISK_PipeHandle *
2416 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2418 struct GNUNET_DISK_PipeHandle *p;
2420 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2425 int eno = 0; /* make gcc happy */
2430 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2431 p->fd[0]->fd = fd[0];
2434 flags = fcntl (fd[0], F_GETFL);
2435 flags |= O_NONBLOCK;
2436 if (0 > fcntl (fd[0], F_SETFL, flags))
2442 flags = fcntl (fd[0], F_GETFD);
2443 flags |= FD_CLOEXEC;
2444 if (0 > fcntl (fd[0], F_SETFD, flags))
2453 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2454 p->fd[1]->fd = fd[1];
2455 if (!blocking_write)
2457 flags = fcntl (fd[1], F_GETFL);
2458 flags |= O_NONBLOCK;
2459 if (0 > fcntl (fd[1], F_SETFL, flags))
2465 flags = fcntl (fd[1], F_GETFD);
2466 flags |= FD_CLOEXEC;
2467 if (0 > fcntl (fd[1], F_SETFD, flags))
2476 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2477 if (p->fd[0]->fd >= 0)
2478 GNUNET_break (0 == close (p->fd[0]->fd));
2479 if (p->fd[1]->fd >= 0)
2480 GNUNET_break (0 == close (p->fd[1]->fd));
2481 GNUNET_free_non_null (p->fd[0]);
2482 GNUNET_free_non_null (p->fd[1]);
2490 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2491 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2492 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2494 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2495 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2496 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2497 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2498 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2502 GNUNET_free (p->fd[0]);
2508 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2509 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2510 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2512 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2513 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2514 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2515 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2516 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2520 GNUNET_free (p->fd[1]);
2531 * Closes an interprocess channel
2533 * @param p pipe to close
2534 * @param end which end of the pipe to close
2535 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2538 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2539 enum GNUNET_DISK_PipeEnd end)
2541 int ret = GNUNET_OK;
2543 if (end == GNUNET_DISK_PIPE_END_READ)
2547 ret = GNUNET_DISK_file_close (p->fd[0]);
2551 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2555 ret = GNUNET_DISK_file_close (p->fd[1]);
2564 * Detaches one of the ends from the pipe.
2565 * Detached end is a fully-functional FileHandle, it will
2566 * not be affected by anything you do with the pipe afterwards.
2567 * Each end of a pipe can only be detched from it once (i.e.
2568 * it is not duplicated).
2570 * @param p pipe to detach an end from
2571 * @param end which end of the pipe to detach
2572 * @return Detached end on success, NULL on failure
2573 * (or if that end is not present or is closed).
2575 struct GNUNET_DISK_FileHandle *
2576 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2577 enum GNUNET_DISK_PipeEnd end)
2579 struct GNUNET_DISK_FileHandle *ret = NULL;
2581 if (end == GNUNET_DISK_PIPE_END_READ)
2589 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2603 * Closes an interprocess channel
2605 * @param p pipe to close
2606 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2609 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2611 int ret = GNUNET_OK;
2614 int write_end_close;
2615 int read_end_close_errno;
2616 int write_end_close_errno;
2618 read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2619 read_end_close_errno = errno;
2620 write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2621 write_end_close_errno = errno;
2624 if (GNUNET_OK != read_end_close)
2626 errno = read_end_close_errno;
2627 ret = read_end_close;
2629 else if (GNUNET_OK != write_end_close)
2631 errno = write_end_close_errno;
2632 ret = write_end_close;
2640 * Get the handle to a particular pipe end
2643 * @param n end to access
2644 * @return handle for the respective end
2646 const struct GNUNET_DISK_FileHandle *
2647 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2648 enum GNUNET_DISK_PipeEnd n)
2652 case GNUNET_DISK_PIPE_END_READ:
2653 case GNUNET_DISK_PIPE_END_WRITE:
2663 * Retrieve OS file handle
2665 * @param fh GNUnet file descriptor
2666 * @param dst destination buffer
2667 * @param dst_len length of dst
2668 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2671 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2672 void *dst, size_t dst_len)
2675 if (dst_len < sizeof (HANDLE))
2676 return GNUNET_SYSERR;
2677 *((HANDLE *) dst) = fh->h;
2679 if (dst_len < sizeof (int))
2680 return GNUNET_SYSERR;
2681 *((int *) dst) = fh->fd;