[libglnx] shutil: Add mkdir -p API
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libglnx] shutil: Add mkdir -p API
- Date: Tue, 7 Apr 2015 19:10:53 +0000 (UTC)
commit 19885b8a20053082543ceb238197315de1cc0bf6
Author: Colin Walters <walters verbum org>
Date: Tue Apr 7 12:29:07 2015 -0400
shutil: Add mkdir -p API
I looked at the systemd code but it didn't have a variant of
mkdir_parents that used `*at()`. This is a fresh implementation, with
the risk that entails.
However I am changing libgsystem to call it now for testing, and
libgsystem APIs are covered by ostree usage at least.
glnx-shutil.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
glnx-shutil.h | 7 ++++
2 files changed, 105 insertions(+), 0 deletions(-)
---
diff --git a/glnx-shutil.c b/glnx-shutil.c
index 967e364..e4df9ae 100644
--- a/glnx-shutil.c
+++ b/glnx-shutil.c
@@ -188,3 +188,101 @@ glnx_shutil_rm_rf_at (int dfd,
out:
return ret;
}
+
+static gboolean
+mkdir_p_at_internal (int dfd,
+ char *path,
+ int mode,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gboolean did_recurse = FALSE;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
+ again:
+ if (mkdirat (dfd, path, mode) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ char *lastslash;
+
+ g_assert (!did_recurse);
+
+ lastslash = strrchr (path, '/');
+ g_assert (lastslash != NULL);
+ /* Note we can mutate the buffer as we dup'd it */
+ *lastslash = '\0';
+
+ if (!glnx_shutil_mkdir_p_at (dfd, path, mode,
+ cancellable, error))
+ goto out;
+
+ /* Now restore it for another mkdir attempt */
+ *lastslash = '/';
+
+ did_recurse = TRUE;
+ goto again;
+ }
+ else if (errno == EEXIST)
+ {
+ /* Fall through; it may not have been a directory,
+ * but we'll find that out on the next call up.
+ */
+ }
+ else
+ {
+ glnx_set_error_from_errno (error);
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+/**
+ * glnx_shutil_mkdir_p_at:
+ * @dfd: Directory fd
+ * @path: Directory path to be created
+ * @mode: Mode for newly created directories
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Similar to g_mkdir_with_parents(), except operates relative to the
+ * directory fd @dfd.
+ */
+gboolean
+glnx_shutil_mkdir_p_at (int dfd,
+ const char *path,
+ int mode,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ struct stat stbuf;
+
+ /* Fast path stat to see whether it already exists */
+ if (fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == 0)
+ {
+ if (S_ISDIR (stbuf.st_mode))
+ {
+ ret = TRUE;
+ goto out;
+ }
+ }
+
+ {
+ char *buf = strdupa (path);
+
+ if (!mkdir_p_at_internal (dfd, buf, mode, cancellable, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
diff --git a/glnx-shutil.h b/glnx-shutil.h
index 0c53fd8..8cc732c 100644
--- a/glnx-shutil.h
+++ b/glnx-shutil.h
@@ -30,4 +30,11 @@ glnx_shutil_rm_rf_at (int dfd,
GCancellable *cancellable,
GError **error);
+gboolean
+glnx_shutil_mkdir_p_at (int dfd,
+ const char *path,
+ int mode,
+ GCancellable *cancellable,
+ GError **error);
+
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]