* du.c: implementation of du.h.
*/
-#include "agedu.h" /* for config.h */
-
-#ifdef HAVE_FEATURES_H
-#define _GNU_SOURCE
-#include <features.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
+#include "agedu.h"
#include "du.h"
#include "alloc.h"
-#if !defined __linux__ || defined HAVE_FDOPENDIR
+#if !defined __linux__ || !defined O_NOATIME || defined HAVE_FDOPENDIR
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+#ifdef HAVE_NDIR_H
+# include <ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+#endif
+#ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+#endif
/*
* Wrappers around POSIX opendir, readdir and closedir, which
* circumstances.
*/
-#include <dirent.h>
typedef DIR *dirhandle;
int open_dir(const char *path, dirhandle *dh)
*/
#define __KERNEL__
-#include <unistd.h>
-#include <fcntl.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <linux/unistd.h>
}
static void du_recurse(char **path, size_t pathlen, size_t *pathsize,
- gotdata_fn_t gotdata, void *gotdata_ctx)
+ gotdata_fn_t gotdata, err_fn_t err, void *gotdata_ctx,
+ int toplevel)
{
const char *name;
dirhandle d;
STRUCT_STAT st;
char **names;
size_t i, nnames, namesize;
+ int statret;
- if (LSTAT(*path, &st) < 0) {
- fprintf(stderr, "%s: lstat: %s\n", *path, strerror(errno));
+ /*
+ * Special case: at the very top of the scan, we follow a
+ * symlink.
+ */
+ if (toplevel)
+ statret = STAT_FUNC(*path, &st);
+ else
+ statret = LSTAT_FUNC(*path, &st);
+ if (statret < 0) {
+ err(gotdata_ctx, "%s: lstat: %s\n", *path, strerror(errno));
return;
}
nnames = namesize = 0;
if (open_dir(*path, &d) < 0) {
- fprintf(stderr, "%s: opendir: %s\n", *path, strerror(errno));
+ err(gotdata_ctx, "%s: opendir: %s\n", *path, strerror(errno));
return;
}
while ((name = read_dir(&d)) != NULL) {
sprintf(*path + pathlen, "/%s", names[i]);
}
- du_recurse(path, newpathlen, pathsize, gotdata, gotdata_ctx);
+ du_recurse(path, newpathlen, pathsize, gotdata, err, gotdata_ctx, 0);
sfree(names[i]);
}
sfree(names);
}
-void du(const char *inpath, gotdata_fn_t gotdata, void *gotdata_ctx)
+void du(const char *inpath, gotdata_fn_t gotdata, err_fn_t err,
+ void *gotdata_ctx)
{
char *path;
size_t pathlen, pathsize;
pathlen = strlen(inpath);
+
+ /*
+ * Trim any trailing slashes from the input path, otherwise we'll
+ * store them in the index with confusing effects.
+ */
+ while (pathlen > 1 && inpath[pathlen-1] == '/')
+ pathlen--;
+
pathsize = pathlen + 256;
path = snewn(pathsize, char);
- strcpy(path, inpath);
+ memcpy(path, inpath, pathlen);
+ path[pathlen] = '\0';
- du_recurse(&path, pathlen, &pathsize, gotdata, gotdata_ctx);
+ du_recurse(&path, pathlen, &pathsize, gotdata, err, gotdata_ctx, 1);
}