utils: Use fstatat and unlinkat if supported
This commit is contained in:
parent
41f0a5a36e
commit
0718e58681
|
@ -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
|
||||
|
|
57
utils/file.c
57
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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
@ -373,61 +388,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.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue