diff options
author | Balint Reczey <balint@balintreczey.hu> | 2022-08-20 18:17:29 +0200 |
---|---|---|
committer | Balint Reczey <balint@balintreczey.hu> | 2022-08-20 18:17:29 +0200 |
commit | 69ca70f20204c63dca3ae4f85dd9a37188dcfc0b (patch) | |
tree | fd3a6ed4ed4551b63d0f9ed74690c8fbcaf2f7df /libmisc/remove_tree.c | |
parent | 8d8547f65fc0474fa335d04201ee9c2ccb9aa773 (diff) | |
parent | 675b462b64b213647d0f5c56b1e8440be5890c8a (diff) | |
download | shadow-69ca70f20204c63dca3ae4f85dd9a37188dcfc0b.tar.gz |
Update upstream source from tag 'upstream/4.12.2+dfsg1'
Update to upstream version '4.12.2+dfsg1'
with Debian dir 52044f35b7f4073e1929e253a646847ef319cac4
Diffstat (limited to 'libmisc/remove_tree.c')
-rw-r--r-- | libmisc/remove_tree.c | 87 |
1 files changed, 39 insertions, 48 deletions
diff --git a/libmisc/remove_tree.c b/libmisc/remove_tree.c index c3aa8131..3d76b95e 100644 --- a/libmisc/remove_tree.c +++ b/libmisc/remove_tree.c @@ -11,6 +11,7 @@ #ident "$Id$" +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -21,90 +22,80 @@ #include "prototypes.h" #include "defines.h" -/* - * remove_tree - delete a directory tree - * - * remove_tree() walks a directory tree and deletes all the files - * and directories. - * At the end, it deletes the root directory itself. - */ - -int remove_tree (const char *root, bool remove_root) +static int remove_tree_at (int at_fd, const char *path, bool remove_root) { - char *new_name = NULL; - int err = 0; - struct DIRECT *ent; - struct stat sb; DIR *dir; + const struct dirent *ent; + int dir_fd, rc = 0; - /* - * Open the source directory and read each entry. Every file - * entry in the directory is copied with the UID and GID set - * to the provided values. As an added security feature only - * regular files (and directories ...) are copied, and no file - * is made set-ID. - */ - dir = opendir (root); - if (NULL == dir) { + dir_fd = openat (at_fd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (dir_fd < 0) { + return -1; + } + + dir = fdopendir (dir_fd); + if (!dir) { + (void) close (dir_fd); return -1; } + /* + * Open the source directory and delete each entry. + */ while ((ent = readdir (dir))) { - size_t new_len = strlen (root) + strlen (ent->d_name) + 2; + struct stat ent_sb; /* * Skip the "." and ".." entries */ - if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) { continue; } - /* - * Make the filename for the current entry. - */ - - free (new_name); - new_name = (char *) malloc (new_len); - if (NULL == new_name) { - err = -1; + rc = fstatat (dirfd(dir), ent->d_name, &ent_sb, AT_SYMLINK_NOFOLLOW); + if (rc < 0) { break; } - (void) snprintf (new_name, new_len, "%s/%s", root, ent->d_name); - if (LSTAT (new_name, &sb) == -1) { - continue; - } - if (S_ISDIR (sb.st_mode)) { + if (S_ISDIR (ent_sb.st_mode)) { /* * Recursively delete this directory. */ - if (remove_tree (new_name, true) != 0) { - err = -1; + if (remove_tree_at (dirfd(dir), ent->d_name, true) != 0) { + rc = -1; break; } } else { /* * Delete the file. */ - if (unlink (new_name) != 0) { - err = -1; + if (unlinkat (dirfd(dir), ent->d_name, 0) != 0) { + rc = -1; break; } } } - if (NULL != new_name) { - free (new_name); - } + (void) closedir (dir); - if (remove_root && (0 == err)) { - if (rmdir (root) != 0) { - err = -1; + if (remove_root && (0 == rc)) { + if (unlinkat (at_fd, path, AT_REMOVEDIR) != 0) { + rc = -1; } } - return err; + return rc; } +/* + * remove_tree - delete a directory tree + * + * remove_tree() walks a directory tree and deletes all the files + * and directories. + * At the end, it deletes the root directory itself. + */ +int remove_tree (const char *root, bool remove_root) +{ + return remove_tree_at (AT_FDCWD, root, remove_root); +} |