.ico Version of the fancy new logo.
[paraslash.git] / osl.c
diff --git a/osl.c b/osl.c
index b1aaf3e..0b14447 100644 (file)
--- a/osl.c
+++ b/osl.c
@@ -5,17 +5,19 @@
  */
 
 /** \file osl.c Object storage layer functions. */
+#include <dirent.h> /* readdir() */
+#include <assert.h>
+
+
 #include "para.h"
 #include "error.h"
+#include "fd.h"
 #include "list.h"
 #include "osl_core.h"
-#include <dirent.h> /* readdir() */
-#include <assert.h>
-
 /**
  * A wrapper for lseek(2).
  *
- * \param fd The filedescriptor whose offset is to be to repositioned.
+ * \param fd The file descriptor whose offset is to be to repositioned.
  * \param offset A value-result parameter.
  * \param whence Usual repositioning directive.
  *
@@ -44,8 +46,8 @@ int para_lseek(int fd, off_t *offset, int whence)
  * \param buf The buffer to write.
  * \param size The length of \a buf in bytes.
  *
- * This function writes out the given bufffer and retries if an interrupt
- * occured during the write.
+ * This function writes out the given buffer and retries if an interrupt
+ * occurred during the write.
  *
  * \return On success, the number of bytes written is returned, otherwise, the
  * function returns \p -E_WRITE.
@@ -93,46 +95,6 @@ ssize_t para_write_all(int fd, const void *buf, size_t size)
        }
        return 1;
 }
-/**
- * Wrapper for the open(2) system call.
- *
- * \param path The filename.
- * \param flags The usual open(2) flags.
- * \param mode Specifies the permissions to use.
- *
- * The mode parameter must be specified when O_CREAT is in the flags, and is ignored
- * otherwise.
- *
- * \return Positive on success, negative on errors. Possible errors: \p
- * E_EXIST, \p E_ISDIR, \p E_NOENT, \p E_OSL_PERM.
- *
- * \sa open(2).
- */
-int para_open(const char *path, int flags, mode_t mode)
-{
-       PARA_DEBUG_LOG("opening %s\n", path);
-       int ret = open(path, flags, mode);
-
-       if (ret >= 0)
-               return ret;
-       switch (errno) {
-       case EEXIST:
-               ret = -E_EXIST;
-               break;
-       case EISDIR:
-               ret = -E_ISDIR;
-               break;
-       case ENOENT:
-               ret = -E_NOENT;
-               break;
-       case EPERM:
-               ret = -E_OSL_PERM;
-               break;
-       };
-       PARA_ERROR_LOG("failed to open %s: %s\n", path, strerror(errno));
-       return ret;
-}
-
 /**
  * Open a file, write the given buffer and close the file.
  *
@@ -249,9 +211,10 @@ out:
  * \param func The function to call for each entry.
  * \param private_data Pointer to an arbitrary data structure.
  *
- * For each regular file  in \a dirname, the supplied function \a func is
+ * For each regular file under \a dirname, the supplied function \a func is
  * called.  The full path of the regular file and the \a private_data pointer
- * are passed to \a func.
+ * are passed to \a func. Directories for which the calling process has no
+ * permissions to change to are silently ignored.
  *
  * \return On success, 1 is returned. Otherwise, this function returns a
  * negative value which indicates the kind of the error.
@@ -259,37 +222,22 @@ out:
 int for_each_file_in_dir(const char *dirname,
                int (*func)(const char *, const void *), const void *private_data)
 {
-       DIR *dir = NULL;
+       DIR *dir;
        struct dirent *entry;
-       /*
-        * Opening the current directory (".") and calling fchdir() to return
-        * is usually faster and more reliable than saving cwd in some buffer
-        * and calling chdir() afterwards (see man 3 getcwd).
-        */
-       int cwd_fd = open(".", O_RDONLY);
-       struct stat s;
-       int ret = -1;
-
-//     PARA_DEBUG_LOG("dirname: %s\n", dirname);
-       if (cwd_fd < 0)
-               return -E_OSL_GETCWD;
-       ret = -E_OSL_CHDIR;
-       if (chdir(dirname) < 0)
-               goto out;
-       ret = -E_OSL_OPENDIR;
-       dir = opendir(".");
-       if (!dir)
-               goto out;
+       int cwd_fd, ret2, ret = para_opendir(dirname, &dir, &cwd_fd);
+
+       if (ret < 0)
+               return ret == -E_CHDIR_PERM? 1 : ret;
        /* scan cwd recursively */
        while ((entry = readdir(dir))) {
                mode_t m;
                char *tmp;
+               struct stat s;
 
                if (!strcmp(entry->d_name, "."))
                        continue;
                if (!strcmp(entry->d_name, ".."))
                        continue;
-               ret = -E_OSL_LSTAT;
                if (lstat(entry->d_name, &s) == -1)
                        continue;
                m = s.st_mode;
@@ -311,29 +259,14 @@ int for_each_file_in_dir(const char *dirname,
        }
        ret = 1;
 out:
-       if (dir)
-               closedir(dir);
-       if (fchdir(cwd_fd) < 0 && ret >= 0)
-               ret = -E_OSL_CHDIR;
+       closedir(dir);
+       ret2 = para_fchdir(cwd_fd);
+       if (ret2 < 0 && ret >= 0)
+               ret = ret2;
        close(cwd_fd);
        return ret;
 }
 
-int para_mkdir(const char *path, mode_t mode)
-{
-       if (!mkdir(path, mode))
-               return 1;
-       if (errno == EEXIST)
-               return -E_EXIST;
-       if (errno == ENOSPC)
-               return -E_NOSPC;
-       if (errno == ENOTDIR)
-               return -E_NOTDIR;
-       if (errno == EPERM)
-               return E_OSL_PERM;
-       return -E_MKDIR;
-}
-
 static int verify_name(const char *name)
 {
        if (!name)
@@ -652,7 +585,7 @@ static int compare_table_descriptions(struct osl_table *t)
        ret = -E_BAD_TABLE_FLAGS;
        if (desc.flags != t->desc->flags)
                goto out;
-       ret = E_BAD_COLUMN_NUM;
+       ret = -E_BAD_COLUMN_NUM;
        if (desc.num_columns != t->desc->num_columns)
                goto out;
        FOR_EACH_COLUMN(i, t->desc, cd1) {
@@ -820,8 +753,7 @@ static void unmap_column(struct osl_table *t, unsigned col_num)
  * \param t Pointer to a mapped table.
  * \param flags Options for unmapping.
  *
- * \return Positive on success, negative on errors. Possible errors include:
- * E_NOT_MAPPED, E_MUNMAP.
+ * \return Positive on success, negative on errors.
  *
  * \sa map_table(), enum osl_close_flags, para_munmap().
  */
@@ -1154,7 +1086,7 @@ void clear_rbtrees(struct osl_table *t)
  * \param flags Options for what should be cleaned up.
  *
  * If osl_open_table() succeeds, the resulting table pointer must later be
- * passed to this function in order to flush all changes to the filesystem and
+ * passed to this function in order to flush all changes to the file system and
  * to free the resources that were allocated by osl_open_table().
  *
  * \return Positive on success, negative on errors. Possible errors: \p E_BAD_TABLE,
@@ -1736,7 +1668,7 @@ static int check_rbtree_col(const struct osl_table *t, unsigned col_num,
  * Lookup \a obj in \a t and return the row containing \a obj. The column
  * specified by \a col_num must have an associated rbtree.
  *
- * \return Positive on success, negative on errors. If an error occured, \a
+ * \return Positive on success, negative on errors. If an error occurred, \a
  * result is set to \p NULL. Possible errors include: \p E_BAD_TABLE, \p
  * E_BAD_STORAGE_FLAGS, errors returned by get_mapped_object(), \p
  * E_RB_KEY_NOT_FOUND.
@@ -1766,9 +1698,12 @@ int osl_get_row(const struct osl_table *t, unsigned col_num,
 static int rbtree_loop(struct osl_column *col,  void *private_data,
                osl_rbtree_loop_func *func)
 {
-       struct rb_node *n;
+       struct rb_node *n, *tmp;
 
-       for (n = rb_first(&col->rbtree); n; n = rb_next(n)) {
+       /* this for-loop is safe against removal of an entry */
+       for (n = rb_first(&col->rbtree), tmp = n? rb_next(n) : NULL;
+                       n;
+                       n = tmp, tmp = tmp? rb_next(tmp) : NULL) {
                struct osl_row *r = get_row_pointer(n, col->rbtree_num);
                int ret = func(r, private_data);
                if (ret < 0)
@@ -1780,9 +1715,12 @@ static int rbtree_loop(struct osl_column *col,  void *private_data,
 static int rbtree_loop_reverse(struct osl_column *col,  void *private_data,
                osl_rbtree_loop_func *func)
 {
-       struct rb_node *n;
+       struct rb_node *n, *tmp;
 
-       for (n = rb_last(&col->rbtree); n; n = rb_prev(n)) {
+       /* safe against removal of an entry */
+       for (n = rb_last(&col->rbtree), tmp = n? rb_prev(n) : NULL;
+                       n;
+                       n = tmp, tmp = tmp? rb_prev(tmp) : NULL) {
                struct osl_row *r = get_row_pointer(n, col->rbtree_num);
                int ret = func(r, private_data);
                if (ret < 0)
@@ -1802,9 +1740,9 @@ static int rbtree_loop_reverse(struct osl_column *col,  void *private_data,
  * This function does an in-order walk of the rbtree associated with \a
  * col_num. It is an error if the \p OSL_RBTREE flag is not set for this
  * column. For each node in the rbtree, the given function \a func is called
- * with two \p void* pointers as arguments: The first argument points to the
+ * with two pointers as arguments: The first osl_row* argument points to the
  * row that contains the object corresponding to the rbtree node currently
- * traversed, and the \a private_data pointer is passed to \a func as the
+ * traversed, and the \a private_data pointer is passed verbatim to \a func as the
  * second argument. The loop terminates either if \a func returns a negative
  * value, or if all nodes of the tree have been visited.
  *
@@ -1898,7 +1836,7 @@ out:
  *
  * This function  gets rid of all references to the old object. This includes
  * removal of the rbtree node in case there is an rbtree associated with \a
- * col_num. It then inserts \a obj into the table and the rbtree if neccessary.
+ * col_num. It then inserts \a obj into the table and the rbtree if necessary.
  *
  * If the \p OSL_RBTREE flag is set for \a col_num, you \b MUST call this
  * function in order to change the contents of an object, even for volatile or