#!/bin/sh # Test rm's behavior when the directory cannot be read. # This test is skipped on systems that lack LD_PRELOAD support. # Copyright (C) 2016-2023 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 . . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src print_ver_ rm require_gcc_shared_ mkdir -p dir/notempty || framework_failure_ # Simulate "readdir" failure. cat > k.c <<\EOF || framework_failure_ #define _GNU_SOURCE /* Setup so we don't have to worry about readdir64. */ #ifndef __LP64__ # define _FILE_OFFSET_BITS 64 #endif #include #include #include #include #include struct dirent *readdir (DIR *dirp) { static int count = 1; #ifndef __LP64__ if (count == 1) fclose (fopen ("32bit", "w")); errno = ENOSYS; return NULL; #endif static struct dirent *(*real_readdir)(DIR *dirp); if (! real_readdir && ! (real_readdir = dlsym (RTLD_NEXT, "readdir"))) { fprintf (stderr, "Failed to find readdir()\n"); errno = ESRCH; return NULL; } struct dirent* d; if (! (d = real_readdir (dirp))) { fprintf (stderr, "Failed to get dirent\n"); errno = ENOENT; return NULL; } /* Flag that LD_PRELOAD and above functions work. */ if (count == 1) fclose (fopen ("preloaded", "w")); /* Return some entries to trigger partial read failure, ensuring we don't return ignored '.' or '..' */ char const *readdir_partial = getenv ("READDIR_PARTIAL"); if (readdir_partial && *readdir_partial && count <= 3) { count++; d->d_name[0]='0'+count; d->d_name[1]='\0'; #ifdef _DIRENT_HAVE_D_NAMLEN d->d_namlen = 1; #endif errno = 0; return d; }; /* Fail. */ errno = ENOENT; return NULL; } EOF # Then compile/link it: gcc_shared_ k.c k.so \ || framework_failure_ 'failed to build shared library' # Test if LD_PRELOAD works: export READDIR_PARTIAL for READDIR_PARTIAL in '' '1'; do rm -f preloaded (export LD_PRELOAD=$LD_PRELOAD:./k.so returns_ 1 rm -Rf dir 2>>errt) || fail=1 if test -f 32bit; then skip_ 'This test only supports 64 bit systems' elif ! test -f preloaded; then cat errt skip_ "internal test failure: maybe LD_PRELOAD doesn't work?" fi done # First case is failure to read any items from dir, then assume empty. # Generally that will be diagnosed when rm tries to rmdir(). # Second case is more general error where we fail immediately # (with ENOENT in this case but it could be anything). cat < exp rm: cannot remove 'dir' Failed to get dirent rm: traversal failed: dir EOF sed 's/\(rm:.*\):.*/\1/' errt > err || framework_failure_ compare exp err || fail=1 Exit $fail