summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/utils-dir.c162
-rw-r--r--src/utils-dir.h25
2 files changed, 187 insertions, 0 deletions
diff --git a/src/utils-dir.c b/src/utils-dir.c
new file mode 100644
index 0000000..af0bcf0
--- /dev/null
+++ b/src/utils-dir.c
@@ -0,0 +1,162 @@
+/*
+ Copyright 2015 IoT.bzh
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "utils-dir.h"
+
+static int clean_dirfd(int dirfd)
+{
+ int rc;
+ DIR *dir;
+ struct dirent *ent;
+ struct {
+ struct dirent entry;
+ char spare[PATH_MAX];
+ } entry;
+
+ dir = fdopendir(dirfd);
+ if (dir == NULL) {
+ close(dirfd);
+ return -1;
+ }
+ for (;;) {
+ rc = -1;
+ if (readdir_r(dir, &entry.entry, &ent) != 0)
+ goto error;
+ if (ent == NULL)
+ break;
+ if (ent->d_name[0] == '.' && (ent->d_name[1] == 0
+ || (ent->d_name[1] == '.' && ent->d_name[2] == 0)))
+ continue;
+ rc = unlinkat(dirfd, ent->d_name, 0);
+ if (!rc)
+ continue;
+ if (errno != EISDIR)
+ goto error;
+ rc = openat(dirfd, ent->d_name, O_DIRECTORY|O_RDONLY);
+ if (rc < 0)
+ goto error;
+ rc = clean_dirfd(rc);
+ if (rc)
+ goto error;
+ rc = unlinkat(dirfd, ent->d_name, AT_REMOVEDIR);
+ if (rc)
+ goto error;
+ }
+ rc = 0;
+error:
+ closedir(dir);
+ return rc;
+}
+
+/* removes recursively the content of a directory */
+int remove_directory_content_fd(int dirfd)
+{
+ dirfd = dup(dirfd);
+ return dirfd < 0 ? dirfd : clean_dirfd(dirfd);
+}
+
+/* removes recursively the content of a directory */
+int remove_directory_content_at(int dirfd, const char *directory)
+{
+ int fd, rc;
+
+ fd = openat(dirfd, directory, O_DIRECTORY|O_RDONLY);
+ if (fd < 0)
+ return fd;
+ rc = remove_directory_content_fd(fd);
+ return rc;
+}
+
+
+int remove_directory_content(const char *directory)
+{
+ return remove_directory_content_at(AT_FDCWD, directory);
+}
+
+/* removes the working directory */
+int remove_directory(const char *directory, int force)
+{
+ int rc;
+ rc = force ? remove_directory_content(directory) : 0;
+ return rc ? rc : rmdir(directory);
+}
+
+int remove_directory_at(int dirfd, const char *directory, int force)
+{
+ int rc;
+ rc = force ? remove_directory_content_at(dirfd, directory) : 0;
+ return rc ? rc : unlinkat(dirfd, directory, AT_REMOVEDIR);
+}
+
+/* create a directory */
+int create_directory_at(int dirfd, const char *directory, int mode, int mkparents)
+{
+ int rc, len, l;
+ char *copy;
+ const char *iter;
+
+ rc = mkdirat(dirfd, directory, mode);
+ if (!rc || errno != ENOENT)
+ return rc;
+
+ /* check parent of dest */
+ iter = strrchr(directory, '/');
+ len = iter ? iter - directory : 0;
+ if (!len)
+ return rc;
+ copy = strndupa(directory, len);
+
+ /* backward loop */
+ l = len;
+ rc = mkdirat(dirfd, copy, mode);
+ while(rc) {
+ if (errno != ENOENT)
+ return rc;
+ while (l && copy[l] != '/')
+ l--;
+ if (l == 0)
+ return rc;
+ copy[l] = 0;
+ rc = mkdirat(dirfd, copy, mode);
+ }
+ /* forward loop */
+ while(l < len) {
+ copy[l] = '/';
+ while (copy[++l]);
+ rc = mkdirat(dirfd, copy, mode);
+ if (rc)
+ return rc;
+ }
+
+ /* finalize */
+ return mkdirat(dirfd, directory, mode);
+}
+
+int create_directory(const char *directory, int mode, int mkparents)
+{
+ return create_directory_at(AT_FDCWD, directory, mode, mkparents);
+}
+
diff --git a/src/utils-dir.h b/src/utils-dir.h
new file mode 100644
index 0000000..c296d02
--- /dev/null
+++ b/src/utils-dir.h
@@ -0,0 +1,25 @@
+/*
+ Copyright 2015 IoT.bzh
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+int remove_directory_content_fd(int dirfd);
+int remove_directory_content(const char *directory);
+int remove_directory_content_at(int dirfd, const char *directory);
+int remove_directory(const char *directory, int force);
+int remove_directory_at(int dirfd, const char *directory, int force);
+
+int create_directory_at(int dirfd, const char *directory, int mode, int mkparents);
+int create_directory(const char *directory, int mode, int mkparents);
+