diff options
author | Jim Meyering <meyering@redhat.com> | 2011-01-08 17:44:55 +0100 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2011-01-10 07:49:55 +0100 |
commit | 1c5987d2effdfae93362fcc4575c8ca4057740fc (patch) | |
tree | 370a04cf2fbf018b89cf1e02d81ed2bcf37e6759 /tests/du | |
parent | d5d283dbc9ae8d727470975bc8fdd3371468cbdf (diff) | |
download | coreutils-1c5987d2effdfae93362fcc4575c8ca4057740fc.tar.xz |
du: don't abort when a subdir is renamed during traversal
* NEWS (Bug fixes): Mention it.
* src/du.c (prev_level): Move declaration "up" to file-scope global.
(du_files): Reset prev_level to 0 upon abnormal fts_read termination.
Reported by Johathan Nieder in http://bugs.debian.org/609049
Also, improve a diagnostic.
* tests/du/move-dir-while-traversing: Test for the above.
* tests/Makefile.am (TESTS): Add it.
Diffstat (limited to 'tests/du')
-rwxr-xr-x | tests/du/move-dir-while-traversing | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/tests/du/move-dir-while-traversing b/tests/du/move-dir-while-traversing new file mode 100755 index 000000000..fe1615c31 --- /dev/null +++ b/tests/du/move-dir-while-traversing @@ -0,0 +1,83 @@ +#!/bin/sh +# Trigger a failed assertion in coreutils-8.9 and earlier. + +# Copyright (C) 2011 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. "${srcdir=.}/init.sh"; path_prepend_ ../src +print_ver_ du + +# We use a python-inotify script, so... +python -m pyinotify -h > /dev/null \ + || skip_ 'python inotify package not installed' + +# Move a directory "up" while du is processing its sub-directories. +# While du is processing a hierarchy .../B/C/D/... this script +# detects when du opens D/, and then moves C/ "up" one level +# so that it is a sibling of B/. +# Given the inherent race condition, we have to add enough "weight" +# under D/ so that in most cases, the monitor performs the single +# rename syscall before du finishes processing the subtree under D/. + +cat <<'EOF' > inotify-watch-for-dir-access.py +#!/usr/bin/env python +import pyinotify as pn +import os,sys + +dir = sys.argv[1] +dest_parent = os.path.dirname(os.path.dirname(dir)) +dest = os.path.join(dest_parent, os.path.basename(dir)) + +class ProcessDir(pn.ProcessEvent): + + def process_IN_OPEN(self, event): + os.rename(dir, dest) + sys.exit(0) + + def process_default(self, event): + pass + +wm = pn.WatchManager() +notifier = pn.Notifier(wm) +wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir) +sys.stdout.write('started\n') +sys.stdout.flush() +notifier.loop() +EOF +chmod a+x inotify-watch-for-dir-access.py + +long=d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z +t=T/U +mkdir -p $t/3/a/b/c/$long d2 || framework_failure +timeout 6 ./inotify-watch-for-dir-access.py $t/3/a/b > start-msg & + +# Wait for the watcher to start... +nonempty() { test -s start-msg || { sleep $1; return 1; }; } +retry_delay_ nonempty .1 5 + +# The above watches for an IN_OPEN event on $t/3/a/b, +# and when it triggers, moves the parent, $t/3/a, up one level +# so it's directly under $t. + +du -a $t d2 2> err +# Before coreutils-8.10, du would abort. +test $? = 1 || fail=1 + +# check for the new diagnostic +printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \ + || fail=1 +compare err exp || fail=1 + +Exit $fail |