to go through by hand looking for data you don't need), but may be
better than nothing if your last-access times are unhelpful.
+The following option affects all the modes that generate reports:
+the web server mode \cw{-w}, the stand-alone HTML generation mode
+\cw{-H} and the text report mode \cw{-t}.
+
+\dt \cw{--files}
+
+\dd This option causes \cw{agedu}'s reports to list the individual
+files in each directory, instead of just giving a combined report
+for everything that's not in a subdirectory.
+
The following options affect the web server mode \cw{-w}, and in one
case also the stand-alone HTML generation mode \cw{-H}:
}
static void text_query(const void *mappedfile, const char *querydir,
- time_t t, int depth)
+ time_t t, int showfiles, int depth)
{
size_t maxpathlen;
char *pathbuf;
unsigned long xi1, xi2;
- unsigned long long s1, s2;
+ unsigned long long size;
maxpathlen = trie_maxpathlen(mappedfile);
pathbuf = snewn(maxpathlen + 1, char);
xi1 = trie_before(mappedfile, querydir);
xi2 = trie_before(mappedfile, pathbuf);
- if (xi2 - xi1 == 1)
+ if (!showfiles && xi2 - xi1 == 1)
return; /* file, or empty dir => no display */
/*
* Now do the lookups in the age index.
*/
- s1 = index_query(mappedfile, xi1, t);
- s2 = index_query(mappedfile, xi2, t);
+ if (xi2 - xi1 == 1) {
+ /*
+ * We are querying an individual file, so we should not
+ * depend on the index entries either side of the node,
+ * since they almost certainly don't both exist. Instead,
+ * just look up the file's size and atime in the main trie.
+ */
+ const struct trie_file *f = trie_getfile(mappedfile, xi1);
+ if (f->atime < t)
+ size = f->size;
+ else
+ size = 0;
+ } else {
+ unsigned long long s1, s2;
+ s1 = index_query(mappedfile, xi1, t);
+ s2 = index_query(mappedfile, xi2, t);
+ size = s2 - s1;
+ }
- if (s1 == s2)
+ if (size == 0)
return; /* no space taken up => no display */
if (depth > 0) {
xi1++;
while (xi1 < xi2) {
trie_getpath(mappedfile, xi1, pathbuf);
- text_query(mappedfile, pathbuf, t, depth-1);
+ text_query(mappedfile, pathbuf, t, showfiles, depth-1);
make_successor(pathbuf);
xi1 = trie_before(mappedfile, pathbuf);
}
}
/* Display in units of 1Kb */
- printf("%-11llu %s\n", (s2 - s1) / 1024, querydir);
+ printf("%-11llu %s\n", (size) / 1024, querydir);
}
/*
HELPOPT("[--scan,--load] fake atimes on directories") \
NOVAL(MTIME) LONG(mtime) \
HELPOPT("[--scan] use mtime instead of atime") \
+ NOVAL(SHOWFILES) LONG(files) \
+ HELPOPT("[--web,--html,--text] list individual files") \
VAL(AGERANGE) SHORT(r) LONG(age_range) LONG(range) LONG(ages) \
HELPARG("age[-age]") HELPOPT("[--web,--html] set limits of colour coding") \
VAL(SERVERADDR) LONG(address) LONG(addr) LONG(server_address) \
int tqdepth = 1;
int fakediratimes = 1;
int mtime = 0;
+ int showfiles = 0;
#ifdef DEBUG_MAD_OPTION_PARSING_MACROS
{
case OPT_NODIRATIME:
fakediratimes = 1;
break;
+ case OPT_SHOWFILES:
+ showfiles = 1;
+ break;
case OPT_MTIME:
mtime = 1;
break;
if (pathlen > 0 && querydir[pathlen-1] == pathsep)
querydir[--pathlen] = '\0';
- text_query(mappedfile, querydir, textcutoff, tqdepth);
+ text_query(mappedfile, querydir, textcutoff, showfiles, tqdepth);
munmap(mappedfile, totalsize);
} else if (mode == HTML) {
cfg.autoage = htmlautoagerange;
cfg.oldest = htmloldest;
cfg.newest = htmlnewest;
+ cfg.showfiles = showfiles;
html = html_query(mappedfile, xi, &cfg);
fputs(html, stdout);
}
pcfg.autoage = htmlautoagerange;
pcfg.oldest = htmloldest;
pcfg.newest = htmlnewest;
+ pcfg.showfiles = showfiles;
run_httpd(mappedfile, auth, &dcfg, &pcfg);
munmap(mappedfile, totalsize);
} else if (mode == REMOVE) {
unsigned long xi1, unsigned long xi2,
unsigned long long atime)
{
- return index_query(t, xi2, atime) - index_query(t, xi1, atime);
+ if (xi2 - xi1 == 1) {
+ /*
+ * We are querying an individual file, so we should not
+ * depend on the index entries either side of the node,
+ * since they almost certainly don't both exist. Instead,
+ * just look up the file's size and atime in the main trie.
+ */
+ const struct trie_file *f = trie_getfile(t, xi1);
+ if (f->atime < atime)
+ return f->size;
+ else
+ return 0;
+ } else {
+ return index_query(t, xi2, atime) - index_query(t, xi1, atime);
+ }
}
static void htescape(struct html *ctx, const char *s, int n, int italics)
}
struct vector {
- int want_href;
+ int want_href, essential;
char *name;
int literal; /* should the name be formatted in fixed-pitch? */
unsigned long index;
return -1;
else if (a->index > b->index)
return +1;
+ else if (a->essential < b->essential)
+ return +1;
+ else if (a->essential > b->essential)
+ return -1;
return 0;
}
static struct vector *make_vector(struct html *ctx, char *path,
- int want_href, char *name, int literal)
+ int want_href, int essential,
+ char *name, int literal)
{
unsigned long xi1, xi2;
struct vector *vec = snew(struct vector);
int i;
vec->want_href = want_href;
+ vec->essential = essential;
vec->name = name ? dupstr(name) : NULL;
vec->literal = literal;
* case we must fiddle about to prevent divisions by zero in
* the code below.
*/
- if (!vec->sizes[MAXCOLOUR] && vec->want_href)
+ if (!vec->sizes[MAXCOLOUR] && !vec->essential)
return;
divisor = ctx->totalsize;
if (!divisor) {
vecsize = 64;
vecs = snewn(vecsize, struct vector *);
nvecs = 1;
- vecs[0] = make_vector(ctx, path, 0, NULL, 0);
+ vecs[0] = make_vector(ctx, path, 0, 1, NULL, 0);
print_heading(ctx, "Overall");
write_report_line(ctx, vecs[0]);
trie_getpath(t, xi1, path2);
get_indices(t, ctx->path2, &xj1, &xj2);
xi1 = xj2;
- if (xj2 - xj1 <= 1)
+ if (!cfg->showfiles && xj2 - xj1 <= 1)
continue; /* skip individual files */
if (nvecs >= vecsize) {
vecsize = nvecs * 3 / 2 + 64;
vecs = sresize(vecs, vecsize, struct vector *);
}
assert(strlen(path2) > pathlen);
- vecs[nvecs] = make_vector(ctx, path2, 1, path2 + subdirpos, 1);
+ vecs[nvecs] = make_vector(ctx, path2, (xj2 - xj1 > 1), 0,
+ path2 + subdirpos, 1);
for (i = 0; i <= MAXCOLOUR; i++)
vecs[0]->sizes[i] -= vecs[nvecs]->sizes[i];
nvecs++;
*/
int autoage;
time_t oldest, newest;
+
+ /*
+ * Specify whether to show individual files as well as
+ * directories in the report.
+ */
+ int showfiles;
};
/*
assert(i < sw->len);
}
}
-}
+}
+
+const struct trie_file *trie_getfile(const void *t, unsigned long n)
+{
+ const struct trie_header *hdr = NODE(t, 0, trie_header);
+ off_t off = hdr->root;
+
+ while (1) {
+ const struct trie_common *node = NODE(t, off, trie_common);
+ if (node->type == TRIE_LEAF) {
+ const struct trie_leaf *leaf = NODE(t, off, trie_leaf);
+ return &leaf->file;
+ } else if (node->type == TRIE_STRING) {
+ const struct trie_string *st = NODE(t, off, trie_string);
+ off = st->subnode;
+ } else if (node->type == TRIE_SWITCH) {
+ const struct trie_switch *sw = NODE(t, off, trie_switch);
+ int i;
+
+ for (i = 0; i < sw->len; i++) {
+ if (n < sw->sw[i].subcount) {
+ off = sw->sw[i].subnode;
+ break;
+ } else
+ n -= sw->sw[i].subcount;
+ }
+ assert(i < sw->len);
+ }
+ }
+}
unsigned long trie_count(const void *t)
{
void trie_getpath(const void *t, unsigned long n, char *buf);
/*
+ * Return the trie_file * for the nth entry in the trie.
+ */
+const struct trie_file *trie_getfile(const void *t, unsigned long n);
+
+/*
* Return the total number of entries in the whole trie.
*/
unsigned long trie_count(const void *t);