From c14a291902346c8555ed2ecec5a45275a9019737 Mon Sep 17 00:00:00 2001 From: Ian Morris Nieves Date: Thu, 15 Feb 2018 16:32:21 -0800 Subject: [PATCH] chmod chown chgrp: added --exclude-files and --exclude-directories chmod: added --exclude-files and --exclude-directories chown: added --exclude-files and --exclude-directories chgrp: added --exclude-files and --exclude-directories It is frequently necessary to distinguish between files and directories when setting permissions, especially when setting permissions recursively. Current solutions like +X and find are unnecessarily complex. The flags --exclude-files and --exclude-directories are intended to greatly simpify this common use case, with only minimal additional code and documentation complexity/ * src/chmod.c (enum, long_options, process_file) (usage, main): Added support for --exclude-files and --exclude-directories. (AUTHORS): updated. Doc fixes * tests/chmod/exclude.sh (all new): tests for --exclude-files and --exclude-directories. * src/chown.c (enum, long_options, usage, main): Added support for --exclude-files and --exclude-directories. (AUTHORS): updated. Doc fixes * src/chown-core.c (chopt_init, change_file_owner): Added support for --exclude-files and --exclude-directories. (AUTHORS): updated. Doc fixes * src/chown-core.h (Chown_options): Added support for --exclude-files and --exclude-directories. * tests/chown/exclude.sh (all new): tests for --exclude-files and --exclude-directories. * src/chgrp.c (enum, long_options, usage, main): Added support for --exclude-files and --exclude-directories. (AUTHORS): updated. Doc fixes * tests/chgrp/exclude.sh (all new): tests for --exclude-files and --exclude-directories. --- src/chgrp.c | 63 ++++++---- src/chmod.c | 77 ++++++++++-- src/chown-core.c | 34 +++++- src/chown-core.h | 6 + src/chown.c | 71 ++++++++---- tests/chgrp/exclude.sh | 309 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/chmod/exclude.sh | 297 +++++++++++++++++++++++++++++++++++++++++++++++ tests/chown/exclude.sh | 307 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1106 insertions(+), 58 deletions(-) create mode 100644 tests/chgrp/exclude.sh create mode 100644 tests/chmod/exclude.sh create mode 100644 tests/chown/exclude.sh diff --git a/src/chgrp.c b/src/chgrp.c index 130fa73dd..ac5c42421 100644 --- a/src/chgrp.c +++ b/src/chgrp.c @@ -14,7 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Written by David MacKenzie . */ +/* Written by David MacKenzie + Jim Meyering + Ian Morris Nieves */ #include #include @@ -36,7 +38,8 @@ #define AUTHORS \ proper_name ("David MacKenzie"), \ - proper_name ("Jim Meyering") + proper_name ("Jim Meyering"), \ + proper_name ("Ian Morris Nieves") #if ! HAVE_ENDGRENT # define endgrent() ((void) 0) @@ -53,11 +56,15 @@ enum DEREFERENCE_OPTION = CHAR_MAX + 1, NO_PRESERVE_ROOT, PRESERVE_ROOT, - REFERENCE_FILE_OPTION + REFERENCE_FILE_OPTION, + EXCLUDE_DIRECTORIES, + EXCLUDE_FILES }; static struct option const long_options[] = { + {"exclude-directories", no_argument, NULL, EXCLUDE_DIRECTORIES}, + {"exclude-files", no_argument, NULL, EXCLUDE_FILES}, {"recursive", no_argument, NULL, 'R'}, {"changes", no_argument, NULL, 'c'}, {"dereference", no_argument, NULL, DEREFERENCE_OPTION}, @@ -118,29 +125,35 @@ With --reference, change the group of each FILE to that of RFILE.\n\ \n\ "), stdout); fputs (_("\ - -c, --changes like verbose but report only when a change is made\n\ - -f, --silent, --quiet suppress most error messages\n\ - -v, --verbose output a diagnostic for every file processed\n\ + -c, --changes like verbose but report only when a change is made\n\ + -f, --silent, --quiet suppress most error messages\n\ + -v, --verbose output a diagnostic for every file processed\n\ "), stdout); fputs (_("\ - --dereference affect the referent of each symbolic link (this is\n\ - the default), rather than the symbolic link itself\n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ + --dereference affect the referent of each symbolic link (this is\n\ + the default), rather than the symbolic link itself\n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ "), stdout); fputs (_("\ - (useful only on systems that can change the\n\ - ownership of a symlink)\n\ + (useful only on systems that can change the\n\ + ownership of a symlink)\n\ "), stdout); fputs (_("\ - --no-preserve-root do not treat '/' specially (the default)\n\ - --preserve-root fail to operate recursively on '/'\n\ + --no-preserve-root do not treat '/' specially (the default)\n\ + --preserve-root fail to operate recursively on '/'\n\ "), stdout); fputs (_("\ - --reference=RFILE use RFILE's group rather than specifying a\n\ - GROUP value\n\ + --reference=RFILE use RFILE's group rather than specifying a\n\ + GROUP value\n\ "), stdout); fputs (_("\ - -R, --recursive operate on files and directories recursively\n\ + --exclude-directories don't change directories\n\ +"), stdout); + fputs (_("\ + --exclude-files don't change files\n\ +"), stdout); + fputs (_("\ + -R, --recursive operate on files and directories recursively\n\ "), stdout); fputs (_("\ \n\ @@ -148,11 +161,11 @@ The following options modify how a hierarchy is traversed when the -R\n\ option is also specified. If more than one is specified, only the final\n\ one takes effect.\n\ \n\ - -H if a command line argument is a symbolic link\n\ - to a directory, traverse it\n\ - -L traverse every symbolic link to a directory\n\ - encountered\n\ - -P do not traverse any symbolic links (default)\n\ + -H if a command line argument is a symbolic link\n\ + to a directory, traverse it\n\ + -L traverse every symbolic link to a directory\n\ + encountered\n\ + -P do not traverse any symbolic links (default)\n\ \n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); @@ -234,6 +247,14 @@ main (int argc, char **argv) reference_file = optarg; break; + case EXCLUDE_DIRECTORIES: + chopt.exclude_directories = true; + break; + + case EXCLUDE_FILES: + chopt.exclude_files = true; + break; + case 'R': chopt.recurse = true; break; diff --git a/src/chmod.c b/src/chmod.c index 0e9436c72..cfb20f335 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -14,7 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Written by David MacKenzie */ +/* Written by David MacKenzie + Jim Meyering + Ian Morris Nieves */ #include #include @@ -37,7 +39,8 @@ #define AUTHORS \ proper_name ("David MacKenzie"), \ - proper_name ("Jim Meyering") + proper_name ("Jim Meyering"), \ + proper_name ("Ian Morris Nieves") enum Change_status { @@ -68,6 +71,12 @@ static mode_t umask_value; /* If true, change the modes of directories recursively. */ static bool recurse; +/* If true, don't change the modes of files. */ +static bool exclude_files; + +/* If true, don't change the modes of directories. */ +static bool exclude_directories; + /* If true, force silence (suppress most of error messages). */ static bool force_silent; @@ -89,12 +98,16 @@ enum { NO_PRESERVE_ROOT = CHAR_MAX + 1, PRESERVE_ROOT, - REFERENCE_FILE_OPTION + REFERENCE_FILE_OPTION, + EXCLUDE_DIRECTORIES, + EXCLUDE_FILES }; static struct option const long_options[] = { {"changes", no_argument, NULL, 'c'}, + {"exclude-directories", no_argument, NULL, EXCLUDE_DIRECTORIES}, + {"exclude-files", no_argument, NULL, EXCLUDE_FILES}, {"recursive", no_argument, NULL, 'R'}, {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT}, {"preserve-root", no_argument, NULL, PRESERVE_ROOT}, @@ -195,6 +208,35 @@ process_file (FTS *fts, FTSENT *ent) bool ok = true; bool chmod_succeeded = false; + if (exclude_directories) + { + switch (ent->fts_info) + { + case FTS_D: + case FTS_DC: + case FTS_DNR: + case FTS_DOT: + case FTS_DP: + return true; + default: + break; + } + } + + if (exclude_files) + { + switch (ent->fts_info) + { + case FTS_DEFAULT: + case FTS_F: + case FTS_NS: + case FTS_NSOK: + return true; + default: + break; + } + } + switch (ent->fts_info) { case FTS_DP: @@ -340,6 +382,7 @@ process_files (char **files, int bit_flags) FTSENT *ent; ent = fts_read (fts); + if (ent == NULL) { if (errno != 0) @@ -383,19 +426,25 @@ With --reference, change the mode of each FILE to that of RFILE.\n\ \n\ "), stdout); fputs (_("\ - -c, --changes like verbose but report only when a change is made\n\ - -f, --silent, --quiet suppress most error messages\n\ - -v, --verbose output a diagnostic for every file processed\n\ + -c, --changes like verbose but report only when a change is made\n\ + -f, --silent, --quiet suppress most error messages\n\ + -v, --verbose output a diagnostic for every file processed\n\ +"), stdout); + fputs (_("\ + --no-preserve-root do not treat '/' specially (the default)\n\ + --preserve-root fail to operate recursively on '/'\n\ "), stdout); fputs (_("\ - --no-preserve-root do not treat '/' specially (the default)\n\ - --preserve-root fail to operate recursively on '/'\n\ + --reference=RFILE use RFILE's mode instead of MODE values\n\ "), stdout); fputs (_("\ - --reference=RFILE use RFILE's mode instead of MODE values\n\ + --exclude-directories don't change directories\n\ "), stdout); fputs (_("\ - -R, --recursive change files and directories recursively\n\ + --exclude-files don't change files\n\ +"), stdout); + fputs (_("\ + -R, --recursive change files and directories recursively\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -430,7 +479,7 @@ main (int argc, char **argv) atexit (close_stdout); - recurse = force_silent = diagnose_surprises = false; + recurse = exclude_files = exclude_directories = force_silent = diagnose_surprises = false; while ((c = getopt_long (argc, argv, ("Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::" @@ -490,6 +539,12 @@ main (int argc, char **argv) case REFERENCE_FILE_OPTION: reference_file = optarg; break; + case EXCLUDE_DIRECTORIES: + exclude_directories = true; + break; + case EXCLUDE_FILES: + exclude_files = true; + break; case 'R': recurse = true; break; diff --git a/src/chown-core.c b/src/chown-core.c index 818ee0ff1..c1d59b873 100644 --- a/src/chown-core.c +++ b/src/chown-core.c @@ -14,7 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. */ +/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. + Added to by Ian Morris Nieves */ #include #include @@ -61,6 +62,8 @@ chopt_init (struct Chown_option *chopt) chopt->root_dev_ino = NULL; chopt->affect_symlink_referent = true; chopt->recurse = false; + chopt->exclude_files = false; + chopt->exclude_directories = false; chopt->force_silent = false; chopt->user_name = NULL; chopt->group_name = NULL; @@ -281,6 +284,35 @@ change_file_owner (FTS *fts, FTSENT *ent, bool do_chown; bool symlink_changed = true; + if (chopt->exclude_directories) + { + switch (ent->fts_info) + { + case FTS_D: + case FTS_DC: + case FTS_DNR: + case FTS_DOT: + case FTS_DP: + return true; + default: + break; + } + } + + if (chopt->exclude_files) + { + switch (ent->fts_info) + { + case FTS_DEFAULT: + case FTS_F: + case FTS_NS: + case FTS_NSOK: + return true; + default: + break; + } + } + switch (ent->fts_info) { case FTS_D: diff --git a/src/chown-core.h b/src/chown-core.h index 26d702e2c..2e0ae053f 100644 --- a/src/chown-core.h +++ b/src/chown-core.h @@ -45,6 +45,12 @@ struct Chown_option /* Level of verbosity. */ enum Verbosity verbosity; + /* If nonzero, don't change the ownership of files. */ + bool exclude_files; + + /* If nonzero, don't change the ownership of directories. */ + bool exclude_directories; + /* If nonzero, change the ownership of directories recursively. */ bool recurse; diff --git a/src/chown.c b/src/chown.c index da6ed4ab4..7df542328 100644 --- a/src/chown.c +++ b/src/chown.c @@ -14,7 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Written by David MacKenzie . */ +/* Written by David MacKenzie + Jim Meyering + Ian Morris Nieves */ #include #include @@ -35,7 +37,8 @@ #define AUTHORS \ proper_name ("David MacKenzie"), \ - proper_name ("Jim Meyering") + proper_name ("Jim Meyering"), \ + proper_name ("Ian Morris Nieves") /* The argument to the --reference option. Use the owner and group IDs of this file. This file must exist. */ @@ -49,11 +52,15 @@ enum FROM_OPTION, NO_PRESERVE_ROOT, PRESERVE_ROOT, - REFERENCE_FILE_OPTION + REFERENCE_FILE_OPTION, + EXCLUDE_DIRECTORIES, + EXCLUDE_FILES }; static struct option const long_options[] = { + {"exclude-directories", no_argument, NULL, EXCLUDE_DIRECTORIES}, + {"exclude-files", no_argument, NULL, EXCLUDE_FILES}, {"recursive", no_argument, NULL, 'R'}, {"changes", no_argument, NULL, 'c'}, {"dereference", no_argument, NULL, DEREFERENCE_OPTION}, @@ -88,36 +95,42 @@ With --reference, change the owner and group of each FILE to those of RFILE.\n\ \n\ "), stdout); fputs (_("\ - -c, --changes like verbose but report only when a change is made\n\ - -f, --silent, --quiet suppress most error messages\n\ - -v, --verbose output a diagnostic for every file processed\n\ + -c, --changes like verbose but report only when a change is made\n\ + -f, --silent, --quiet suppress most error messages\n\ + -v, --verbose output a diagnostic for every file processed\n\ "), stdout); fputs (_("\ - --dereference affect the referent of each symbolic link (this is\n\ - the default), rather than the symbolic link itself\n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ + --dereference affect the referent of each symbolic link (this is\n\ + the default), rather than the symbolic link itself\n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ "), stdout); fputs (_("\ - (useful only on systems that can change the\n\ - ownership of a symlink)\n\ + (useful only on systems that can change the\n\ + ownership of a symlink)\n\ "), stdout); fputs (_("\ --from=CURRENT_OWNER:CURRENT_GROUP\n\ - change the owner and/or group of each file only if\n\ - its current owner and/or group match those specified\n\ - here. Either may be omitted, in which case a match\n\ - is not required for the omitted attribute\n\ + change the owner and/or group of each file only if\n\ + its current owner and/or group match those specified\n\ + here. Either may be omitted, in which case a match\n\ + is not required for the omitted attribute\n\ "), stdout); fputs (_("\ - --no-preserve-root do not treat '/' specially (the default)\n\ - --preserve-root fail to operate recursively on '/'\n\ + --no-preserve-root do not treat '/' specially (the default)\n\ + --preserve-root fail to operate recursively on '/'\n\ "), stdout); fputs (_("\ - --reference=RFILE use RFILE's owner and group rather than\n\ - specifying OWNER:GROUP values\n\ + --reference=RFILE use RFILE's owner and group rather than\n\ + specifying OWNER:GROUP values\n\ "), stdout); fputs (_("\ - -R, --recursive operate on files and directories recursively\n\ + --exclude-directories don't change directories\n\ +"), stdout); + fputs (_("\ + --exclude-files don't change files\n\ +"), stdout); + fputs (_("\ + -R, --recursive operate on files and directories recursively\n\ "), stdout); fputs (_("\ \n\ @@ -125,11 +138,11 @@ The following options modify how a hierarchy is traversed when the -R\n\ option is also specified. If more than one is specified, only the final\n\ one takes effect.\n\ \n\ - -H if a command line argument is a symbolic link\n\ - to a directory, traverse it\n\ - -L traverse every symbolic link to a directory\n\ - encountered\n\ - -P do not traverse any symbolic links (default)\n\ + -H if a command line argument is a symbolic link\n\ + to a directory, traverse it\n\ + -L traverse every symbolic link to a directory\n\ + encountered\n\ + -P do not traverse any symbolic links (default)\n\ \n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); @@ -235,6 +248,14 @@ main (int argc, char **argv) break; } + case EXCLUDE_DIRECTORIES: + chopt.exclude_directories = true; + break; + + case EXCLUDE_FILES: + chopt.exclude_files = true; + break; + case 'R': chopt.recurse = true; break; diff --git a/tests/chgrp/exclude.sh b/tests/chgrp/exclude.sh new file mode 100644 index 000000000..ccd8f4b7e --- /dev/null +++ b/tests/chgrp/exclude.sh @@ -0,0 +1,309 @@ +#!/bin/sh +# Make sure GNU chgrp works the same way as those of Solaris, HPUX, AIX +# on directories with the setgid bit set. Also, check that the GNU octal +# notations work. + +# Copyright (C) 2001-2018 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_ chgrp + +require_membership_in_two_groups_ + +set _ $groups; shift +g1=$1 +g2=$2 + +# when called on a single directory +# check --exclude-files excludes nothing +# and --exclude-directories excludes the directory + +# create directory with group g1 and check +mkdir d || framework_failure_ +chgrp $g1 d || framework_failure_ +test $(stat --p=%g d) = $g1 || fail=1 +# change group to g2 and check +chgrp $g2 d || framework_failure_ +test $(stat --p=%g d) = $g2 || fail=1 +# change group back to g1 with --exclude-directories +# and check unchanged +chgrp --exclude-directories $g1 d || fail=1 +test $(stat --p=%g d) = $g2 || fail=1 +# change group back to g1 with --exclude-files +# and check changed +chgrp --exclude-files $g1 d || fail=1 +test $(stat --p=%g d) = $g1 || fail=1 +# cleanup +rm -rf d || framework_failure_ + +# when called on a single file +# check --exclude-directories excludes nothing +# and --exclude-files excludes the file + +# create file with group g1 and check +touch f || framework_failure_ +chgrp $g1 f || framework_failure_ +test $(stat --p=%g f) = $g1 || fail=1 +# change group to g2 and check +chgrp $g2 f || framework_failure_ +test $(stat --p=%g f) = $g2 || fail=1 +# change group back to g1 with --exclude-files +# and check unchanged +chgrp --exclude-files $g1 f || fail=1 +test $(stat --p=%g f) = $g2 || fail=1 +# change group back to g1 with --exclude-directories +# and check changed +chgrp --exclude-directories $g1 f || fail=1 +test $(stat --p=%g f) = $g1 || fail=1 +# cleanup +rm -f f || framework_failure_ + +# when called on a directory with recursion (-R) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything + +# create directory with a child file +# and child directory within +mkdir d || framework_failure_ +touch d/f || framework_failure_ +mkdir d/d || framework_failure_ +# set group of parent directory to g1 +# and check +chgrp $g1 d || framework_failure_ +test $(stat --p=%g d) = $g1 || fail=1 +# set group of child file to g1 +# and check +chgrp $g1 d/f || framework_failure_ +test $(stat --p=%g d/f) = $g1 || fail=1 +# set group of child directory to g1 +# and check +chgrp $g1 d/d || framework_failure_ +test $(stat --p=%g d/d) = $g1 || fail=1 +# recursively set all to g2 with --exclude-files +# and check file unchanged +chgrp -R --exclude-files $g2 d || fail=1 +test $(stat --p=%g d) = $g2 || fail=1 +test $(stat --p=%g d/f) = $g1 || fail=1 +test $(stat --p=%g d/d) = $g2 || fail=1 +# set child file to g2 and check +chgrp $g2 d/f || framework_failure_ +test $(stat --p=%g d/f) = $g2 || framework_failure_ +# recursively set all to g1 with --exclude-directories +# and check directory unchanged +chgrp -R --exclude-directories $g1 d || fail=1 +test $(stat --p=%g d) = $g2 || fail=1 +test $(stat --p=%g d/f) = $g1 || fail=1 +test $(stat --p=%g d/d) = $g2 || fail=1 +# set child file to g2 and check +chgrp $g2 d/f || framework_failure_ +test $(stat --p=%g d/f) = $g2 || framework_failure_ +# recursively set all to g1 with --exclude-files +# and --exclude-directories and check all unchanged +chgrp -R --exclude-files --exclude-directories $g1 d || fail=1 +test $(stat --p=%g d) = $g2 || fail=1 +test $(stat --p=%g d/f) = $g2 || fail=1 +test $(stat --p=%g d/d) = $g2 || fail=1 +# cleanup +rm -rf d || framework_failure_ + +# when called on a directory with recursion (-R) +# and default of do not follow symlinks (-P) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything +# and symlink referents are affected but not the symlink +# and symlinks are not traversed +# using structure: +# +# d1 +# f2 +# f3 +# d4 +# d5 +# f6 +# s7 -> d1 +# s8 -> f3 + +# create structure +mkdir d1 || framework_failure_ +touch d1/f2 || framework_failure_ +touch f3 || framework_failure_ +mkdir d4 || framework_failure_ +mkdir d4/d5 || framework_failure_ +touch d4/f6 || framework_failure_ +ln -s ../d1 d4/s7 || framework_failure_ +ln -s ../f3 d4/s8 || framework_failure_ +# set structure to group g1 +chgrp -R $g1 d1 || framework_failure_ +chgrp $g1 f3 || framework_failure_ +chgrp $g1 d4 || framework_failure_ +chgrp $g1 d4/d5 || framework_failure_ +chgrp $g1 d4/f6 || framework_failure_ +chgrp $g1 d4/s7 || framework_failure_ +chgrp $g1 d4/s8 || framework_failure_ +# check groups set to g1 +test $(stat --p=%g d1) = $g1 || framework_failure_ +test $(stat --p=%g d1/f2) = $g1 || framework_failure_ +test $(stat --p=%g f3) = $g1 || framework_failure_ +test $(stat --p=%g d4) = $g1 || framework_failure_ +test $(stat --p=%g d4/d5) = $g1 || framework_failure_ +test $(stat --p=%g d4/f6) = $g1 || framework_failure_ +test $(stat --p=%g d4/s7) = $g1 || framework_failure_ +test $(stat --p=%g d4/s8) = $g1 || framework_failure_ +# check --exclude-directories excludes directories only +chgrp -R -P --exclude-directories $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g1 || fail=1 +test $(stat --p=%g d1/f2) = $g1 || fail=1 +test $(stat --p=%g f3) = $g1 || fail=1 +test $(stat --p=%g d4) = $g1 || fail=1 +test $(stat --p=%g d4/d5) = $g1 || fail=1 +test $(stat --p=%g d4/f6) = $g2 || fail=1 +test $(stat --p=%g d4/s7) = $g2 || fail=1 +test $(stat --p=%g d4/s8) = $g2 || fail=1 +# reset +chgrp $g1 d4/f6 || framework_failure_ +chgrp -h $g1 d4/s7 || framework_failure_ +chgrp -h $g1 d4/s8 || framework_failure_ +test $(stat --p=%g d4/f6) = $g1 || framework_failure_ +test $(stat --p=%g d4/s7) = $g1 || framework_failure_ +test $(stat --p=%g d4/s8) = $g1 || framework_failure_ +# check --exclude-files excludes files only +chgrp -R -P --exclude-files $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g1 || fail=1 +test $(stat --p=%g d1/f2) = $g1 || fail=1 +test $(stat --p=%g f3) = $g1 || fail=1 +test $(stat --p=%g d4) = $g2 || fail=1 +test $(stat --p=%g d4/d5) = $g2 || fail=1 +test $(stat --p=%g d4/f6) = $g1 || fail=1 +test $(stat --p=%g d4/s7) = $g1 || fail=1 +test $(stat --p=%g d4/s8) = $g1 || fail=1 +# reset +chgrp $g1 d4 || framework_failure_ +chgrp $g1 d4/d5 || framework_failure_ +test $(stat --p=%g d4) = $g1 || framework_failure_ +test $(stat --p=%g d4/d5) = $g1 || framework_failure_ +# check --exclude-directories and --exclude-files +# excludes everything +chgrp -R -P --exclude-directories --exclude-files $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g1 || fail=1 +test $(stat --p=%g d1/f2) = $g1 || fail=1 +test $(stat --p=%g f3) = $g1 || fail=1 +test $(stat --p=%g d4) = $g1 || fail=1 +test $(stat --p=%g d4/d5) = $g1 || fail=1 +test $(stat --p=%g d4/f6) = $g1 || fail=1 +test $(stat --p=%g d4/s7) = $g1 || fail=1 +test $(stat --p=%g d4/s8) = $g1 || fail=1 +# cleanup +rm -rf d1 || framework_failure_ +rm f3 || framework_failure_ +rm -rf d4 || framework_failure_ + +# when called on a directory with recursion (-R) +# and do follow symlinks (-L) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything +# and symlink referents are affected but not the symlink +# and symlinks are traversed +# using structure: +# +# d1 +# f2 +# f3 +# d4 +# d5 +# f6 +# s7 -> d1 +# s8 -> f3 + +# create structure +mkdir d1 || framework_failure_ +touch d1/f2 || framework_failure_ +touch f3 || framework_failure_ +mkdir d4 || framework_failure_ +mkdir d4/d5 || framework_failure_ +touch d4/f6 || framework_failure_ +ln -s ../d1 d4/s7 || framework_failure_ +ln -s ../f3 d4/s8 || framework_failure_ +# set structure to group g1 +chgrp -R $g1 d1 || framework_failure_ +chgrp $g1 f3 || framework_failure_ +chgrp $g1 d4 || framework_failure_ +chgrp $g1 d4/d5 || framework_failure_ +chgrp $g1 d4/f6 || framework_failure_ +chgrp $g1 d4/s7 || framework_failure_ +chgrp $g1 d4/s8 || framework_failure_ +# check groups set to g1 +test $(stat --p=%g d1) = $g1 || framework_failure_ +test $(stat --p=%g d1/f2) = $g1 || framework_failure_ +test $(stat --p=%g f3) = $g1 || framework_failure_ +test $(stat --p=%g d4) = $g1 || framework_failure_ +test $(stat --p=%g d4/d5) = $g1 || framework_failure_ +test $(stat --p=%g d4/f6) = $g1 || framework_failure_ +test $(stat --p=%g d4/s7) = $g1 || framework_failure_ +test $(stat --p=%g d4/s8) = $g1 || framework_failure_ +# check --exclude-directories excludes directories only +chgrp -R -L --exclude-directories $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g1 || fail=1 +test $(stat --p=%g d1/f2) = $g2 || fail=1 +test $(stat --p=%g f3) = $g2 || fail=1 +test $(stat --p=%g d4) = $g1 || fail=1 +test $(stat --p=%g d4/d5) = $g1 || fail=1 +test $(stat --p=%g d4/f6) = $g2 || fail=1 +test $(stat --p=%g d4/s7) = $g1 || fail=1 +test $(stat --p=%g d4/s8) = $g1 || fail=1 +# reset +chgrp $g1 d1/f2 || framework_failure_ +chgrp $g1 f3 || framework_failure_ +chgrp $g1 d4/f6 || framework_failure_ +test $(stat --p=%g d1/f2) = $g1 || framework_failure_ +test $(stat --p=%g f3) = $g1 || framework_failure_ +test $(stat --p=%g d4/f6) = $g1 || framework_failure_ +# check --exclude-files excludes files only +chgrp -R -L --exclude-files $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g2 || fail=1 +test $(stat --p=%g d1/f2) = $g1 || fail=1 +test $(stat --p=%g f3) = $g1 || fail=1 +test $(stat --p=%g d4) = $g2 || fail=1 +test $(stat --p=%g d4/d5) = $g2 || fail=1 +test $(stat --p=%g d4/f6) = $g1 || fail=1 +test $(stat --p=%g d4/s7) = $g1 || fail=1 +test $(stat --p=%g d4/s8) = $g1 || fail=1 +# reset +chgrp $g1 d1 || framework_failure_ +chgrp $g1 d4 || framework_failure_ +chgrp $g1 d4/d5 || framework_failure_ +test $(stat --p=%g d1) = $g1 || framework_failure_ +test $(stat --p=%g d4) = $g1 || framework_failure_ +test $(stat --p=%g d4/d5) = $g1 || framework_failure_ +# check --exclude-directories and --exclude-files +# excludes everything +chgrp -R -L --exclude-directories --exclude-files $g2 d4 || fail=1 +test $(stat --p=%g d1) = $g1 || fail=1 +test $(stat --p=%g d1/f2) = $g1 || fail=1 +test $(stat --p=%g f3) = $g1 || fail=1 +test $(stat --p=%g d4) = $g1 || fail=1 +test $(stat --p=%g d4/d5) = $g1 || fail=1 +test $(stat --p=%g d4/f6) = $g1 || fail=1 +test $(stat --p=%g d4/s7) = $g1 || fail=1 +test $(stat --p=%g d4/s8) = $g1 || fail=1 +# cleanup +rm -rf d1 || framework_failure_ +rm f3 || framework_failure_ +rm -rf d4 || framework_failure_ + +Exit $fail diff --git a/tests/chmod/exclude.sh b/tests/chmod/exclude.sh new file mode 100644 index 000000000..2e3c0c6b0 --- /dev/null +++ b/tests/chmod/exclude.sh @@ -0,0 +1,297 @@ +#!/bin/sh +# Make sure GNU chmod works the same way as those of Solaris, HPUX, AIX +# on directories with the setgid bit set. Also, check that the GNU octal +# notations work. + +# Copyright (C) 2001-2018 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_ chmod + +require_membership_in_two_groups_ + +umask 0 + +# when called on a single directory +# check --exclude-files excludes nothing +# and --exclude-directories excludes the directory + +# create directory with mode 755 and check +mkdir d || framework_failure_ +chmod 755 d || framework_failure_ +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# change mode to 700 and check +chmod 700 d || framework_failure_ +chmod -c 700 d > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# change mode back to 755 with --exclude-directories +# and check unchanged +chmod --exclude-directories 755 d || fail=1 +chmod -c 700 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# change mode back to 755 with --exclude-directories +# and --exclude-files and check unchanged +chmod --exclude-directories --exclude-files 755 d || fail=1 +chmod -c 700 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# change mode back to 755 with --exclude-files +# and check changed +chmod --exclude-files 755 d || fail=1 +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# cleanup +rm -rf d || framework_failure_ + +# when called on a single file +# check --exclude-directories excludes nothing +# and --exclude-files excludes the file + +# create file with mode 755 and check +touch f || framework_failure_ +chmod 755 f || framework_failure_ +chmod -c 755 f > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# change mode to 700 and ckeck +chmod 700 f || framework_failure_ +chmod -c 700 f > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# change mode back to 755 with --exclude-files +# and check unchanged +chmod --exclude-files 755 f || fail=1 +chmod -c 700 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# change mode back to 755 with --exclude-files +# and --exclude-directories and check unchanged +chmod --exclude-files --exclude-directories 755 f || fail=1 +chmod -c 700 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# change mode back to 755 with --exclude-directories +# and check changed +chmod --exclude-directories 755 f || fail=1 +chmod -c 755 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# cleanup +rm -f f || framework_failure_ + +# when called on a directory with recursion (-R) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything + +# create directory with a child file +# and child directory within +mkdir d || framework_failure_ +touch d/f || framework_failure_ +mkdir d/d || framework_failure_ +# set permissions of parent directory to 755 +# and check +chmod 755 d || framework_failure_ +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# set permissions of child file to 755 +# and check +chmod 755 d/f || framework_failure_ +chmod -c 755 d/f > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# set permissions of child directory to 755 +# and check +chmod 755 d/d || framework_failure_ +chmod -c 755 d/d > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# recursively set all to 744 with --exclude-files +# and check file unchanged +chmod -R --exclude-files 744 d || fail=1 +chmod -c 744 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d/f > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d/d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# recursively set all to 733 with --exclude-directories +# and check directory unchanged +chmod -R --exclude-directories 733 d || fail=1 +chmod -c 744 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 733 d/f > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d/d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# recursively set all to 722 with --exclude-files +# and --exclude-directories and check all unchanged +chmod -R --exclude-files --exclude-directories 722 d || fail=1 +chmod -c 744 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 733 d/f > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d/d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# cleanup +rm -rf d || framework_failure_ + +# when called on a directory with recursion (-R) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything +# and symlink are ignored +# and symlinks are not traversed +# using structure: +# +# d1 +# f2 +# f3 +# d4 +# d5 +# f6 +# s7 -> d1 +# s8 -> f3 + +# create structure +mkdir d1 || framework_failure_ +touch d1/f2 || framework_failure_ +touch f3 || framework_failure_ +mkdir d4 || framework_failure_ +mkdir d4/d5 || framework_failure_ +touch d4/f6 || framework_failure_ +ln -s ../d1 d4/s7 || framework_failure_ +ln -s ../f3 d4/s8 || framework_failure_ +# set all to 755 +chmod -R 755 d1 || framework_failure_ +chmod 755 f3 || framework_failure_ +chmod -R 755 d4 || framework_failure_ +# check all 755 +chmod -c 755 d1 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 d1/f2 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 f3 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 d4 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 d4/d5 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 d4/f6 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# check --exclude-directories excludes directories only +chmod -R --exclude-directories 744 d4 || fail=1 +chmod -c 755 d1 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d1/f2 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 f3 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4/d5 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d4/f6 > empty || framework_failure_ +compare /dev/null empty || fail=1 +# reset +chmod 755 d4/f6 || framework_failure_ +chmod -c 755 d4/f6 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# check --exclude-files excludes files only +chmod -R --exclude-files 744 d4 || fail=1 +chmod -c 755 d1 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d1/f2 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 f3 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d4 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 d4/d5 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4/f6 > empty || framework_failure_ +compare /dev/null empty || fail=1 +# reset +chmod 755 d4 || framework_failure_ +chmod 755 d4/d5 || framework_failure_ +chmod -c 755 d4 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +chmod -c 755 d4/d5 > empty || framework_failure_ +compare /dev/null empty || framework_failure_ +# check --exclude-directories and --exclude-files +# excludes everything +chmod -R --exclude-directories --exclude-files 744 d4 || fail=1 +chmod -c 755 d1 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d1/f2 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 f3 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4/d5 > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 d4/f6 > empty || framework_failure_ +compare /dev/null empty || fail=1 +# cleanup +rm -rf d1 || framework_failure_ +rm f3 || framework_failure_ +rm -rf d4 || framework_failure_ + +# when called on symlink to a directory +# and a symlink to a file +# check --exclude-files excludes the target file only +# and --exclude-directories excludes the target directory only +# and --exclude-files and --exclude-directories excludes both + +# creat directory and file and links +mkdir d || framework_failure_ +touch f || framework_failure_ +ln -s d linkd || framework_failure_ +ln -s f linkf || framework_failure_ +# set permissions to 755 +chmod 755 d || framework_failure_ +chmod 755 f || framework_failure_ +# check --exclude-directories excludes directories +chmod --exclude-directories 744 linkd || fail=1 +chmod --exclude-directories 744 linkf || fail=1 +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 744 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# reset +chmod 755 f || framework_failure_ +chmod -c 755 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# check --exclude-files excludes files +chmod --exclude-files 744 linkd || fail=1 +chmod --exclude-files 744 linkf || fail=1 +chmod -c 744 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# reset +chmod 755 d || framework_failure_ +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +# check --exclude-directories and --exclude-files +# excludes directories and files +chmod --exclude-directories --exclude-files 744 linkd || fail=1 +chmod --exclude-directories --exclude-files 744 linkf || fail=1 +chmod -c 755 d > empty || framework_failure_ +compare /dev/null empty || fail=1 +chmod -c 755 f > empty || framework_failure_ +compare /dev/null empty || fail=1 +# cleanup +rm linkd || framework_failure_ +rm linkf || framework_failure_ +rm -rf d || framework_failure_ +rm f || framework_failure_ + +Exit $fail diff --git a/tests/chown/exclude.sh b/tests/chown/exclude.sh new file mode 100644 index 000000000..15c06a380 --- /dev/null +++ b/tests/chown/exclude.sh @@ -0,0 +1,307 @@ +#!/bin/sh +# Make sure GNU chown works the same way as those of Solaris, HPUX, AIX +# on directories with the setgid bit set. Also, check that the GNU octal +# notations work. + +# Copyright (C) 2001-2018 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_ chown + +require_membership_in_two_groups_ + +set _ $groups; shift +g1=$1 +g2=$2 + +# when called on a single directory +# check --exclude-files excludes nothing +# and --exclude-directories excludes the directory + +# create directory with owner g1 and check +mkdir d || framework_failure_ +chown $g1 d || framework_failure_ +test $(stat --p=%u d) = $g1 || fail=1 +# change owner to g2 and check +chown $g2 d || framework_failure_ +test $(stat --p=%u d) = $g2 || fail=1 +# change owner back to g1 with --exclude-directories +# and check unchanged +chown --exclude-directories $g1 d || fail=1 +test $(stat --p=%u d) = $g2 || fail=1 +# change owner back to g1 with --exclude-files +# and check changed +chown --exclude-files $g1 d || fail=1 +test $(stat --p=%u d) = $g1 || fail=1 +# cleanup +rm -rf d || framework_failure_ + +# when called on a single file +# check --exclude-directories excludes nothing +# and --exclude-files excludes the file + +# create file with owner g1 and check +touch f || framework_failure_ +chown $g1 f || framework_failure_ +test $(stat --p=%u f) = $g1 || fail=1 +# change owner to g2 and check +chown $g2 f || framework_failure_ +test $(stat --p=%u f) = $g2 || fail=1 +# change owner back to g1 with --exclude-files +# and check unchanged +chown --exclude-files $g1 f || fail=1 +test $(stat --p=%u f) = $g2 || fail=1 +# change owner back to g1 with --exclude-directories +# and check changed +chown --exclude-directories $g1 f || fail=1 +test $(stat --p=%u f) = $g1 || fail=1 +# cleanup +rm -f f || framework_failure_ + +# when called on a directory with recursion (-R) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything + +# create directory with a child file +# and child directory within +mkdir d || framework_failure_ +touch d/f || framework_failure_ +mkdir d/d || framework_failure_ +# set owner of parent directory to g1 +# and check +chown $g1 d || framework_failure_ +test $(stat --p=%u d) = $g1 || fail=1 +# set owner of child file to g1 +# and check +chown $g1 d/f || framework_failure_ +test $(stat --p=%u d/f) = $g1 || fail=1 +# set owner of child directory to g1 +# and check +chown $g1 d/d || framework_failure_ +test $(stat --p=%u d/d) = $g1 || fail=1 +# recursively set all to g2 with --exclude-files +# and check file unchanged +chown -R --exclude-files $g2 d || fail=1 +test $(stat --p=%u d) = $g2 || fail=1 +test $(stat --p=%u d/f) = $g1 || fail=1 +test $(stat --p=%u d/d) = $g2 || fail=1 +# set child file to g2 and check +chown $g2 d/f || framework_failure_ +test $(stat --p=%u d/f) = $g2 || framework_failure_ +# recursively set all to g1 with --exclude-directories +# and check directory unchanged +chown -R --exclude-directories $g1 d || fail=1 +test $(stat --p=%u d) = $g2 || fail=1 +test $(stat --p=%u d/f) = $g1 || fail=1 +test $(stat --p=%u d/d) = $g2 || fail=1 +# set child file to g2 and check +chown $g2 d/f || framework_failure_ +test $(stat --p=%u d/f) = $g2 || framework_failure_ +# recursively set all to g1 with --exclude-files +# and --exclude-directories and check all unchanged +chown -R --exclude-files --exclude-directories $g1 d || fail=1 +test $(stat --p=%u d) = $g2 || fail=1 +test $(stat --p=%u d/f) = $g2 || fail=1 +test $(stat --p=%u d/d) = $g2 || fail=1 + +# when called on a directory with recursion (-R) +# and default of do not follow symlinks (-P) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything +# and symlink referents are affected but not the symlink +# and symlinks are not traversed +# using structure: +# +# d1 +# f2 +# f3 +# d4 +# d5 +# f6 +# s7 -> d1 +# s8 -> f3 + +# create structure +mkdir d1 || framework_failure_ +touch d1/f2 || framework_failure_ +touch f3 || framework_failure_ +mkdir d4 || framework_failure_ +mkdir d4/d5 || framework_failure_ +touch d4/f6 || framework_failure_ +ln -s ../d1 d4/s7 || framework_failure_ +ln -s ../f3 d4/s8 || framework_failure_ +# set structure to owner g1 +chown -R $g1 d1 || framework_failure_ +chown $g1 f3 || framework_failure_ +chown $g1 d4 || framework_failure_ +chown $g1 d4/d5 || framework_failure_ +chown $g1 d4/f6 || framework_failure_ +chown $g1 d4/s7 || framework_failure_ +chown $g1 d4/s8 || framework_failure_ +# check owners set to g1 +test $(stat --p=%u d1) = $g1 || framework_failure_ +test $(stat --p=%u d1/f2) = $g1 || framework_failure_ +test $(stat --p=%u f3) = $g1 || framework_failure_ +test $(stat --p=%u d4) = $g1 || framework_failure_ +test $(stat --p=%u d4/d5) = $g1 || framework_failure_ +test $(stat --p=%u d4/f6) = $g1 || framework_failure_ +test $(stat --p=%u d4/s7) = $g1 || framework_failure_ +test $(stat --p=%u d4/s8) = $g1 || framework_failure_ +# check --exclude-directories excludes directories only +chown -R -P --exclude-directories $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g1 || fail=1 +test $(stat --p=%u d1/f2) = $g1 || fail=1 +test $(stat --p=%u f3) = $g1 || fail=1 +test $(stat --p=%u d4) = $g1 || fail=1 +test $(stat --p=%u d4/d5) = $g1 || fail=1 +test $(stat --p=%u d4/f6) = $g2 || fail=1 +test $(stat --p=%u d4/s7) = $g2 || fail=1 +test $(stat --p=%u d4/s8) = $g2 || fail=1 +# reset +chown $g1 d4/f6 || framework_failure_ +chown -h $g1 d4/s7 || framework_failure_ +chown -h $g1 d4/s8 || framework_failure_ +test $(stat --p=%u d4/f6) = $g1 || framework_failure_ +test $(stat --p=%u d4/s7) = $g1 || framework_failure_ +test $(stat --p=%u d4/s8) = $g1 || framework_failure_ +# check --exclude-files excludes files only +chown -R -P --exclude-files $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g1 || fail=1 +test $(stat --p=%u d1/f2) = $g1 || fail=1 +test $(stat --p=%u f3) = $g1 || fail=1 +test $(stat --p=%u d4) = $g2 || fail=1 +test $(stat --p=%u d4/d5) = $g2 || fail=1 +test $(stat --p=%u d4/f6) = $g1 || fail=1 +test $(stat --p=%u d4/s7) = $g1 || fail=1 +test $(stat --p=%u d4/s8) = $g1 || fail=1 +# reset +chown $g1 d4 || framework_failure_ +chown $g1 d4/d5 || framework_failure_ +test $(stat --p=%u d4) = $g1 || framework_failure_ +test $(stat --p=%u d4/d5) = $g1 || framework_failure_ +# check --exclude-directories and --exclude-files +# excludes everything +chown -R -P --exclude-directories --exclude-files $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g1 || fail=1 +test $(stat --p=%u d1/f2) = $g1 || fail=1 +test $(stat --p=%u f3) = $g1 || fail=1 +test $(stat --p=%u d4) = $g1 || fail=1 +test $(stat --p=%u d4/d5) = $g1 || fail=1 +test $(stat --p=%u d4/f6) = $g1 || fail=1 +test $(stat --p=%u d4/s7) = $g1 || fail=1 +test $(stat --p=%u d4/s8) = $g1 || fail=1 +# cleanup +rm -rf d1 || framework_failure_ +rm f3 || framework_failure_ +rm -rf d4 || framework_failure_ + +# when called on a directory with recursion (-R) +# and do follow symlinks (-L) +# check --exclude-directories excludes directories only +# and --exclude-files excludes files only +# and combined they exclude everything +# and symlink referents are affected but not the symlink +# and symlinks are traversed +# using structure: +# +# d1 +# f2 +# f3 +# d4 +# d5 +# f6 +# s7 -> d1 +# s8 -> f3 + +# create structure +mkdir d1 || framework_failure_ +touch d1/f2 || framework_failure_ +touch f3 || framework_failure_ +mkdir d4 || framework_failure_ +mkdir d4/d5 || framework_failure_ +touch d4/f6 || framework_failure_ +ln -s ../d1 d4/s7 || framework_failure_ +ln -s ../f3 d4/s8 || framework_failure_ +# set structure to owner g1 +chown -R $g1 d1 || framework_failure_ +chown $g1 f3 || framework_failure_ +chown $g1 d4 || framework_failure_ +chown $g1 d4/d5 || framework_failure_ +chown $g1 d4/f6 || framework_failure_ +chown $g1 d4/s7 || framework_failure_ +chown $g1 d4/s8 || framework_failure_ +# check owner set to g1 +test $(stat --p=%u d1) = $g1 || framework_failure_ +test $(stat --p=%u d1/f2) = $g1 || framework_failure_ +test $(stat --p=%u f3) = $g1 || framework_failure_ +test $(stat --p=%u d4) = $g1 || framework_failure_ +test $(stat --p=%u d4/d5) = $g1 || framework_failure_ +test $(stat --p=%u d4/f6) = $g1 || framework_failure_ +test $(stat --p=%u d4/s7) = $g1 || framework_failure_ +test $(stat --p=%u d4/s8) = $g1 || framework_failure_ +# check --exclude-directories excludes directories only +chown -R -L --exclude-directories $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g1 || fail=1 +test $(stat --p=%u d1/f2) = $g2 || fail=1 +test $(stat --p=%u f3) = $g2 || fail=1 +test $(stat --p=%u d4) = $g1 || fail=1 +test $(stat --p=%u d4/d5) = $g1 || fail=1 +test $(stat --p=%u d4/f6) = $g2 || fail=1 +test $(stat --p=%u d4/s7) = $g1 || fail=1 +test $(stat --p=%u d4/s8) = $g1 || fail=1 +# reset +chown $g1 d1/f2 || framework_failure_ +chown $g1 f3 || framework_failure_ +chown $g1 d4/f6 || framework_failure_ +test $(stat --p=%u d1/f2) = $g1 || framework_failure_ +test $(stat --p=%u f3) = $g1 || framework_failure_ +test $(stat --p=%u d4/f6) = $g1 || framework_failure_ +# check --exclude-files excludes files only +chown -R -L --exclude-files $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g2 || fail=1 +test $(stat --p=%u d1/f2) = $g1 || fail=1 +test $(stat --p=%u f3) = $g1 || fail=1 +test $(stat --p=%u d4) = $g2 || fail=1 +test $(stat --p=%u d4/d5) = $g2 || fail=1 +test $(stat --p=%u d4/f6) = $g1 || fail=1 +test $(stat --p=%u d4/s7) = $g1 || fail=1 +test $(stat --p=%u d4/s8) = $g1 || fail=1 +# reset +chown $g1 d1 || framework_failure_ +chown $g1 d4 || framework_failure_ +chown $g1 d4/d5 || framework_failure_ +test $(stat --p=%u d1) = $g1 || framework_failure_ +test $(stat --p=%u d4) = $g1 || framework_failure_ +test $(stat --p=%u d4/d5) = $g1 || framework_failure_ +# check --exclude-directories and --exclude-files +# excludes everything +chown -R -L --exclude-directories --exclude-files $g2 d4 || fail=1 +test $(stat --p=%u d1) = $g1 || fail=1 +test $(stat --p=%u d1/f2) = $g1 || fail=1 +test $(stat --p=%u f3) = $g1 || fail=1 +test $(stat --p=%u d4) = $g1 || fail=1 +test $(stat --p=%u d4/d5) = $g1 || fail=1 +test $(stat --p=%u d4/f6) = $g1 || fail=1 +test $(stat --p=%u d4/s7) = $g1 || fail=1 +test $(stat --p=%u d4/s8) = $g1 || fail=1 +# cleanup +rm -rf d1 || framework_failure_ +rm f3 || framework_failure_ +rm -rf d4 || framework_failure_ + +Exit $fail -- 2.13.6 (Apple Git-96)