X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fdisk.c;h=d536ec8979b4297e153ca56a6692707844d45000;hb=5b085881ab278a85c3ef3a1d91c58a5724a4e430;hp=25a01aba6c14f99d9e05b86c771f702b82094247;hpb=a1193adca1ddba0f6ac1c58154ae8377225063a3;p=oweals%2Fgnunet.git diff --git a/src/util/disk.c b/src/util/disk.c index 25a01aba6..d536ec897 100644 --- a/src/util/disk.c +++ b/src/util/disk.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001--2013 Christian Grothoff (and other contributing authors) + Copyright (C) 2001--2013, 2016 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,26 +14,25 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ - /** * @file util/disk.c * @brief disk IO convenience methods * @author Christian Grothoff * @author Nils Durner */ - #include "platform.h" -#include "gnunet_util_lib.h" #include "disk.h" +#include "gnunet_strings_lib.h" +#include "gnunet_disk_lib.h" -#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) +#define LOG(kind,...) GNUNET_log_from (kind, "util-disk", __VA_ARGS__) -#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-disk", syscall) -#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-disk", syscall, filename) /** * Block size for IO for copying files. @@ -330,8 +329,10 @@ GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, BY_HANDLE_FILE_INFORMATION info; int succ; - fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0); - if (fh == NULL) + fh = GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fh) return GNUNET_SYSERR; succ = GetFileInformationByHandle (fh->h, &info); GNUNET_DISK_file_close (fh); @@ -528,14 +529,18 @@ char * GNUNET_DISK_mkdtemp (const char *t) { char *fn; + mode_t omask; + omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH); fn = mktemp_name (t); if (fn != mkdtemp (fn)) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdtemp", fn); GNUNET_free (fn); + umask (omask); return NULL; } + umask (omask); return fn; } @@ -588,14 +593,18 @@ GNUNET_DISK_mktemp (const char *t) { int fd; char *fn; + mode_t omask; + omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH); fn = mktemp_name (t); if (-1 == (fd = mkstemp (fn))) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn); GNUNET_free (fn); + umask (omask); return NULL; } + umask (omask); if (0 != CLOSE (fd)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn); return fn; @@ -609,7 +618,7 @@ GNUNET_DISK_mktemp (const char *t) * with the same name). * * @param fil filename to test - * @param is_readable GNUNET_YES to additionally check if @a fil is readable; + * @param is_readable #GNUNET_YES to additionally check if @a fil is readable; * #GNUNET_NO to disable this check * @return #GNUNET_YES if yes, #GNUNET_NO if not; #GNUNET_SYSERR if it * does not exist or stat'ed @@ -801,8 +810,7 @@ GNUNET_DISK_directory_create (const char *dir) /** - * Create the directory structure for storing - * a file. + * Create the directory structure for storing a file. * * @param filename name of a file in the directory * @returns #GNUNET_OK on success, @@ -816,18 +824,30 @@ GNUNET_DISK_directory_create_for_file (const char *filename) char *rdir; size_t len; int ret; + int eno; rdir = GNUNET_STRINGS_filename_expand (filename); - if (rdir == NULL) + if (NULL == rdir) + { + errno = EINVAL; return GNUNET_SYSERR; + } len = strlen (rdir); while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) len--; rdir[len] = '\0'; + /* The empty path is invalid and in this case refers to / */ + if (0 == len) + { + GNUNET_free (rdir); + rdir = GNUNET_strdup ("/"); + } ret = GNUNET_DISK_directory_create (rdir); - if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK))) + if ((GNUNET_OK == ret) && (0 != ACCESS (rdir, W_OK))) ret = GNUNET_NO; + eno = errno; GNUNET_free (rdir); + errno = eno; return ret; } @@ -868,7 +888,9 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, { if (GetLastError () != ERROR_IO_PENDING) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Error reading from pipe: %u\n", + GetLastError ()); SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } @@ -939,7 +961,9 @@ GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h, return GNUNET_SYSERR; } } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytes_read); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Read %u bytes\n", + bytes_read); } else { @@ -981,13 +1005,17 @@ GNUNET_DISK_fn_read (const char *fn, { struct GNUNET_DISK_FileHandle *fh; ssize_t ret; + int eno; - fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); - if (!fh) + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fh) return GNUNET_SYSERR; ret = GNUNET_DISK_file_read (fh, result, len); + eno = errno; GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); - + errno = eno; return ret; } @@ -1154,7 +1182,9 @@ GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, * @return number of bytes written on success, #GNUNET_SYSERR on error */ ssize_t -GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, +GNUNET_DISK_fn_write (const char *fn, + const void *buffer, + size_t n, enum GNUNET_DISK_AccessPermissions mode) { struct GNUNET_DISK_FileHandle *fh; @@ -1163,7 +1193,7 @@ GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, mode); - if (!fh) + if (! fh) return GNUNET_SYSERR; ret = GNUNET_DISK_file_write (fh, buffer, n); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); @@ -1196,19 +1226,22 @@ GNUNET_DISK_directory_scan (const char *dir_name, unsigned int name_len; unsigned int n_size; - GNUNET_assert (dir_name != NULL); + GNUNET_assert (NULL != dir_name); dname = GNUNET_STRINGS_filename_expand (dir_name); - if (dname == NULL) + if (NULL == dname) return GNUNET_SYSERR; - while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR)) + while ( (strlen (dname) > 0) && + (dname[strlen (dname) - 1] == DIR_SEPARATOR) ) dname[strlen (dname) - 1] = '\0'; if (0 != STAT (dname, &istat)) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, + "stat", + dname); GNUNET_free (dname); return GNUNET_SYSERR; } - if (!S_ISDIR (istat.st_mode)) + if (! S_ISDIR (istat.st_mode)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"), @@ -1218,38 +1251,48 @@ GNUNET_DISK_directory_scan (const char *dir_name, } errno = 0; dinfo = OPENDIR (dname); - if ((errno == EACCES) || (dinfo == NULL)) + if ( (EACCES == errno) || + (NULL == dinfo) ) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname); - if (dinfo != NULL) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, + "opendir", + dname); + if (NULL != dinfo) CLOSEDIR (dinfo); GNUNET_free (dname); return GNUNET_SYSERR; } name_len = 256; - n_size = strlen (dname) + name_len + 2; + n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1; name = GNUNET_malloc (n_size); - while ((finfo = READDIR (dinfo)) != NULL) + while (NULL != (finfo = READDIR (dinfo))) { - if ((0 == strcmp (finfo->d_name, ".")) || - (0 == strcmp (finfo->d_name, ".."))) + if ( (0 == strcmp (finfo->d_name, ".")) || + (0 == strcmp (finfo->d_name, "..")) ) continue; - if (callback != NULL) + if (NULL != callback) { if (name_len < strlen (finfo->d_name)) { GNUNET_free (name); name_len = strlen (finfo->d_name); - n_size = strlen (dname) + name_len + 2; + n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1; name = GNUNET_malloc (n_size); } /* dname can end in "/" only if dname == "/"; * if dname does not end in "/", we need to add * a "/" (otherwise, we must not!) */ - GNUNET_snprintf (name, n_size, "%s%s%s", dname, - (strcmp (dname, DIR_SEPARATOR_STR) == - 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name); - ret = callback (callback_cls, name); + GNUNET_snprintf (name, + n_size, + "%s%s%s", + dname, + (0 == strcmp (dname, + DIR_SEPARATOR_STR)) + ? "" + : DIR_SEPARATOR_STR, + finfo->d_name); + ret = callback (callback_cls, + name); if (GNUNET_OK != ret) { CLOSEDIR (dinfo); @@ -1269,155 +1312,17 @@ GNUNET_DISK_directory_scan (const char *dir_name, } -/** - * Opaque handle used for iterating over a directory. - */ -struct GNUNET_DISK_DirectoryIterator -{ - - /** - * Function to call on directory entries. - */ - GNUNET_DISK_DirectoryIteratorCallback callback; - - /** - * Closure for callback. - */ - void *callback_cls; - - /** - * Reference to directory. - */ - DIR *directory; - - /** - * Directory name. - */ - char *dirname; - - /** - * Next filename to process. - */ - char *next_name; - - /** - * Our priority. - */ - enum GNUNET_SCHEDULER_Priority priority; - -}; - - -/** - * Task used by the directory iterator. - */ -static void -directory_iterator_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_DISK_DirectoryIterator *iter = cls; - char *name; - - name = iter->next_name; - GNUNET_assert (name != NULL); - iter->next_name = NULL; - iter->callback (iter->callback_cls, iter, name, iter->dirname); - GNUNET_free (name); -} - - -/** - * This function must be called during the DiskIteratorCallback - * (exactly once) to schedule the task to process the next - * filename in the directory (if there is one). - * - * @param iter opaque handle for the iterator - * @param can set to GNUNET_YES to terminate the iteration early - * @return GNUNET_YES if iteration will continue, - * GNUNET_NO if this was the last entry (and iteration is complete), - * GNUNET_SYSERR if abort was YES - */ -int -GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter, - int can) -{ - struct dirent *finfo; - - GNUNET_assert (iter->next_name == NULL); - if (can == GNUNET_YES) - { - CLOSEDIR (iter->directory); - GNUNET_free (iter->dirname); - GNUNET_free (iter); - return GNUNET_SYSERR; - } - while (NULL != (finfo = READDIR (iter->directory))) - { - if ((0 == strcmp (finfo->d_name, ".")) || - (0 == strcmp (finfo->d_name, ".."))) - continue; - GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname, - DIR_SEPARATOR_STR, finfo->d_name); - break; - } - if (finfo == NULL) - { - GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES); - return GNUNET_NO; - } - GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task, - iter); - return GNUNET_YES; -} - - -/** - * Scan a directory for files using the scheduler to run a task for - * each entry. The name of the directory must be expanded first (!). - * If a scheduler does not need to be used, GNUNET_DISK_directory_scan - * may provide a simpler API. - * - * @param prio priority to use - * @param dir_name the name of the directory - * @param callback the method to call for each file - * @param callback_cls closure for callback - * @return GNUNET_YES if directory is not empty and 'callback' - * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error. - */ -int -GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio, - const char *dir_name, - GNUNET_DISK_DirectoryIteratorCallback - callback, void *callback_cls) -{ - struct GNUNET_DISK_DirectoryIterator *di; - - di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator); - di->callback = callback; - di->callback_cls = callback_cls; - di->directory = OPENDIR (dir_name); - if (di->directory == NULL) - { - GNUNET_free (di); - callback (callback_cls, NULL, NULL, NULL); - return GNUNET_SYSERR; - } - di->dirname = GNUNET_strdup (dir_name); - di->priority = prio; - return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); -} - - /** * Function that removes the given directory by calling - * "GNUNET_DISK_directory_remove". + * #GNUNET_DISK_directory_remove(). * * @param unused not used * @param fn directory to remove * @return #GNUNET_OK */ static int -remove_helper (void *unused, const char *fn) +remove_helper (void *unused, + const char *fn) { (void) GNUNET_DISK_directory_remove (fn); return GNUNET_OK; @@ -1425,7 +1330,7 @@ remove_helper (void *unused, const char *fn) /** - * Remove all files in a directory (rm -rf). Call with + * Remove all files in a directory (rm -r). Call with * caution. * * @param filename the file to remove @@ -1443,24 +1348,33 @@ GNUNET_DISK_directory_remove (const char *filename) } if (0 != LSTAT (filename, &istat)) return GNUNET_NO; /* file may not exist... */ - (void) CHMOD (filename, S_IWUSR | S_IRUSR | S_IXUSR); - if (UNLINK (filename) == 0) + (void) CHMOD (filename, + S_IWUSR | S_IRUSR | S_IXUSR); + if (0 == UNLINK (filename)) return GNUNET_OK; - if ((errno != EISDIR) && - /* EISDIR is not sufficient in all cases, e.g. - * sticky /tmp directory may result in EPERM on BSD. - * So we also explicitly check "isDirectory" */ - (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES))) - { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename); + if ( (errno != EISDIR) && + /* EISDIR is not sufficient in all cases, e.g. + * sticky /tmp directory may result in EPERM on BSD. + * So we also explicitly check "isDirectory" */ + (GNUNET_YES != + GNUNET_DISK_directory_test (filename, + GNUNET_YES)) ) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, + "rmdir", + filename); return GNUNET_SYSERR; } if (GNUNET_SYSERR == - GNUNET_DISK_directory_scan (filename, &remove_helper, NULL)) + GNUNET_DISK_directory_scan (filename, + &remove_helper, + NULL)) return GNUNET_SYSERR; if (0 != RMDIR (filename)) { - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, + "rmdir", + filename); return GNUNET_SYSERR; } return GNUNET_OK; @@ -1539,8 +1453,7 @@ GNUNET_DISK_filename_canonicalize (char *fn) char *idx; char c; - idx = fn; - while (*idx) + for (idx = fn; *idx; idx++) { c = *idx; @@ -1549,8 +1462,6 @@ GNUNET_DISK_filename_canonicalize (char *fn) { *idx = '_'; } - - idx++; } } @@ -1561,24 +1472,33 @@ GNUNET_DISK_filename_canonicalize (char *fn) * * @param filename name of file to change the owner of * @param user name of the new owner - * @return GNUNET_OK on success, GNUNET_SYSERR on failure + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ int -GNUNET_DISK_file_change_owner (const char *filename, const char *user) +GNUNET_DISK_file_change_owner (const char *filename, + const char *user) { #ifndef MINGW struct passwd *pws; pws = getpwnam (user); - if (pws == NULL) + if (NULL == pws) { LOG (GNUNET_ERROR_TYPE_ERROR, - _("Cannot obtain information about user `%s': %s\n"), user, + _("Cannot obtain information about user `%s': %s\n"), + user, STRERROR (errno)); return GNUNET_SYSERR; } - if (0 != chown (filename, pws->pw_uid, pws->pw_gid)) - LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename); + if (0 != chown (filename, + pws->pw_uid, + pws->pw_gid)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, + "chown", + filename); + return GNUNET_SYSERR; + } #endif return GNUNET_OK; } @@ -1586,15 +1506,18 @@ GNUNET_DISK_file_change_owner (const char *filename, const char *user) /** * Lock a part of a file + * * @param fh file handle * @param lock_start absolute position from where to lock * @param lock_end absolute position until where to lock - * @param excl GNUNET_YES for an exclusive lock - * @return GNUNET_OK on success, GNUNET_SYSERR on error + * @param excl #GNUNET_YES for an exclusive lock + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lock_start, - off_t lock_end, int excl) +GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, + off_t lock_start, + off_t lock_end, + int excl) { if (fh == NULL) { @@ -1638,13 +1561,15 @@ GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lock_start, /** * Unlock a part of a file + * * @param fh file handle * @param unlock_start absolute position from where to unlock * @param unlock_end absolute position until where to unlock * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlock_start, +GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, + off_t unlock_start, off_t unlock_end) { if (fh == NULL) @@ -1833,9 +1758,10 @@ GNUNET_DISK_file_open (const char *fn, /** - * Close an open file + * Close an open file. + * * @param h file handle - * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) @@ -1850,7 +1776,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) ret = GNUNET_OK; #if MINGW - if (!CloseHandle (h->h)) + if (! CloseHandle (h->h)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); @@ -1858,7 +1784,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) } if (h->oOverlapRead) { - if (!CloseHandle (h->oOverlapRead->hEvent)) + if (! CloseHandle (h->oOverlapRead->hEvent)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); @@ -1887,6 +1813,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) return ret; } + #ifdef WINDOWS /** * Get a GNUnet file handle from a W32 handle. @@ -1898,7 +1825,6 @@ struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) { struct GNUNET_DISK_FileHandle *fh; - DWORD dwret; enum GNUNET_FILE_Type ftype; @@ -1912,10 +1838,13 @@ GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) ftype = GNUNET_DISK_HANLDE_TYPE_PIPE; break; case FILE_TYPE_UNKNOWN: - if (GetLastError () == NO_ERROR) + if ( (GetLastError () == NO_ERROR) || + (GetLastError () == ERROR_INVALID_HANDLE) ) { if (0 != ResetEvent (osfh)) ftype = GNUNET_DISK_HANLDE_TYPE_EVENT; + else + return NULL; } else return NULL;