diff options
author | Jim Meyering <meyering@redhat.com> | 2012-05-04 16:42:31 +0200 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2012-05-07 13:39:48 +0200 |
commit | ee9e43460f366406edff96b5abfb3ff33587e062 (patch) | |
tree | 7451920817eb2c42bcc4aee062074f46e2f9d041 /tests | |
parent | 3468d26884800d7bc6fcc1ba52cd481175c655d8 (diff) | |
download | coreutils-ee9e43460f366406edff96b5abfb3ff33587e062.tar.xz |
cp: handle a race condition more sensibly
* src/copy.c (copy_reg): In a narrow race (stat sees dest, yet
open-without-O_CREAT fails with ENOENT), retry the open with O_CREAT.
* tests/cp/nfs-removal-race: New file.
* tests/Makefile.am (TESTS): Add it.
* NEWS (Bug fixes): Mention it.
Reported by Philipp Thomas and Neil F. Brown in
http://bugs.gnu.org/11100
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/cp/nfs-removal-race | 70 |
2 files changed, 71 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index 72717e318..ca190517b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -349,6 +349,7 @@ TESTS = \ cp/link-no-deref \ cp/link-preserve \ cp/link-symlink \ + cp/nfs-removal-race \ cp/no-deref-link1 \ cp/no-deref-link2 \ cp/no-deref-link3 \ diff --git a/tests/cp/nfs-removal-race b/tests/cp/nfs-removal-race new file mode 100755 index 000000000..6a435b0c5 --- /dev/null +++ b/tests/cp/nfs-removal-race @@ -0,0 +1,70 @@ +#!/bin/sh +# Running cp S D on an NFS client while another client has just removed D +# would lead (w/coreutils-8.16 and earlier) to cp's initial stat call +# seeing (via stale NFS cache) that D exists, so that cp would then call +# open without the O_CREAT flag. Yet, the open must actually consult +# the server, which confesses that D has been deleted, thus causing the +# open call to fail with ENOENT. +# +# This test simulates that situation by intercepting stat for a nonexistent +# destination, D, and making the stat fill in the result struct for another +# file and return 0. +# +# This test is skipped on systems that lack LD_PRELOAD support; that's fine. +# Similarly, on a system that lacks <dlfcn.h> or __xstat, skipping it is fine. + +# Copyright (C) 2012 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_ cp + +# Replace each stat call with a call to this wrapper. +cat > k.c <<'EOF' || framework_failure_ +#define _GNU_SOURCE +#include <sys/types.h> +#include <dlfcn.h> + +#define __xstat __xstat_orig + +#include <sys/stat.h> +#include <stddef.h> + +#undef __xstat + +int +__xstat (int ver, const char *path, struct stat *st) +{ + static int (*real_stat)(int ver, const char *path, struct stat *st) = NULL; + if (!real_stat) + real_stat = dlsym (RTLD_NEXT, "__xstat"); + /* When asked to stat nonexistent "d", + return results suggesting it exists. */ + return real_stat (ver, *path == 'd' && path[1] == 0 ? "d2" : path, st); +} +EOF + +# Then compile/link it: +$CC -shared -fPIC -O2 k.c -o k.so \ + || framework_failure_ 'failed to compile with -shared -fPIC' + +touch d2 || framework_failure_ +echo xyz > src || framework_failure_ + +# Finally, run the test: +LD_PRELOAD=./k.so cp src d || fail=1 + +compare src d || fail=1 +Exit $fail |