I updated my patch a bit.
There was a problem with storing only mtime's seconds as mandb's last changed time. There's a chance that if mandb -p gets called twice within a second that it won't know to crawl a directory on the second run. That didn't matter as much before, since the changed files would be indexed on the next run, whenever that happened. But with the ctime patch, there's a risk that it could never catch some files if this happened. I made mandb store nanoseconds to avoid this.
Index: man-db-2.6.3/src/check_mandirs.c =================================================================== --- man-db-2.6.3.orig/src/check_mandirs.c 2012-10-27 12:00:13.000000000 +0300 +++ man-db-2.6.3/src/check_mandirs.c 2012-10-31 20:24:59.285914354 +0200 @@ -316,12 +316,15 @@ free (lg.whatis); } -static inline void add_dir_entries (const char *path, char *infile) +static inline void add_dir_entries (const char *path, char *infile, + time_t last, time_t ulast) { char *manpage; int len; struct dirent *newdir; DIR *dir; + struct stat statbuf; + int fd, ret; manpage = appendstr (NULL, path, "/", infile, "/", NULL); len = strlen (manpage); @@ -332,7 +335,17 @@ */ dir = opendir (infile); - if (!dir) { + if (dir) { +#if _BSD_SOURCE + if ( (fd = dirfd (dir)) != -1) + ret = fchdir (fd); + else + ret = chdir (infile); +#else + ret = chdir (infile); +#endif + } + if (!dir || ret == -1) { error (0, errno, _("can't search directory %s"), manpage); free (manpage); return; @@ -343,12 +356,25 @@ while ( (newdir = readdir (dir)) ) if (!(*newdir->d_name == '.' && strlen (newdir->d_name) < (size_t) 3)) { +#if _BSD_SOURCE + if (last) + lstat(newdir->d_name, &statbuf); + if (!last || last < statbuf.st_ctime || + (last == statbuf.st_ctime + && ulast < statbuf.st_ctim.tv_nsec)) { + manpage = appendstr (manpage, newdir->d_name, NULL); + test_manfile (manpage, path); + *(manpage + len) = '\0'; + } +#else manpage = appendstr (manpage, newdir->d_name, NULL); test_manfile (manpage, path); *(manpage + len) = '\0'; +#endif } free (manpage); + chdir (".."); closedir (dir); } @@ -425,13 +451,14 @@ * scanned for new files, which are then added to the db. */ static int testmandirs (const char *path, const char *catpath, time_t last, - int create) + time_t ulast, int create) { DIR *dir; struct dirent *mandir; struct stat stbuf; int amount = 0; int created = 0; + int fd; debug ("Testing %s for new files\n", path); @@ -441,7 +468,14 @@ return 0; } +#ifdef _BSD_SOURCE + if ( (fd = dirfd (dir)) != -1) + fchdir (fd); + else + chdir (path); +#else chdir (path); +#endif while( (mandir = readdir (dir)) ) { if (strncmp (mandir->d_name, "man", 3) != 0) @@ -453,13 +487,26 @@ continue; if (!S_ISDIR(stbuf.st_mode)) /* not a directory */ continue; - if (last && stbuf.st_mtime <= last) { +#ifdef _BSD_SOURCE + if (last && (stbuf.st_mtime < last + || (stbuf.st_mtime == last + && stbuf.st_mtim.tv_nsec < ulast))) { + /* scanned already */ + debug ("%s modified %ld.%09d, db modified %ld.%09d\n", + mandir->d_name, (long) stbuf.st_mtime, + (int) stbuf.st_mtim.tv_nsec, + (long) last, (int) ulast); + continue; + } +#else + if (last && stbuf.st_mtime < last) { /* scanned already */ debug ("%s modified %ld, db modified %ld\n", mandir->d_name, (long) stbuf.st_mtime, (long) last); continue; } +#endif debug ("\tsubdirectory %s has been 'modified'\n", mandir->d_name); @@ -508,7 +555,7 @@ if (!tty) fprintf (stderr, "\n"); } - add_dir_entries (path, mandir->d_name); + add_dir_entries (path, mandir->d_name, last, ulast); MYDBM_CLOSE (dbf); amount++; } @@ -520,11 +567,14 @@ /* update the time key stored within `database' */ void update_db_time (void) { + struct timeval tv; datum key, content; #ifdef FAST_BTREE datum key1, content1; #endif /* FAST_BTREE */ + gettimeofday (&tv, NULL); + memset (&key, 0, sizeof key); memset (&content, 0, sizeof content); #ifdef FAST_BTREE @@ -533,7 +583,8 @@ #endif MYDBM_SET (key, xstrdup (KEY)); - MYDBM_SET (content, xasprintf ("%ld", (long) time (NULL))); + MYDBM_SET (content, xasprintf ("%ld.%09d", (long) tv.tv_sec, + (int) tv.tv_usec)); /* Open the db in RW to store the $mtime$ ID */ /* we know that this should succeed because we just updated the db! */ @@ -595,7 +646,7 @@ debug ("create_db(%s): %s\n", manpath, database); - amount = testmandirs (manpath, catpath, (time_t) 0, 1); + amount = testmandirs (manpath, catpath, (time_t) 0, (time_t) 0, 1); if (amount) { update_db_time (); @@ -646,6 +697,8 @@ if (dbf) { datum key, content; int new; + long sec; + int usec; memset (&key, 0, sizeof key); memset (&content, 0, sizeof content); @@ -654,16 +707,23 @@ content = MYDBM_FETCH (dbf, key); MYDBM_CLOSE (dbf); free (MYDBM_DPTR (key)); + if (MYDBM_DPTR (content)) { + char *end; + + sec = strtol (MYDBM_DPTR (content), &end, 10); + usec = *end == '.' ? strtol (end+1, NULL, 10) : 0; + } else + sec = usec = 0; - debug ("update_db(): %ld\n", - MYDBM_DPTR (content) ? atol (MYDBM_DPTR (content)) : 0L); + debug ("update_db(): %ld.%09d\n", sec, usec); if (MYDBM_DPTR (content)) { new = testmandirs ( manpath, catpath, - (time_t) atol (MYDBM_DPTR (content)), 0); + (time_t) sec, (time_t) usec, 0); MYDBM_FREE (MYDBM_DPTR (content)); } else - new = testmandirs (manpath, catpath, (time_t) 0, 0); + new = testmandirs (manpath, catpath, + (time_t) 0, (time_t) 0, 0); if (new) { update_db_time ();