diff options
Diffstat (limited to 'libkmod/libkmod-util.c')
-rw-r--r-- | libkmod/libkmod-util.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/libkmod/libkmod-util.c b/libkmod/libkmod-util.c index 71bf51d..d686250 100644 --- a/libkmod/libkmod-util.c +++ b/libkmod/libkmod-util.c @@ -1,7 +1,9 @@ /* * libkmod - interface to kernel module operations * - * Copyright (C) 2011-2012 ProFUSION embedded systems + * 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 @@ -29,7 +31,7 @@ #include <ctype.h> #include "libkmod.h" -#include "libkmod-private.h" +#include "libkmod-internal.h" /* * Read one logical line from a configuration file. @@ -308,6 +310,77 @@ 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, int len, mode_t mode) +{ + char *start, *end; + + start = strndupa(path, len); + 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; +} + +int mkdir_parents(const char *path, mode_t mode) +{ + char *end = strrchr(path, '/'); + + /* no parent directories */ + if (end == NULL) + return 0; + + return mkdir_p(path, end - path, mode); +} + const struct kmod_ext kmod_exts[] = { {".ko", sizeof(".ko") - 1}, #ifdef ENABLE_ZLIB |