static void dump_line(const char *pathname, const struct trie_file *tf)
{
const char *p;
- printf("%llu %llu ", tf->size, tf->atime);
+ if (printf("%llu %llu ", tf->size, tf->atime) < 0) goto error;
for (p = pathname; *p; p++) {
- if (*p >= ' ' && *p < 127 && *p != '%')
- putchar(*p);
- else
- printf("%%%02x", (unsigned char)*p);
+ if (*p >= ' ' && *p < 127 && *p != '%') {
+ if (putchar(*p) == EOF) goto error;
+ } else {
+ if (printf("%%%02x", (unsigned char)*p) < 0) goto error;
+ }
}
- putchar('\n');
+ if (putchar('\n') == EOF) goto error;
+ return;
+ error:
+ fatal("standard output: %s", strerror(errno));
}
static int gotdata(void *vctx, const char *pathname, const STRUCT_STAT *st)
if (ctx->usemtime || (ctx->fakeatimes && S_ISDIR(st->st_mode)))
file.atime = st->st_mtime;
else
- file.atime = st->st_atime;
+ file.atime = max(st->st_mtime, st->st_atime);
/*
* Filter based on wildcards.
}
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;
}
p++;
}
+ } else {
+ p++;
}
*q++ = c;
- p++;
}
*q = '\0';
triebuild_add(ctx->tb, buf, &tf);
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) {
char *querydir = actions[action].arg;
- size_t pathlen;
+ size_t pathlen, maxpathlen;
+ char *pathbuf;
struct html_config cfg;
unsigned long xi;
char *html;
}
pathsep = trie_pathsep(mappedfile);
+ maxpathlen = trie_maxpathlen(mappedfile);
+ pathbuf = snewn(maxpathlen, char);
+
/*
* Trim trailing slash, just in case.
*/
querydir[--pathlen] = '\0';
xi = trie_before(mappedfile, querydir);
- cfg.format = NULL;
- cfg.autoage = htmlautoagerange;
- cfg.oldest = htmloldest;
- cfg.newest = htmlnewest;
- html = html_query(mappedfile, xi, &cfg);
- fputs(html, stdout);
+ if (xi >= trie_count(mappedfile) ||
+ (trie_getpath(mappedfile, xi, pathbuf),
+ strcmp(pathbuf, querydir))) {
+ fprintf(stderr, "%s: pathname '%s' does not exist in index\n"
+ "%*s(check it is spelled exactly as it is in the "
+ "index, including\n%*sany leading './')\n",
+ PNAME, querydir,
+ (int)(1+sizeof(PNAME)), "",
+ (int)(1+sizeof(PNAME)), "");
+ } else if (!index_has_root(mappedfile, xi)) {
+ fprintf(stderr, "%s: pathname '%s' is"
+ " a file, not a directory\n", PNAME, querydir);
+ } else {
+ cfg.format = NULL;
+ cfg.autoage = htmlautoagerange;
+ cfg.oldest = htmloldest;
+ cfg.newest = htmlnewest;
+ cfg.showfiles = showfiles;
+ html = html_query(mappedfile, xi, &cfg);
+ fputs(html, stdout);
+ }
munmap(mappedfile, totalsize);
+ sfree(pathbuf);
} else if (mode == DUMP) {
size_t maxpathlen;
char *buf;
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) {