diff options
author | John-Mark Bell <jmb@netsurf-browser.org> | 2022-11-02 14:00:14 +0000 |
---|---|---|
committer | John-Mark Bell <jmb@netsurf-browser.org> | 2022-11-02 17:28:18 +0000 |
commit | 0718e5868119c9f61a6c6f1fe11de21ff6ba9b9a (patch) | |
tree | 9bc988f72c100ad1712a3fa5cb8ca0bacfd6d37e | |
parent | 41f0a5a36ecc6381880bd19b4f6838ac22f7d833 (diff) | |
download | netsurf-0718e5868119c9f61a6c6f1fe11de21ff6ba9b9a.tar.gz netsurf-0718e5868119c9f61a6c6f1fe11de21ff6ba9b9a.tar.bz2 |
utils: Use fstatat and unlinkat if supported
-rw-r--r-- | utils/config.h | 9 | ||||
-rw-r--r-- | utils/file.c | 57 | ||||
-rw-r--r-- | utils/filename.c | 88 |
3 files changed, 65 insertions, 89 deletions
diff --git a/utils/config.h b/utils/config.h index 0227f4177..f54326dba 100644 --- a/utils/config.h +++ b/utils/config.h @@ -146,6 +146,15 @@ char *realpath(const char *path, char *resolved_path); #undef HAVE_SCANDIR #endif +#define HAVE_DIRFD +#define HAVE_UNLINKAT +#define HAVE_FSTATAT +#if (defined(_WIN32) || defined(__riscos__) || defined(__HAIKU__) || defined(__BEOS__) || defined(__amigaos4__) || defined(__AMIGA__) || defined(__MINT__)) +#undef HAVE_DIRFD +#undef HAVE_UNLINKAT +#undef HAVE_FSTATAT +#endif + #define HAVE_REGEX #if (defined(__serenity__)) #undef HAVE_REGEX diff --git a/utils/file.c b/utils/file.c index c460e49e9..75a8a1c03 100644 --- a/utils/file.c +++ b/utils/file.c @@ -26,6 +26,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <fcntl.h> #include <errno.h> #include "desktop/gui_internal.h" @@ -318,16 +319,13 @@ nserror netsurf_mkdir_all(const char *fname) nserror netsurf_recursive_rm(const char *path) { - struct dirent **listing = NULL; /* directory entry listing */ - int nentries, ent; + DIR *parent; + struct dirent *entry; nserror ret = NSERROR_OK; struct stat ent_stat; /* stat result of leaf entry */ - char *leafpath = NULL; - const char *leafname; - - nentries = scandir(path, &listing, 0, alphasort); - if (nentries < 0) { + parent = opendir(path); + if (parent == NULL) { switch (errno) { case ENOENT: return NSERROR_NOT_FOUND; @@ -336,26 +334,44 @@ netsurf_recursive_rm(const char *path) } } - for (ent = 0; ent < nentries; ent++) { - leafname = listing[ent]->d_name; - if (strcmp(leafname, ".") == 0 || - strcmp(leafname, "..") == 0) + while ((entry = readdir(parent))) { + char *leafpath = NULL; + + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) continue; - ret = netsurf_mkpath(&leafpath, NULL, 2, path, leafname); - if (ret != NSERROR_OK) goto out; + + ret = netsurf_mkpath(&leafpath, NULL, 2, path, entry->d_name); + if (ret != NSERROR_OK) + goto out; + +#if (defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)) + if (fstatat(dirfd(parent), entry->d_name, &ent_stat, + AT_SYMLINK_NOFOLLOW) != 0) { +#else if (stat(leafpath, &ent_stat) != 0) { +#endif + free(leafpath); goto out_via_errno; } if (S_ISDIR(ent_stat.st_mode)) { ret = netsurf_recursive_rm(leafpath); - if (ret != NSERROR_OK) goto out; + if (ret != NSERROR_OK) { + free(leafpath); + goto out; + } } else { +#if (defined(HAVE_DIRFD) && defined(HAVE_UNLINKAT)) + if (unlinkat(dirfd(parent), entry->d_name, 0) != 0) { +#else if (unlink(leafpath) != 0) { +#endif + free(leafpath); goto out_via_errno; } } + free(leafpath); - leafpath = NULL; } if (rmdir(path) != 0) { @@ -373,16 +389,7 @@ out_via_errno: ret = NSERROR_UNKNOWN; } out: - if (listing != NULL) { - for (ent = 0; ent < nentries; ent++) { - free(listing[ent]); - } - free(listing); - } - - if (leafpath != NULL) { - free(leafpath); - } + closedir(parent); return ret; } diff --git a/utils/filename.c b/utils/filename.c index 00ade7409..346fa85cc 100644 --- a/utils/filename.c +++ b/utils/filename.c @@ -29,10 +29,13 @@ #include <stdio.h> #include <stdlib.h> #include <errno.h> +#include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include "utils/dirent.h" +#include "utils/errors.h" +#include "utils/file.h" #include "utils/filename.h" #include "utils/log.h" #include "utils/utils.h" @@ -55,7 +58,6 @@ static char filename_directory[256]; static struct directory *filename_create_directory(const char *prefix); static bool filename_flush_directory(const char *folder, int depth); -static bool filename_delete_recursive(char *folder); /** * Request a new, unique, filename. @@ -272,6 +274,8 @@ bool filename_flush_directory(const char *folder, int depth) } parent = opendir(folder); + if (parent == NULL) + return false; while ((entry = readdir(parent))) { int written; @@ -288,7 +292,12 @@ bool filename_flush_directory(const char *folder, int depth) child[sizeof(child) - 1] = '\0'; } +#if (defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)) + if (fstatat(dirfd(parent), entry->d_name, &statbuf, + AT_SYMLINK_NOFOLLOW) == -1) { +#else if (stat(child, &statbuf) == -1) { +#endif NSLOG(netsurf, INFO, "Unable to stat %s: %s", child, strerror(errno)); continue; @@ -354,14 +363,20 @@ bool filename_flush_directory(const char *folder, int depth) /* delete or recurse */ if (del) { - if (S_ISDIR(statbuf.st_mode)) - filename_delete_recursive(child); - - if (remove(child)) - NSLOG(netsurf, INFO, "Failed to remove '%s'", - child); - else - changed = true; + if (S_ISDIR(statbuf.st_mode)) { + changed = (netsurf_recursive_rm(child) == + NSERROR_OK); + } else { +#if (defined(HAVE_DIRFD) && defined(HAVE_UNLINKAT)) + if (unlinkat(dirfd(parent), entry->d_name, 0)) { +#else + if (unlink(child)) { +#endif + NSLOG(netsurf, INFO, + "Failed to remove '%s'", child); + } else + changed = true; + } } else { while (filename_flush_directory(child, depth + 1)); } @@ -374,61 +389,6 @@ bool filename_flush_directory(const char *folder, int depth) /** - * Recursively deletes the contents of a directory - * - * \param folder the directory to delete - * \return true on success, false otherwise - */ -bool filename_delete_recursive(char *folder) -{ - DIR *parent; - struct dirent *entry; - char child[256]; - struct stat statbuf; - - parent = opendir(folder); - - while ((entry = readdir(parent))) { - int written; - - /* Ignore '.' and '..' */ - if (strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0) - continue; - - written = snprintf(child, sizeof(child), "%s/%s", - folder, entry->d_name); - if (written == sizeof(child)) { - child[sizeof(child) - 1] = '\0'; - } - - if (stat(child, &statbuf) == -1) { - NSLOG(netsurf, INFO, "Unable to stat %s: %s", child, - strerror(errno)); - continue; - } - - if (S_ISDIR(statbuf.st_mode)) { - if (!filename_delete_recursive(child)) { - closedir(parent); - return false; - } - } - - if (remove(child)) { - NSLOG(netsurf, INFO, "Failed to remove '%s'", child); - closedir(parent); - return false; - } - } - - closedir(parent); - - return true; -} - - -/** * Creates a new directory. * * \param prefix the prefix to use, or NULL to allocate a new one |