summaryrefslogtreecommitdiff
path: root/file_io
diff options
context:
space:
mode:
authorfitz <fitz@13f79535-47bb-0310-9956-ffa450edef68>2002-05-31 22:28:40 +0000
committerfitz <fitz@13f79535-47bb-0310-9956-ffa450edef68>2002-05-31 22:28:40 +0000
commit0c13352488752674358fef333bc8751090f73039 (patch)
tree64f5112203ec102ae360b7a3690332596f72b257 /file_io
parenteaddd65e35ace20184097e1988ecf4962e363793 (diff)
downloadlibapr-0c13352488752674358fef333bc8751090f73039.tar.gz
Needed a function in Subversion to behave like 'mkdir -p', and this
seems like the logical place for it. * file_io/unix/dir.c: apr_dir_make_recursive: New function. (The following 2 are support for the above function. Perhaps one day they'll live in a path utilities file of their own?) path_canonicalize: New static function. path_remove_last_component: New static function. * include/apr_file_io.h: apr_dir_make_recursive: New declaration. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@63457 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'file_io')
-rw-r--r--file_io/unix/dir.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/file_io/unix/dir.c b/file_io/unix/dir.c
index fe8003ed6..5f6779dab 100644
--- a/file_io/unix/dir.c
+++ b/file_io/unix/dir.c
@@ -73,6 +73,39 @@ static apr_status_t dir_cleanup(void *thedir)
}
}
+#define PATH_SEPARATOR '/'
+
+/* Remove trailing separators that don't affect the meaning of PATH. */
+static const char *path_canonicalize (const char *path, apr_pool_t *pool)
+{
+ /* At some point this could eliminate redundant components. For
+ * now, it just makes sure there is no trailing slash. */
+ apr_size_t len = strlen (path);
+ apr_size_t orig_len = len;
+
+ while ((len > 0) && (path[len - 1] == PATH_SEPARATOR))
+ len--;
+
+ if (len != orig_len)
+ return apr_pstrndup (pool, path, len);
+ else
+ return path;
+}
+
+/* Remove one component off the end of PATH. */
+static char *path_remove_last_component (const char *path, apr_pool_t *pool)
+{
+ const char *newpath = path_canonicalize (path, pool);
+ int i;
+
+ for (i = (strlen(newpath) - 1); i >= 0; i--) {
+ if (path[i] == PATH_SEPARATOR)
+ break;
+ }
+
+ return apr_pstrndup (pool, path, (i < 0) ? 0 : i);
+}
+
apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, apr_pool_t *pool)
{
/* On some platforms (e.g., Linux+GNU libc), d_name[] in struct
@@ -204,6 +237,29 @@ apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *po
}
}
+apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm,
+ apr_pool_t *pool)
+{
+ apr_status_t apr_err = 0;
+
+ apr_err = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
+
+ if (apr_err == EEXIST) /* It's OK if PATH exists */
+ return APR_SUCCESS;
+
+ if (apr_err == ENOENT) { /* Missing an intermediate dir */
+ char *dir;
+
+ dir = path_remove_last_component(path, pool);
+ apr_err = apr_dir_make_recursive(dir, perm, pool);
+
+ if (!apr_err)
+ apr_err = apr_dir_make (path, perm, pool);
+ }
+
+ return apr_err;
+}
+
apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
{
if (rmdir(path) == 0) {