summaryrefslogtreecommitdiff
path: root/libkmod/libkmod-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'libkmod/libkmod-util.c')
-rw-r--r--libkmod/libkmod-util.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/libkmod/libkmod-util.c b/libkmod/libkmod-util.c
index e636ae1..43d8b02 100644
--- a/libkmod/libkmod-util.c
+++ b/libkmod/libkmod-util.c
@@ -2,6 +2,8 @@
* libkmod - interface to kernel module operations
*
* Copyright (C) 2011-2013 ProFUSION embedded systems
+ * Copyright (C) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -308,6 +310,65 @@ char *path_make_absolute_cwd(const char *p)
return r;
}
+static inline int is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) >= 0)
+ return S_ISDIR(st.st_mode);
+
+ return -errno;
+}
+
+int mkdir_p(const char *path, mode_t mode)
+{
+ char *start = strdupa(path);
+ int len = strlen(path);
+ char *end = start + len;
+
+ /*
+ * scan backwards, replacing '/' with '\0' while the component doesn't
+ * exist
+ */
+ for (;;) {
+ int r = is_dir(start);
+ if (r > 0) {
+ end += strlen(end);
+
+ if (end == start + len)
+ return 0;
+
+ /* end != start, since it would be caught on the first
+ * iteration */
+ *end = '/';
+ break;
+ } else if (r == 0)
+ return -ENOTDIR;
+
+ if (end == start)
+ break;
+
+ *end = '\0';
+
+ /* Find the next component, backwards, discarding extra '/'*/
+ while (end > start && *end != '/')
+ end--;
+
+ while (end > start && *(end - 1) == '/')
+ end--;
+ }
+
+ for (; end < start + len;) {
+ if (mkdir(start, mode) < 0 && errno != EEXIST)
+ return -errno;
+
+ end += strlen(end);
+ *end = '/';
+ }
+
+ return 0;
+}
+
const struct kmod_ext kmod_exts[] = {
{".ko", sizeof(".ko") - 1},
#ifdef ENABLE_ZLIB