fitz 2002/05/31 15:28:40
Modified: file_io/unix dir.c
include apr_file_io.h
Log:
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.
Revision Changes Path
1.61 +56 -0 apr/file_io/unix/dir.c
Index: dir.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/dir.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -r1.60 -r1.61
--- dir.c 20 Mar 2002 08:54:42 -0000 1.60
+++ dir.c 31 May 2002 22:28:40 -0000 1.61
@@ -73,6 +73,39 @@
}
}
+#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
@@ -202,6 +235,29 @@
else {
return errno;
}
+}
+
+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)
1.125 +10 -0 apr/include/apr_file_io.h
Index: apr_file_io.h
===================================================================
RCS file: /home/cvs/apr/include/apr_file_io.h,v
retrieving revision 1.124
retrieving revision 1.125
diff -u -r1.124 -r1.125
--- apr_file_io.h 25 May 2002 22:27:02 -0000 1.124
+++ apr_file_io.h 31 May 2002 22:28:40 -0000 1.125
@@ -613,6 +613,16 @@
APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t
perm,
apr_pool_t *cont);
+/** Creates a new directory on the file system, but behaves like
+ * 'mkdir -p'. Creates intermediate directories as required. No error
+ * will be reported if PATH already exists.
+ * @param path the path for the directory to be created. (use / on all
systems)
+ * @param perm Permissions for the new direcoty.
+ * @param cont the pool to use. */
+APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path,
+ apr_fileperms_t perm,
+ apr_pool_t *pool);
+
/**
* Remove directory from the file system.
* @param path the path for the directory to be removed. (use / on all
systems)