Use the configure output to select an lstat, and to select a method
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 3 Nov 2008 22:16:30 +0000 (22:16 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 3 Nov 2008 22:16:30 +0000 (22:16 +0000)
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
agedu.c
agedu.h
config.h [new file with mode: 0644]
configure.ac
du.c

diff --git a/TODO b/TODO
index 2f5c2d3..0cd19f8 100644 (file)
--- 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 (file)
--- 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 (file)
--- a/agedu.h
+++ b/agedu.h
 #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 (file)
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
index 510a5d1..e1cc6c5 100644 (file)
@@ -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 (file)
--- a/du.c
+++ b/du.c
 #include <sys/stat.h>
 #include <unistd.h>
 
+#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 <unistd.h>
-#include <fcntl.h>
-#include <linux/types.h>
-#include <linux/dirent.h>
-#include <linux/unistd.h>
-
-_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 <dirent.h>
+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 <unistd.h>
+#include <fcntl.h>
+#include <linux/types.h>
+#include <linux/dirent.h>
+#include <linux/unistd.h>
+
+_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 <dirent.h>
-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;
     }