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 dirName 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 *dirName,
1119 GNUNET_FileNameCallback callback,
1123 struct dirent *finfo;
1129 unsigned int name_len;
1130 unsigned int n_size;
1132 GNUNET_assert (dirName != NULL);
1133 dname = GNUNET_STRINGS_filename_expand (dirName);
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 dirName 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 *dirName,
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 (dirName);
1331 if (di->directory == NULL)
1334 callback (callback_cls, NULL, NULL, NULL);
1335 return GNUNET_SYSERR;
1337 di->dirname = GNUNET_strdup (dirName);
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, const char *dst)
1412 struct GNUNET_DISK_FileHandle *in;
1413 struct GNUNET_DISK_FileHandle *out;
1415 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1416 return GNUNET_SYSERR;
1418 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ,
1419 GNUNET_DISK_PERM_NONE);
1421 return GNUNET_SYSERR;
1423 GNUNET_DISK_file_open (dst,
1424 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE |
1425 GNUNET_DISK_OPEN_FAILIFEXISTS,
1426 GNUNET_DISK_PERM_USER_READ |
1427 GNUNET_DISK_PERM_USER_WRITE |
1428 GNUNET_DISK_PERM_GROUP_READ |
1429 GNUNET_DISK_PERM_GROUP_WRITE);
1432 GNUNET_DISK_file_close (in);
1433 return GNUNET_SYSERR;
1435 buf = GNUNET_malloc (COPY_BLK_SIZE);
1438 len = COPY_BLK_SIZE;
1439 if (len > size - pos)
1441 if (len != GNUNET_DISK_file_read (in, buf, len))
1443 if (len != GNUNET_DISK_file_write (out, buf, len))
1448 GNUNET_DISK_file_close (in);
1449 GNUNET_DISK_file_close (out);
1453 GNUNET_DISK_file_close (in);
1454 GNUNET_DISK_file_close (out);
1455 return GNUNET_SYSERR;
1460 * @brief Removes special characters as ':' from a filename.
1461 * @param fn the filename to canonicalize
1464 GNUNET_DISK_filename_canonicalize (char *fn)
1474 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
1475 c == '<' || c == '>' || c == '|')
1487 * @brief Change owner of a file
1489 * @param filename name of file to change the owner of
1490 * @param user name of the new owner
1491 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1494 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1499 pws = getpwnam (user);
1502 LOG (GNUNET_ERROR_TYPE_ERROR,
1503 _("Cannot obtain information about user `%s': %s\n"), user,
1505 return GNUNET_SYSERR;
1507 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1508 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1515 * Lock a part of a file
1516 * @param fh file handle
1517 * @param lockStart absolute position from where to lock
1518 * @param lockEnd absolute position until where to lock
1519 * @param excl GNUNET_YES for an exclusive lock
1520 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1523 GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart,
1524 OFF_T lockEnd, int excl)
1529 return GNUNET_SYSERR;
1535 memset (&fl, 0, sizeof (struct flock));
1536 fl.l_type = excl ? F_WRLCK : F_RDLCK;
1537 fl.l_whence = SEEK_SET;
1538 fl.l_start = lockStart;
1541 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1544 OFF_T diff = lockEnd - lockStart;
1545 DWORD diff_low, diff_high;
1546 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1547 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1549 memset (&o, 0, sizeof (OVERLAPPED));
1550 o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);;
1551 o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1554 (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1555 0, diff_low, diff_high, &o))
1557 SetErrnoFromWinError (GetLastError ());
1558 return GNUNET_SYSERR;
1567 * Unlock a part of a file
1568 * @param fh file handle
1569 * @param unlockStart absolute position from where to unlock
1570 * @param unlockEnd absolute position until where to unlock
1571 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1574 GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart,
1580 return GNUNET_SYSERR;
1586 memset (&fl, 0, sizeof (struct flock));
1587 fl.l_type = F_UNLCK;
1588 fl.l_whence = SEEK_SET;
1589 fl.l_start = unlockStart;
1590 fl.l_len = unlockEnd;
1592 return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1595 OFF_T diff = unlockEnd - unlockStart;
1596 DWORD diff_low, diff_high;
1597 diff_low = (DWORD) (diff & 0xFFFFFFFF);
1598 diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1600 memset (&o, 0, sizeof (OVERLAPPED));
1601 o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);;
1602 o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1604 if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1606 SetErrnoFromWinError (GetLastError ());
1607 return GNUNET_SYSERR;
1616 * Open a file. Note that the access permissions will only be
1617 * used if a new file is created and if the underlying operating
1618 * system supports the given permissions.
1620 * @param fn file name to be opened
1621 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1622 * @param perm permissions for the newly created file, use
1623 * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this
1624 * call (because of flags)
1625 * @return IO handle on success, NULL on error
1627 struct GNUNET_DISK_FileHandle *
1628 GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags,
1629 enum GNUNET_DISK_AccessPermissions perm)
1632 struct GNUNET_DISK_FileHandle *ret;
1638 wchar_t wexpfn[MAX_PATH + 1];
1645 expfn = GNUNET_STRINGS_filename_expand (fn);
1650 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1651 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1652 else if (flags & GNUNET_DISK_OPEN_READ)
1654 else if (flags & GNUNET_DISK_OPEN_WRITE)
1659 GNUNET_free (expfn);
1662 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1663 oflags |= (O_CREAT | O_EXCL);
1664 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1666 if (flags & GNUNET_DISK_OPEN_APPEND)
1668 if (flags & GNUNET_DISK_OPEN_CREATE)
1670 (void) GNUNET_DISK_directory_create_for_file (expfn);
1672 mode = translate_unix_perms (perm);
1675 fd = open (expfn, oflags
1679 | O_LARGEFILE, mode);
1682 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1683 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1685 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1686 GNUNET_free (expfn);
1693 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1694 access = FILE_READ_DATA | FILE_WRITE_DATA;
1695 else if (flags & GNUNET_DISK_OPEN_READ)
1696 access = FILE_READ_DATA;
1697 else if (flags & GNUNET_DISK_OPEN_WRITE)
1698 access = FILE_WRITE_DATA;
1700 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1704 else if (flags & GNUNET_DISK_OPEN_CREATE)
1706 (void) GNUNET_DISK_directory_create_for_file (expfn);
1707 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1708 disp = CREATE_ALWAYS;
1712 else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1714 disp = TRUNCATE_EXISTING;
1718 disp = OPEN_EXISTING;
1721 if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1722 h = CreateFileW (wexpfn, access,
1723 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1724 disp, FILE_ATTRIBUTE_NORMAL, NULL);
1726 h = INVALID_HANDLE_VALUE;
1727 if (h == INVALID_HANDLE_VALUE)
1730 SetErrnoFromWinError (GetLastError ());
1732 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1733 GNUNET_free (expfn);
1738 if (flags & GNUNET_DISK_OPEN_APPEND)
1739 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1741 SetErrnoFromWinError (GetLastError ());
1742 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1744 GNUNET_free (expfn);
1749 ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1752 ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1756 GNUNET_free (expfn);
1762 * Close an open file
1763 * @param h file handle
1764 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1767 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1773 return GNUNET_SYSERR;
1779 if (!CloseHandle (h->h))
1781 SetErrnoFromWinError (GetLastError ());
1782 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1783 ret = GNUNET_SYSERR;
1785 if (h->oOverlapRead)
1787 if (!CloseHandle (h->oOverlapRead->hEvent))
1789 SetErrnoFromWinError (GetLastError ());
1790 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1791 ret = GNUNET_SYSERR;
1793 GNUNET_free (h->oOverlapRead);
1795 if (h->oOverlapWrite)
1797 if (!CloseHandle (h->oOverlapWrite->hEvent))
1799 SetErrnoFromWinError (GetLastError ());
1800 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1801 ret = GNUNET_SYSERR;
1803 GNUNET_free (h->oOverlapWrite);
1806 if (close (h->fd) != 0)
1808 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1809 ret = GNUNET_SYSERR;
1818 * Get a GNUnet file handle from a W32 handle.
1820 * @param handle native handle
1821 * @return GNUnet file handle corresponding to the W32 handle
1823 struct GNUNET_DISK_FileHandle *
1824 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1826 struct GNUNET_DISK_FileHandle *fh;
1829 enum GNUNET_FILE_Type ftype;
1831 dwret = GetFileType (osfh);
1834 case FILE_TYPE_DISK:
1835 ftype = GNUNET_DISK_HANLDE_TYPE_FILE;
1837 case FILE_TYPE_PIPE:
1838 ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1844 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1848 if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1851 * Note that we can't make it overlapped if it isn't already.
1852 * (ReOpenFile() is only available in 2003/Vista).
1853 * The process that opened this file in the first place (usually a parent
1854 * process, if this is stdin/stdout/stderr) must make it overlapped,
1855 * otherwise we're screwed, as selecting on non-overlapped handle
1858 fh->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
1859 fh->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
1860 fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1861 fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1869 * Get a handle from a native integer FD.
1871 * @param fno native integer file descriptor
1872 * @return file handle corresponding to the descriptor, NULL on error
1874 struct GNUNET_DISK_FileHandle *
1875 GNUNET_DISK_get_handle_from_int_fd (int fno)
1877 struct GNUNET_DISK_FileHandle *fh;
1879 if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1881 return NULL; /* invalid FD */
1884 fh = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
1890 osfh = _get_osfhandle (fno);
1891 if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1894 fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1902 * Get a handle from a native streaming FD.
1904 * @param fd native streaming file descriptor
1905 * @return file handle corresponding to the descriptor
1907 struct GNUNET_DISK_FileHandle *
1908 GNUNET_DISK_get_handle_from_native (FILE *fd)
1916 return GNUNET_DISK_get_handle_from_int_fd (fno);
1921 * Construct full path to a file inside of the private
1922 * directory used by GNUnet. Also creates the corresponding
1923 * directory. If the resulting name is supposed to be
1924 * a directory, end the last argument in '/' (or pass
1925 * DIR_SEPARATOR_STR as the last argument before NULL).
1927 * @param cfg configuration to use (determines HOME)
1928 * @param serviceName name of the service
1929 * @param ... is NULL-terminated list of
1930 * path components to append to the
1931 * private directory name.
1932 * @return the constructed filename
1935 GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
1936 const char *serviceName, ...)
1942 unsigned int needed;
1945 GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx))
1949 LOG (GNUNET_ERROR_TYPE_WARNING,
1950 _("No `%s' specified for service `%s' in configuration.\n"), "HOME",
1954 needed = strlen (pfx) + 2;
1955 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1957 va_start (ap, serviceName);
1960 c = va_arg (ap, const char *);
1964 needed += strlen (c);
1965 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1969 ret = GNUNET_malloc (needed);
1972 va_start (ap, serviceName);
1975 c = va_arg (ap, const char *);
1979 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1980 strcat (ret, DIR_SEPARATOR_STR);
1984 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1985 (void) GNUNET_DISK_directory_create_for_file (ret);
1987 (void) GNUNET_DISK_directory_create (ret);
1993 * Handle for a memory-mapping operation.
1995 struct GNUNET_DISK_MapHandle
1998 * Address where the map is in memory.
2004 * Underlying OS handle.
2009 * Number of bytes mapped.
2017 #define MAP_FAILED ((void *) -1)
2021 * Map a file into memory
2023 * @param h open file handle
2024 * @param m handle to the new mapping
2025 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
2026 * @param len size of the mapping
2027 * @return pointer to the mapped memory region, NULL on failure
2030 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
2031 struct GNUNET_DISK_MapHandle **m,
2032 enum GNUNET_DISK_MapType access, size_t len)
2041 DWORD mapAccess, protect;
2043 if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2044 (access & GNUNET_DISK_MAP_TYPE_WRITE))
2046 protect = PAGE_READWRITE;
2047 mapAccess = FILE_MAP_ALL_ACCESS;
2049 else if (access & GNUNET_DISK_MAP_TYPE_READ)
2051 protect = PAGE_READONLY;
2052 mapAccess = FILE_MAP_READ;
2054 else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2056 protect = PAGE_READWRITE;
2057 mapAccess = FILE_MAP_WRITE;
2065 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2066 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2067 if ((*m)->h == INVALID_HANDLE_VALUE)
2069 SetErrnoFromWinError (GetLastError ());
2074 (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2077 SetErrnoFromWinError (GetLastError ());
2078 CloseHandle ((*m)->h);
2087 if (access & GNUNET_DISK_MAP_TYPE_READ)
2089 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2091 *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
2092 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2093 GNUNET_assert (NULL != (*m)->addr);
2094 if (MAP_FAILED == (*m)->addr)
2106 * @param h mapping handle
2107 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2110 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
2117 return GNUNET_SYSERR;
2121 ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2122 if (ret != GNUNET_OK)
2123 SetErrnoFromWinError (GetLastError ());
2124 if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2126 ret = GNUNET_SYSERR;
2127 SetErrnoFromWinError (GetLastError ());
2130 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2138 * Write file changes to disk
2139 * @param h handle to an open file
2140 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2143 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
2148 return GNUNET_SYSERR;
2154 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2155 if (ret != GNUNET_OK)
2156 SetErrnoFromWinError (GetLastError ());
2158 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2159 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2161 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2168 #define PIPE_BUF 512
2170 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2171 http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2173 /* Create a pipe, and return handles to the read and write ends,
2174 just like CreatePipe, but ensure that the write end permits
2175 FILE_READ_ATTRIBUTES access, on later versions of win32 where
2176 this is supported. This access is needed by NtQueryInformationFile,
2177 which is used to implement select and nonblocking writes.
2178 Note that the return value is either NO_ERROR or GetLastError,
2179 unlike CreatePipe, which returns a bool for success or failure. */
2181 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2182 LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2183 DWORD dwReadMode, DWORD dwWriteMode)
2185 /* Default to error. */
2186 *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2191 /* Ensure that there is enough pipe buffer space for atomic writes. */
2192 if (psize < PIPE_BUF)
2195 char pipename[MAX_PATH];
2197 /* Retry CreateNamedPipe as long as the pipe name is in use.
2198 * Retrying will probably never be necessary, but we want
2199 * to be as robust as possible. */
2202 static volatile LONG pipe_unique_id;
2204 snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2205 getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2206 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2208 /* Use CreateNamedPipe instead of CreatePipe, because the latter
2209 * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2210 * access, on versions of win32 earlier than WinXP SP2.
2211 * CreatePipe also stupidly creates a full duplex pipe, which is
2212 * a waste, since only a single direction is actually used.
2213 * It's important to only allow a single instance, to ensure that
2214 * the pipe was not created earlier by some other process, even if
2215 * the pid has been reused. */
2216 read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2217 psize, /* output buffer size */
2218 psize, /* input buffer size */
2219 NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2221 if (read_pipe != INVALID_HANDLE_VALUE)
2223 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2227 DWORD err = GetLastError ();
2231 case ERROR_PIPE_BUSY:
2232 /* The pipe is already open with compatible parameters.
2233 * Pick a new name and retry. */
2234 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2236 case ERROR_ACCESS_DENIED:
2237 /* The pipe is already open with incompatible parameters.
2238 * Pick a new name and retry. */
2239 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2241 case ERROR_CALL_NOT_IMPLEMENTED:
2242 /* We are on an older Win9x platform without named pipes.
2243 * Return an anonymous pipe as the best approximation. */
2244 LOG (GNUNET_ERROR_TYPE_DEBUG,
2245 "CreateNamedPipe not implemented, resorting to "
2246 "CreatePipe: size = %lu\n", psize);
2247 if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2249 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2254 err = GetLastError ();
2255 LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2258 LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2263 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2265 /* Open the named pipe for writing.
2266 * Be sure to permit FILE_READ_ATTRIBUTES access. */
2267 write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2268 sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2269 0); /* handle to template file */
2271 if (write_pipe == INVALID_HANDLE_VALUE)
2274 DWORD err = GetLastError ();
2276 LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2277 CloseHandle (read_pipe);
2280 LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2282 *read_pipe_ptr = read_pipe;
2283 *write_pipe_ptr = write_pipe;
2290 * Creates an interprocess channel
2292 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2293 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2294 * @param inherit_read inherit the parent processes stdin (only for windows)
2295 * @param inherit_write inherit the parent processes stdout (only for windows)
2296 * @return handle to the new pipe, NULL on error
2298 struct GNUNET_DISK_PipeHandle *
2299 GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write)
2310 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
2314 return GNUNET_DISK_pipe_from_fd (blocking_read,
2318 struct GNUNET_DISK_PipeHandle *p;
2323 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2324 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2325 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2327 /* All pipes are overlapped. If you want them to block - just
2328 * call WriteFile() and ReadFile() with NULL overlapped pointer.
2329 * NOTE: calling with NULL overlapped pointer works only
2330 * for pipes, and doesn't seem to be a documented feature.
2331 * It will NOT work for files, because overlapped files need
2332 * to read offsets from the overlapped structure, regardless.
2333 * Pipes are not seekable, and need no offsets, which is
2334 * probably why it works for them.
2337 create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2338 FILE_FLAG_OVERLAPPED,
2339 FILE_FLAG_OVERLAPPED);
2342 SetErrnoFromWinError (GetLastError ());
2344 GNUNET_free (p->fd[0]);
2345 GNUNET_free (p->fd[1]);
2350 if (!DuplicateHandle
2351 (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2352 inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2354 SetErrnoFromWinError (GetLastError ());
2356 CloseHandle (p->fd[0]->h);
2357 CloseHandle (p->fd[1]->h);
2358 GNUNET_free (p->fd[0]);
2359 GNUNET_free (p->fd[1]);
2364 CloseHandle (p->fd[0]->h);
2365 p->fd[0]->h = tmp_handle;
2367 if (!DuplicateHandle
2368 (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2369 inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2371 SetErrnoFromWinError (GetLastError ());
2373 CloseHandle (p->fd[0]->h);
2374 CloseHandle (p->fd[1]->h);
2375 GNUNET_free (p->fd[0]);
2376 GNUNET_free (p->fd[1]);
2381 CloseHandle (p->fd[1]->h);
2382 p->fd[1]->h = tmp_handle;
2384 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2385 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2387 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2388 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2389 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2390 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2392 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2393 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2395 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2396 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2404 * Creates a pipe object from a couple of file descriptors.
2405 * Useful for wrapping existing pipe FDs.
2407 * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO
2408 * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO
2409 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
2411 * @return handle to the new pipe, NULL on error
2413 struct GNUNET_DISK_PipeHandle *
2414 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2416 struct GNUNET_DISK_PipeHandle *p;
2418 p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle));
2423 int eno = 0; /* make gcc happy */
2428 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2429 p->fd[0]->fd = fd[0];
2432 flags = fcntl (fd[0], F_GETFL);
2433 flags |= O_NONBLOCK;
2434 if (0 > fcntl (fd[0], F_SETFL, flags))
2440 flags = fcntl (fd[0], F_GETFD);
2441 flags |= FD_CLOEXEC;
2442 if (0 > fcntl (fd[0], F_SETFD, flags))
2451 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2452 p->fd[1]->fd = fd[1];
2453 if (!blocking_write)
2455 flags = fcntl (fd[1], F_GETFL);
2456 flags |= O_NONBLOCK;
2457 if (0 > fcntl (fd[1], F_SETFL, flags))
2463 flags = fcntl (fd[1], F_GETFD);
2464 flags |= FD_CLOEXEC;
2465 if (0 > fcntl (fd[1], F_SETFD, flags))
2474 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
2475 if (p->fd[0]->fd >= 0)
2476 GNUNET_break (0 == close (p->fd[0]->fd));
2477 if (p->fd[1]->fd >= 0)
2478 GNUNET_break (0 == close (p->fd[1]->fd));
2479 GNUNET_free_non_null (p->fd[0]);
2480 GNUNET_free_non_null (p->fd[1]);
2488 p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2489 p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2490 if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2492 p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2493 p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2494 p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2495 p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2496 p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2500 GNUNET_free (p->fd[0]);
2506 p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
2507 p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2508 if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2510 p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2511 p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED));
2512 p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED));
2513 p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2514 p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2518 GNUNET_free (p->fd[1]);
2529 * Closes an interprocess channel
2531 * @param p pipe to close
2532 * @param end which end of the pipe to close
2533 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2536 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
2537 enum GNUNET_DISK_PipeEnd end)
2539 int ret = GNUNET_OK;
2541 if (end == GNUNET_DISK_PIPE_END_READ)
2545 ret = GNUNET_DISK_file_close (p->fd[0]);
2549 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2553 ret = GNUNET_DISK_file_close (p->fd[1]);
2562 * Detaches one of the ends from the pipe.
2563 * Detached end is a fully-functional FileHandle, it will
2564 * not be affected by anything you do with the pipe afterwards.
2565 * Each end of a pipe can only be detched from it once (i.e.
2566 * it is not duplicated).
2568 * @param p pipe to detach an end from
2569 * @param end which end of the pipe to detach
2570 * @return Detached end on success, NULL on failure
2571 * (or if that end is not present or is closed).
2573 struct GNUNET_DISK_FileHandle *
2574 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
2575 enum GNUNET_DISK_PipeEnd end)
2577 struct GNUNET_DISK_FileHandle *ret = NULL;
2579 if (end == GNUNET_DISK_PIPE_END_READ)
2587 else if (end == GNUNET_DISK_PIPE_END_WRITE)
2601 * Closes an interprocess channel
2603 * @param p pipe to close
2604 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2607 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
2609 int ret = GNUNET_OK;
2612 int write_end_close;
2613 int read_end_close_errno;
2614 int write_end_close_errno;
2616 read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
2617 read_end_close_errno = errno;
2618 write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
2619 write_end_close_errno = errno;
2622 if (GNUNET_OK != read_end_close)
2624 errno = read_end_close_errno;
2625 ret = read_end_close;
2627 else if (GNUNET_OK != write_end_close)
2629 errno = write_end_close_errno;
2630 ret = write_end_close;
2638 * Get the handle to a particular pipe end
2641 * @param n end to access
2642 * @return handle for the respective end
2644 const struct GNUNET_DISK_FileHandle *
2645 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
2646 enum GNUNET_DISK_PipeEnd n)
2650 case GNUNET_DISK_PIPE_END_READ:
2651 case GNUNET_DISK_PIPE_END_WRITE:
2661 * Retrieve OS file handle
2663 * @param fh GNUnet file descriptor
2664 * @param dst destination buffer
2665 * @param dst_len length of dst
2666 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
2669 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
2670 void *dst, size_t dst_len)
2673 if (dst_len < sizeof (HANDLE))
2674 return GNUNET_SYSERR;
2675 *((HANDLE *) dst) = fh->h;
2677 if (dst_len < sizeof (int))
2678 return GNUNET_SYSERR;
2679 *((int *) dst) = fh->fd;