return -errno;
regex_t re;
- const char * pattern = ".*/[a-f0-9]+/(debuginfo|executable|source.*)$";
+ const char * pattern = ".*/[a-f0-9]+(/debuginfo|/executable|/source.*|)$"; /* include dirs */
if (regcomp (&re, pattern, REG_EXTENDED | REG_NOSUB) != 0)
return -ENOMEM;
FTSENT *f;
long files = 0;
+ time_t now = time(NULL);
while ((f = fts_read(fts)) != NULL)
{
/* ignore any files that do not match the pattern. */
switch (f->fts_info)
{
case FTS_F:
- /* delete file if max_unused_age has been met or exceeded. */
- /* XXX consider extra effort to clean up old tmp files */
- if (time(NULL) - f->fts_statp->st_atime >= max_unused_age)
- unlink (f->fts_path);
+ /* delete file if max_unused_age has been met or exceeded w.r.t. atime. */
+ if (now - f->fts_statp->st_atime >= max_unused_age)
+ (void) unlink (f->fts_path);
break;
case FTS_DP:
- /* Remove if empty. */
- (void) rmdir (f->fts_path);
+ /* Remove if old & empty. Weaken race against concurrent creation by
+ checking mtime. */
+ if (now - f->fts_statp->st_mtime >= max_unused_age)
+ (void) rmdir (f->fts_path);
break;
default:
}
/* thereafter, goto out0 on error*/
- /* create target directory in cache if not found. */
- struct stat st;
- if (stat(target_cache_dir, &st) == -1 && mkdir(target_cache_dir, 0700) < 0)
- {
- rc = -errno;
- goto out0;
- }
-
- /* NB: write to a temporary file first, to avoid race condition of
- multiple clients checking the cache, while a partially-written or empty
- file is in there, being written from libcurl. */
- fd = mkstemp (target_cache_tmppath);
- if (fd < 0)
+ /* Because of a race with cache cleanup / rmdir, try to mkdir/mkstemp up to twice. */
+ for(int i=0; i<2; i++) {
+ /* (re)create target directory in cache */
+ (void) mkdir(target_cache_dir, 0700);
+
+ /* NB: write to a temporary file first, to avoid race condition of
+ multiple clients checking the cache, while a partially-written or empty
+ file is in there, being written from libcurl. */
+ fd = mkstemp (target_cache_tmppath);
+ if (fd >= 0) break;
+ }
+ if (fd < 0) /* Still failed after two iterations. */
{
rc = -errno;
goto out0;
(EXTRA_DIST): Add run-low_high_pc-dw-form-indirect.sh,
run-readelf-dw-form-indirect.sh, and testfile-dw-form-indirect.bz2.
+2021-04-26 Frank Ch. Eigler <fche@redhat.com>
+
+ PR26125
+ * run-debuginfod-find.sh: Add test case for cache cleanup rmdir.
+
2021-04-23 Frank Ch. Eigler <fche@redhat.com>
* run-debuginfod-find.sh: Add a tiny test for client object reuse.
touch $DEBUGINFOD_CACHE_PATH/malformed0
touch $DEBUGINFOD_CACHE_PATH/malformed/malformed1
+# A valid format for an empty buildid subdirectory
+mkdir $DEBUGINFOD_CACHE_PATH/00000000
+touch -d '1970-01-01' $DEBUGINFOD_CACHE_PATH/00000000 # old enough to guarantee nukage
+
# Trigger a cache clean and run the tests again. The clients should be unable to
# find the target.
echo 0 > $DEBUGINFOD_CACHE_PATH/cache_clean_interval_s
exit 1
fi
+if [ -d $DEBUGINFOD_CACHE_PATH/00000000 ]; then
+ echo "failed to rmdir old cache dir"
+ exit 1
+fi
+
# Test debuginfod without a path list; reuse $PORT1
env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -F -U -d :memory: -p $PORT1 -L -F &
PID3=$!