From 9c6e61f23dd65086378606be16d3740d909477d4 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 3 Nov 2008 22:16:30 +0000 Subject: [PATCH] Use the configure output to select an lstat, and to select a method of scanning directories. Everything else can wait until somebody complains - not least because when they do I'll know what sort of system I need to test the required changes on... git-svn-id: svn://svn.tartarus.org/sgt/agedu@8268 cda61777-01e9-0310-a592-d414129be87e --- TODO | 14 +++--- agedu.c | 2 +- agedu.h | 8 +++ config.h | 15 ++++++ configure.ac | 2 +- du.c | 155 +++++++++++++++++++++++++++++++++++------------------------ 6 files changed, 123 insertions(+), 73 deletions(-) create mode 100644 config.h diff --git a/TODO b/TODO index 2f5c2d3..0cd19f8 100644 --- a/TODO +++ b/TODO @@ -1,16 +1,14 @@ TODO list for agedu =================== -Before it's non-embarrassingly releasable: - - - now we have a configure framework, actually use it to: - * configure use of stat64 - * configure use of Linux syscall magic replacing readdir - + later glibcs have fdopendir, hooray! So we can use that - too, if it's available and O_NOATIME is too. - Future possibilities: + - integrate more usefully with the output of configure. It's + generating oodles of automatic boilerplate in config.h and I'm + sure three quarters of it _ought_ to be usable to add + portability, if only I had the gumption to actually pay attention + to all those HAVE_FOO macros it's defined for me. + - IPv6 support in the HTTP server * of course, Linux magic auth can still work in this context; we merely have to be prepared to open one of /proc/net/tcp or diff --git a/agedu.c b/agedu.c index 4914057..c3ac6a7 100644 --- a/agedu.c +++ b/agedu.c @@ -82,7 +82,7 @@ static void dump_line(const char *pathname, const struct trie_file *tf) putchar('\n'); } -static int gotdata(void *vctx, const char *pathname, const struct stat64 *st) +static int gotdata(void *vctx, const char *pathname, const STRUCT_STAT *st) { struct ctx *ctx = (struct ctx *)vctx; struct trie_file file; diff --git a/agedu.h b/agedu.h index 4f6d874..ca53f1e 100644 --- a/agedu.h +++ b/agedu.h @@ -11,3 +11,11 @@ #define lenof(x) (sizeof((x))/sizeof(*(x))) extern char pathsep; + +#ifdef HAVE_LSTAT64 +#define STRUCT_STAT struct stat64 +#define LSTAT lstat64 +#else +#define STRUCT_STAT struct stat +#define LSTAT lstat +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..95d89c0 --- /dev/null +++ b/config.h @@ -0,0 +1,15 @@ +/* + * config.h: stub version of the autoconf-generated config.h, to + * stop the #include in agedu.h from failing when run from the + * master source directory instead of from the unpacked contents + * of the autotoolsified tarball. + * + * This version of config.h hardwires some parameters that match + * the sorts of systems I tend to be building on. A nasty hack and + * a self-centred one, but autotools is so icky that I can't quite + * bring myself to inflict it on my main development directory, + * and am instead keeping it at arm's length in the distribution + * tarballs. Sorry about that. + */ + +#define HAVE_LSTAT64 diff --git a/configure.ac b/configure.ac index 510a5d1..e1cc6c5 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ AC_FUNC_MMAP AC_FUNC_SELECT_ARGTYPES AC_FUNC_STRFTIME AC_FUNC_VPRINTF -AC_CHECK_FUNCS([ftruncate inet_ntoa memchr munmap select socket strcasecmp strchr strcspn strerror strrchr strspn strtoul strtoull]) +AC_CHECK_FUNCS([ftruncate fdopendir inet_ntoa lstat64 memchr munmap select socket strcasecmp strchr strcspn strerror strrchr strspn strtoul strtoull]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/du.c b/du.c index 30a880d..9a8a4a3 100644 --- a/du.c +++ b/du.c @@ -14,46 +14,41 @@ #include #include +#include "agedu.h" #include "du.h" #include "alloc.h" -#ifdef __linux__ +#if !defined __linux__ || defined HAVE_FDOPENDIR /* - * On Linux, we have the O_NOATIME flag. This means we can read - * the contents of directories without affecting their atimes, - * which enables us to at least try to include them in the age - * display rather than exempting them. - * - * Unfortunately, opendir() doesn't let us open a directory with - * O_NOATIME. In later glibcs we can open one manually using - * open() and then use fdopendir() to translate the fd into a - * POSIX dir handle; in earlier glibcs fdopendir() is not - * available, so we have no option but to talk directly to the - * kernel system call interface which underlies the POSIX - * opendir/readdir machinery. + * Wrappers around POSIX opendir, readdir and closedir, which + * permit me to replace them with different wrappers in special + * circumstances. */ -#define __KERNEL__ -#include -#include -#include -#include -#include - -_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count) - -typedef struct { - int fd; - struct dirent data[32]; - struct dirent *curr; - int pos, endpos; -} dirhandle; +#include +typedef DIR *dirhandle; int open_dir(const char *path, dirhandle *dh) { - dh->fd = open(path, O_RDONLY | O_NOATIME | O_DIRECTORY); - if (dh->fd < 0) { +#if defined O_NOATIME && defined HAVE_FDOPENDIR + + /* + * On Linux, we have the O_NOATIME flag. This means we can + * read the contents of directories without affecting their + * atimes, which enables us to at least try to include them in + * the age display rather than exempting them. + * + * Unfortunately, opendir() doesn't let us open a directory + * with O_NOATIME. So instead, we have to open the directory + * with vanilla open(), and then use fdopendir() to translate + * the fd into a POSIX dir handle. + */ + int fd; + + fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_LARGEFILE | + O_NOATIME | O_DIRECTORY); + if (fd < 0) { /* * Opening a file with O_NOATIME is not unconditionally * permitted by the Linux kernel. As far as I can tell, @@ -71,7 +66,70 @@ int open_dir(const char *path, dirhandle *dh) * we receive EPERM. */ if (errno == EPERM) - dh->fd = open(path, O_RDONLY | O_DIRECTORY); + fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY | + O_LARGEFILE | O_DIRECTORY); + if (fd < 0) + return -1; + } + + *dh = fdopendir(fd); +#else + *dh = opendir(path); +#endif + + if (!*dh) + return -1; + return 0; +} + +const char *read_dir(dirhandle *dh) +{ + struct dirent *de = readdir(*dh); + return de ? de->d_name : NULL; +} + +void close_dir(dirhandle *dh) +{ + closedir(*dh); +} + +#else /* defined __linux__ && !defined HAVE_FDOPENDIR */ + +/* + * Earlier versions of glibc do not have fdopendir(). Therefore, + * if we are on Linux and still wish to make use of O_NOATIME, we + * have no option but to talk directly to the kernel system call + * interface which underlies the POSIX opendir/readdir machinery. + */ + +#define __KERNEL__ +#include +#include +#include +#include +#include + +_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count) + +typedef struct { + int fd; + struct dirent data[32]; + struct dirent *curr; + int pos, endpos; +} dirhandle; + +int open_dir(const char *path, dirhandle *dh) +{ + /* + * As above, we try with O_NOATIME and then fall back to + * trying without it. + */ + dh->fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_LARGEFILE | + O_NOATIME | O_DIRECTORY); + if (dh->fd < 0) { + if (errno == EPERM) + dh->fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY | + O_LARGEFILE | O_DIRECTORY); if (dh->fd < 0) return -1; } @@ -106,36 +164,7 @@ void close_dir(dirhandle *dh) close(dh->fd); } -#else /* __linux__ */ - -/* - * This branch of the ifdef is a simple exercise of ordinary POSIX - * opendir/readdir. - */ - -#include -typedef DIR *dirhandle; - -int open_dir(const char *path, dirhandle *dh) -{ - *dh = opendir(path); - if (!*dh) - return -1; - return 0; -} - -const char *read_dir(dirhandle *dh) -{ - struct dirent *de = readdir(*dh); - return de ? de->d_name : NULL; -} - -void close_dir(dirhandle *dh) -{ - closedir(*dh); -} - -#endif +#endif /* !defined __linux__ || defined HAVE_FDOPENDIR */ static int str_cmp(const void *av, const void *bv) { @@ -147,11 +176,11 @@ static void du_recurse(char **path, size_t pathlen, size_t *pathsize, { const char *name; dirhandle d; - struct stat64 st; + STRUCT_STAT st; char **names; size_t i, nnames, namesize; - if (lstat64(*path, &st) < 0) { + if (LSTAT(*path, &st) < 0) { fprintf(stderr, "%s: lstat: %s\n", *path, strerror(errno)); return; } -- 2.11.0