2 This file is part of GNUnet.
3 (C) 2001, 2002, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief disk IO convenience methods
24 * @author Christian Grothoff
29 #include "io_handle.h"
30 #include "gnunet_common.h"
31 #include "gnunet_directories.h"
32 #include "gnunet_io_lib.h"
33 #include "gnunet_disk_lib.h"
34 #include "gnunet_scheduler_lib.h"
35 #include "gnunet_strings_lib.h"
42 #include <sys/param.h>
43 #include <sys/mount.h>
46 #include <sys/param.h>
47 #include <sys/mount.h>
50 #include <sys/types.h>
51 #include <sys/statvfs.h>
54 #define _IFMT 0170000 /* type of file */
55 #define _IFLNK 0120000 /* symbolic link */
56 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
58 #error PORT-ME: need to port statfs (how much space is left on the drive?)
75 unsigned long long total;
76 int include_sym_links;
80 getSizeRec (void *ptr, const char *fn)
82 GetFileSizeData *gfsd = ptr;
90 if (0 != STAT64 (fn, &buf))
92 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat64", fn);
96 if (0 != STAT (fn, &buf))
98 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", fn);
102 if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
103 gfsd->total += buf.st_size;
104 if ((S_ISDIR (buf.st_mode)) &&
105 (0 == ACCESS (fn, X_OK)) &&
106 ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
108 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd))
109 return GNUNET_SYSERR;
116 * Move the read/write pointer in a file
117 * @param h handle of an open file
118 * @param offset position to move to
119 * @param whence specification to which position the offset parameter relates to
120 * @return the new position on success, GNUNET_SYSERR otherwise
123 GNUNET_DISK_file_seek (const struct GNUNET_IO_Handle *h, off_t offset,
124 enum GNUNET_DISK_Seek whence)
129 return GNUNET_SYSERR;
134 static DWORD t[] = { [GNUNET_SEEK_SET] = FILE_BEGIN,
135 [GNUNET_SEEK_CUR] = FILE_CURRENT, [GNUNET_SEEK_END] = FILE_END };
137 ret = SetFilePointer (h->h, offset, NULL, t[whence]);
138 if (ret == INVALID_SET_FILE_POINTER)
140 SetErrnoFromWinError (GetLastError ());
141 return GNUNET_SYSERR;
145 static int t[] = { [GNUNET_SEEK_SET] = SEEK_SET,
146 [GNUNET_SEEK_CUR] = SEEK_CUR, [GNUNET_SEEK_END] = SEEK_END };
148 return lseek (h->fd, offset, t[whence]);
153 * Get the size of the file (or directory)
154 * of the given file (in bytes).
156 * @return GNUNET_SYSERR on error, GNUNET_OK on success
159 GNUNET_DISK_file_size (const char *filename,
160 unsigned long long *size, int includeSymLinks)
162 GetFileSizeData gfsd;
165 GNUNET_assert (size != NULL);
167 gfsd.include_sym_links = includeSymLinks;
168 ret = getSizeRec (&gfsd, filename);
175 * Get the number of blocks that are left on the partition that
176 * contains the given file (for normal users).
178 * @param part a file on the partition to check
179 * @return -1 on errors, otherwise the number of free blocks
182 GNUNET_DISK_get_blocks_available (const char *part)
187 if (0 != statvfs (part, &buf))
189 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
198 memcpy (szDrive, part, 3);
200 if (!GetDiskFreeSpace (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy))
202 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
203 _("`%s' failed for drive `%s': %u\n"),
204 "GetDiskFreeSpace", szDrive, GetLastError ());
211 if (0 != statfs (part, &s))
213 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "statfs", part);
221 * Test if fil is a directory.
223 * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it
227 GNUNET_DISK_directory_test (const char *fil)
229 struct stat filestat;
232 ret = STAT (fil, &filestat);
237 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
238 return GNUNET_SYSERR;
242 if (!S_ISDIR (filestat.st_mode))
244 if (ACCESS (fil, R_OK | X_OK) < 0)
246 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "access", fil);
247 return GNUNET_SYSERR;
253 * Check that fil corresponds to a filename
254 * (of a file that exists and that is not a directory).
255 * @returns GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something
256 * else (will print an error message in that case, too).
259 GNUNET_DISK_file_test (const char *fil)
261 struct stat filestat;
265 rdir = GNUNET_STRINGS_filename_expand (fil);
267 return GNUNET_SYSERR;
269 ret = STAT (rdir, &filestat);
274 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", rdir);
276 return GNUNET_SYSERR;
281 if (!S_ISREG (filestat.st_mode))
286 if (ACCESS (rdir, R_OK) < 0)
288 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "access", rdir);
290 return GNUNET_SYSERR;
297 * Implementation of "mkdir -p"
298 * @param dir the directory to create
299 * @returns GNUNET_OK on success, GNUNET_SYSERR on failure
302 GNUNET_DISK_directory_create (const char *dir)
309 rdir = GNUNET_STRINGS_filename_expand (dir);
311 return GNUNET_SYSERR;
315 pos = 1; /* skip heading '/' */
317 /* Local or Network path? */
318 if (strncmp (rdir, "\\\\", 2) == 0)
323 if (rdir[pos] == '\\')
333 pos = 3; /* strlen("C:\\") */
338 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
341 ret = GNUNET_DISK_directory_test (rdir);
342 if (ret == GNUNET_SYSERR)
345 return GNUNET_SYSERR;
347 if (ret == GNUNET_NO)
350 ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
354 if ((ret != 0) && (errno != EEXIST))
356 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir",
359 return GNUNET_SYSERR;
362 rdir[pos] = DIR_SEPARATOR;
372 * Create the directory structure for storing
375 * @param filename name of a file in the directory
376 * @returns GNUNET_OK on success,
377 * GNUNET_SYSERR on failure,
378 * GNUNET_NO if the directory
379 * exists but is not writeable for us
382 GNUNET_DISK_directory_create_for_file (const char *dir)
388 rdir = GNUNET_STRINGS_filename_expand (dir);
390 return GNUNET_SYSERR;
392 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
395 ret = GNUNET_DISK_directory_create (rdir);
396 if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK)))
403 * Read the contents of a binary file into a buffer.
404 * @param h handle to an open file
405 * @param result the buffer to write the result to
406 * @param len the maximum number of bytes to read
407 * @return the number of bytes read on success, GNUNET_SYSERR on failure
410 GNUNET_DISK_file_read (const struct GNUNET_IO_Handle *h, void *result, int len)
415 return GNUNET_SYSERR;
421 if (!ReadFile (h->h, result, len, &bytesRead, NULL))
423 SetErrnoFromWinError (GetLastError ());
424 return GNUNET_SYSERR;
428 return read (h->fd, result, len);
434 * Read the contents of a binary file into a buffer.
435 * @param fn file name
436 * @param result the buffer to write the result to
437 * @param len the maximum number of bytes to read
438 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
441 GNUNET_DISK_fn_read (const char * const fn, void *result, int len)
443 struct GNUNET_IO_Handle *fh;
446 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ);
448 return GNUNET_SYSERR;
449 ret = (len == GNUNET_DISK_file_read (fh, result, len)) ? GNUNET_OK : GNUNET_SYSERR;
450 GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(&fh));
457 * Convert string to value ('755' for chmod-call)
464 while (('0' <= *s) && (*s < '8'))
473 * Write a buffer to a file.
474 * @param h handle to open file
475 * @param buffer the data to write
476 * @param n number of bytes to write
477 * @return number of bytes written on success, GNUNET_SYSERR on error
480 GNUNET_DISK_file_write (const struct GNUNET_IO_Handle *h, const void *buffer,
486 return GNUNET_SYSERR;
492 if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
494 SetErrnoFromWinError (GetLastError ());
495 return GNUNET_SYSERR;
499 return write (h->fd, buffer, n);
504 * Write a buffer to a file.
505 * @param fn file name
506 * @param buffer the data to write
507 * @param n number of bytes to write
508 * @return GNUNET_OK on success, GNUNET_SYSERR on error
511 GNUNET_DISK_fn_write (const char * const fn, const void *buffer,
512 unsigned int n, int mode)
514 struct GNUNET_IO_Handle *fh;
517 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE
518 | GNUNET_DISK_OPEN_CREATE, mode);
520 return GNUNET_SYSERR;
521 ret = (n == GNUNET_DISK_file_write (fh, buffer, n)) ? GNUNET_OK : GNUNET_SYSERR;
522 GNUNET_assert(GNUNET_OK == GNUNET_DISK_file_close(&fh));
528 * Scan a directory for files. The name of the directory
529 * must be expanded first (!).
530 * @param dirName the name of the directory
531 * @param callback the method to call for each file,
532 * can be NULL, in that case, we only count
533 * @param data argument to pass to callback
534 * @return the number of files found, GNUNET_SYSERR on error or
535 * ieration aborted by callback returning GNUNET_SYSERR
538 GNUNET_DISK_directory_scan (const char *dirName,
539 GNUNET_FileNameCallback callback, void *data)
542 struct dirent *finfo;
547 unsigned int name_len;
550 GNUNET_assert (dirName != NULL);
551 dname = GNUNET_STRINGS_filename_expand (dirName);
552 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
553 dname[strlen (dname) - 1] = '\0';
554 if (0 != STAT (dname, &istat))
556 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
558 return GNUNET_SYSERR;
560 if (!S_ISDIR (istat.st_mode))
562 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
563 _("Expected `%s' to be a directory!\n"), dirName);
565 return GNUNET_SYSERR;
568 dinfo = OPENDIR (dname);
569 if ((errno == EACCES) || (dinfo == NULL))
571 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
575 return GNUNET_SYSERR;
578 n_size = strlen (dname) + name_len + 2;
579 name = GNUNET_malloc (n_size);
580 while ((finfo = readdir (dinfo)) != NULL)
582 if ((0 == strcmp (finfo->d_name, ".")) ||
583 (0 == strcmp (finfo->d_name, "..")))
585 if (callback != NULL)
587 if (name_len < strlen (finfo->d_name))
590 name_len = strlen (finfo->d_name);
591 n_size = strlen (dname) + name_len + 2;
592 name = GNUNET_malloc (n_size);
594 /* dname can end in "/" only if dname == "/";
595 if dname does not end in "/", we need to add
596 a "/" (otherwise, we must not!) */
597 GNUNET_snprintf (name,
601 (strcmp (dname, DIR_SEPARATOR_STR) ==
602 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name);
603 if (GNUNET_OK != callback (data, name))
608 return GNUNET_SYSERR;
621 * Opaque handle used for iterating over a directory.
623 struct GNUNET_DISK_DirectoryIterator
628 struct GNUNET_SCHEDULER_Handle *sched;
631 * Function to call on directory entries.
633 GNUNET_DISK_DirectoryIteratorCallback callback;
636 * Closure for callback.
641 * Reference to directory.
651 * Next filename to process.
658 enum GNUNET_SCHEDULER_Priority priority;
664 * Task used by the directory iterator.
667 directory_iterator_task (void *cls,
668 const struct GNUNET_SCHEDULER_TaskContext *tc)
670 struct GNUNET_DISK_DirectoryIterator *iter = cls;
673 name = iter->next_name;
674 GNUNET_assert (name != NULL);
675 iter->next_name = NULL;
676 iter->callback (iter->callback_cls, iter, name, iter->dirname);
682 * This function must be called during the DiskIteratorCallback
683 * (exactly once) to schedule the task to process the next
684 * filename in the directory (if there is one).
686 * @param iter opaque handle for the iterator
687 * @param can set to GNUNET_YES to terminate the iteration early
688 * @return GNUNET_YES if iteration will continue,
689 * GNUNET_NO if this was the last entry (and iteration is complete),
690 * GNUNET_SYSERR if abort was YES
693 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator
696 struct dirent *finfo;
698 GNUNET_assert (iter->next_name == NULL);
699 if (can == GNUNET_YES)
701 closedir (iter->directory);
702 GNUNET_free (iter->dirname);
704 return GNUNET_SYSERR;
706 while (NULL != (finfo = readdir (iter->directory)))
708 if ((0 == strcmp (finfo->d_name, ".")) ||
709 (0 == strcmp (finfo->d_name, "..")))
711 GNUNET_asprintf (&iter->next_name,
713 iter->dirname, DIR_SEPARATOR_STR, finfo->d_name);
718 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
721 GNUNET_SCHEDULER_add_after (iter->sched,
724 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
725 &directory_iterator_task, iter);
731 * Scan a directory for files using the scheduler to run a task for
732 * each entry. The name of the directory must be expanded first (!).
733 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
734 * may provide a simpler API.
736 * @param sched scheduler to use
737 * @param prio priority to use
738 * @param dirName the name of the directory
739 * @param callback the method to call for each file
740 * @param callback_cls closure for callback
743 GNUNET_DISK_directory_iterator_start (struct GNUNET_SCHEDULER_Handle *sched,
744 enum GNUNET_SCHEDULER_Priority prio,
746 GNUNET_DISK_DirectoryIteratorCallback
747 callback, void *callback_cls)
749 struct GNUNET_DISK_DirectoryIterator *di;
751 di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator));
753 di->callback = callback;
754 di->callback_cls = callback_cls;
755 di->directory = OPENDIR (dirName);
756 di->dirname = GNUNET_strdup (dirName);
758 GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
763 remove_helper (void *unused, const char *fn)
765 GNUNET_DISK_directory_remove (fn);
770 * Remove all files in a directory (rm -rf). Call with
774 * @param fileName the file to remove
775 * @return GNUNET_OK on success, GNUNET_SYSERR on error
778 GNUNET_DISK_directory_remove (const char *fileName)
782 if (0 != LSTAT (fileName, &istat))
783 return GNUNET_NO; /* file may not exist... */
784 if (UNLINK (fileName) == 0)
786 if ((errno != EISDIR) &&
787 /* EISDIR is not sufficient in all cases, e.g.
788 sticky /tmp directory may result in EPERM on BSD.
789 So we also explicitly check "isDirectory" */
790 (GNUNET_YES != GNUNET_DISK_directory_test (fileName)))
792 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
793 return GNUNET_SYSERR;
796 GNUNET_DISK_directory_scan (fileName, remove_helper, NULL))
797 return GNUNET_SYSERR;
798 if (0 != RMDIR (fileName))
800 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName);
801 return GNUNET_SYSERR;
806 #define COPY_BLK_SIZE 65536
810 * @return GNUNET_OK on success, GNUNET_SYSERR on error
813 GNUNET_DISK_file_copy (const char *src, const char *dst)
816 unsigned long long pos;
817 unsigned long long size;
818 unsigned long long len;
819 struct GNUNET_IO_Handle *in, *out;
821 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES))
822 return GNUNET_SYSERR;
824 in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ);
826 return GNUNET_SYSERR;
827 out = GNUNET_DISK_file_open (dst, GNUNET_DISK_OPEN_WRITE
828 | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS,
829 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
830 | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_GROUP_WRITE);
833 GNUNET_DISK_file_close (&in);
834 return GNUNET_SYSERR;
836 buf = GNUNET_malloc (COPY_BLK_SIZE);
840 if (len > size - pos)
842 if (len != GNUNET_DISK_file_read (in, buf, len))
844 if (len != GNUNET_DISK_file_write (out, buf, len))
849 GNUNET_DISK_file_close (&in);
850 GNUNET_DISK_file_close (&out);
854 GNUNET_DISK_file_close (&in);
855 GNUNET_DISK_file_close (&out);
856 return GNUNET_SYSERR;
861 * @brief Removes special characters as ':' from a filename.
862 * @param fn the filename to canonicalize
865 GNUNET_DISK_filename_canonicalize (char *fn)
875 if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' ||
876 c == '"' || c == '<' || c == '>' || c == '|')
888 * @brief Change owner of a file
891 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
896 pws = getpwnam (user);
899 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
900 _("Cannot obtain information about user `%s': %s\n"),
901 user, STRERROR (errno));
902 return GNUNET_SYSERR;
904 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
905 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
912 * Lock a part of a file
913 * @param fh file handle
914 * @lockStart absolute position from where to lock
915 * @lockEnd absolute position until where to lock
916 * @return GNUNET_OK on success, GNUNET_SYSERR on error
919 GNUNET_DISK_file_lock(struct GNUNET_IO_Handle *fh, off_t lockStart,
925 return GNUNET_SYSERR;
931 memset(&fl, 0, sizeof(struct flock));
933 fl.l_whence = SEEK_SET;
934 fl.l_start = lockStart;
937 return fcntl(fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
939 if (!LockFile(fh->h, 0, lockStart, 0, lockEnd))
941 SetErrnoFromWinError(GetLastError());
942 return GNUNET_SYSERR;
952 * @param fn file name to be opened
953 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
954 * @param perm permissions for the newly created file
955 * @return IO handle on success, NULL on error
957 struct GNUNET_IO_Handle *
958 GNUNET_DISK_file_open (const char *fn, int flags, ...)
961 struct GNUNET_IO_Handle *ret;
970 expfn = GNUNET_STRINGS_filename_expand (fn);
974 if (flags & GNUNET_DISK_OPEN_READ)
976 if (flags & GNUNET_DISK_OPEN_WRITE)
978 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
979 oflags |= (O_CREAT & O_EXCL);
980 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
982 if (flags & GNUNET_DISK_OPEN_CREATE)
989 va_start (arg, flags);
990 perm = va_arg (arg, int);
994 if (perm & GNUNET_DISK_PERM_USER_READ)
996 if (perm & GNUNET_DISK_PERM_USER_WRITE)
998 if (perm & GNUNET_DISK_PERM_USER_EXEC)
1000 if (perm & GNUNET_DISK_PERM_GROUP_READ)
1002 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
1004 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
1006 if (perm & GNUNET_DISK_PERM_OTHER_READ)
1008 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
1010 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
1013 if (flags & GNUNET_DISK_OPEN_APPEND)
1016 fd = open (expfn, oflags | O_LARGEFILE, mode);
1019 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", fn);
1026 if (flags & GNUNET_DISK_OPEN_READ)
1027 access = FILE_READ_DATA;
1028 if (flags & GNUNET_DISK_OPEN_WRITE)
1029 access = FILE_WRITE_DATA;
1031 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1033 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1034 disp = TRUNCATE_EXISTING;
1035 if (flags & GNUNET_DISK_OPEN_CREATE)
1036 disp |= OPEN_ALWAYS;
1038 /* TODO: access priviledges? */
1039 h = CreateFile (expfn, access, FILE_SHARE_DELETE | FILE_SHARE_READ
1040 | FILE_SHARE_WRITE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
1041 if (h == INVALID_HANDLE_VALUE)
1043 SetErrnoFromWinError (GetLastError ());
1044 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", fn);
1048 if (flags & GNUNET_DISK_OPEN_APPEND)
1049 if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1051 SetErrnoFromWinError (GetLastError ());
1052 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", fn);
1058 ret = (struct GNUNET_IO_Handle *) GNUNET_malloc(sizeof(struct GNUNET_IO_Handle));
1069 * Close an open file
1070 * @param h file handle
1071 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1074 GNUNET_DISK_file_close (struct GNUNET_IO_Handle **h)
1079 return GNUNET_SYSERR;
1083 if (!CloseHandle ((*h)->h))
1085 SetErrnoFromWinError (GetLastError ());
1086 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
1087 return GNUNET_SYSERR;
1090 if (close ((*h)->fd) != 0)
1092 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
1093 return GNUNET_SYSERR;
1097 GNUNET_IO_handle_invalidate (*h);
1105 * Construct full path to a file inside of the private
1106 * directory used by GNUnet. Also creates the corresponding
1107 * directory. If the resulting name is supposed to be
1108 * a directory, end the last argument in '/' (or pass
1109 * DIR_SEPARATOR_STR as the last argument before NULL).
1111 * @param serviceName name of the service
1112 * @param varargs is NULL-terminated list of
1113 * path components to append to the
1114 * private directory name.
1115 * @return the constructed filename
1118 GNUNET_DISK_get_home_filename (struct GNUNET_CONFIGURATION_Handle *cfg,
1119 const char *serviceName, ...)
1125 unsigned int needed;
1128 GNUNET_CONFIGURATION_get_value_filename (cfg,
1129 serviceName, "HOME", &pfx))
1133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1134 _("No `%s' specified for service `%s' in configuration.\n"),
1135 "HOME", serviceName);
1138 needed = strlen (pfx) + 2;
1139 if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\'))
1141 va_start (ap, serviceName);
1144 c = va_arg (ap, const char *);
1147 needed += strlen (c);
1148 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1152 ret = GNUNET_malloc (needed);
1155 va_start (ap, serviceName);
1158 c = va_arg (ap, const char *);
1161 if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\'))
1162 strcat (ret, DIR_SEPARATOR_STR);
1166 if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\'))
1167 GNUNET_DISK_directory_create_for_file (ret);
1169 GNUNET_DISK_directory_create (ret);
1174 * Map a file into memory
1175 * @param h open file handle
1176 * @param m handle to the new mapping
1177 * @param access access specification, GNUNET_DISK_MAP_xxx
1178 * @param len size of the mapping
1179 * @return pointer to the mapped memory region, NULL on failure
1182 GNUNET_DISK_file_map (const struct GNUNET_IO_Handle *h, struct GNUNET_IO_Handle **m,
1183 int access, size_t len)
1192 DWORD mapAccess, protect;
1195 if (access & GNUNET_DISK_MAP_READ && access & GNUNET_DISK_MAP_WRITE)
1197 protect = PAGE_READWRITE;
1198 mapAccess = FILE_MAP_ALL_ACCESS;
1200 else if (access & GNUNET_DISK_MAP_READ)
1202 protect = PAGE_READONLY;
1203 mapAccess = FILE_MAP_READ;
1205 else if (access & GNUNET_DISK_MAP_WRITE)
1207 protect = PAGE_READWRITE;
1208 mapAccess = FILE_MAP_WRITE;
1216 *m = (struct GNUNET_IO_Handle *) GNUNET_malloc (sizeof (struct GNUNET_IO_Handle));
1217 (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
1218 if ((*m)->h == INVALID_HANDLE_VALUE)
1220 SetErrnoFromWinError (GetLastError ());
1225 ret = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
1228 SetErrnoFromWinError (GetLastError ());
1229 CloseHandle ((*m)->h);
1238 if (access & GNUNET_DISK_MAP_READ)
1240 if (access & GNUNET_DISK_MAP_WRITE)
1243 return mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1249 * @param h mapping handle
1250 * @param addr pointer to the mapped memory region
1251 * @param len size of the mapping
1252 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1255 GNUNET_DISK_file_unmap (struct GNUNET_IO_Handle **h, void *addr, size_t len)
1260 if (h == NULL || *h == NULL)
1263 return GNUNET_SYSERR;
1266 ret = UnmapViewOfFile (addr) ? GNUNET_OK : GNUNET_SYSERR;
1267 if (ret != GNUNET_OK)
1268 SetErrnoFromWinError (GetLastError ());
1269 if (!CloseHandle ((*h)->h) && ret == GNUNET_OK)
1271 ret = GNUNET_SYSERR;
1272 SetErrnoFromWinError (GetLastError ());
1275 GNUNET_IO_handle_invalidate (*h);
1282 ret = munmap (addr, len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1283 GNUNET_IO_handle_invalidate (h);
1289 * Write file changes to disk
1290 * @param h handle to an open file
1291 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
1294 GNUNET_DISK_file_sync (const struct GNUNET_IO_Handle *h)
1299 return GNUNET_SYSERR;
1305 ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
1306 if (ret != GNUNET_OK)
1307 SetErrnoFromWinError (GetLastError ());
1310 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;