#define STATE_2ND_HALF 2
#define STATE_OCTAL_NUM 3
+static int mode_dest_special_bits(int where)
+{
+ int bits = 0;
+
+ if (where & 0100)
+ bits |= S_ISUID;
+ if (where & 0010)
+ bits |= S_ISGID;
+ if (where & 0001)
+ bits |= S_ISVTX;
+
+ return bits;
+}
+
/* Parse a chmod-style argument, and break it down into one or more AND/OR
* pairs in a linked list. We return a pointer to new items on success
* (appending the items to the specified list), or NULL on error. */
curr_mode->ModeOP = op;
break;
case CHMOD_EQ:
- curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
+ curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0)
+ - (copybits ? mode_dest_special_bits(where) : 0);
curr_mode->ModeOR = bits + topoct;
curr_mode->ModeCOPY_SRC = copybits;
curr_mode->ModeCOPY_DST = where;
checkit(['-avv', '--chmod', 'ug-s,a+rX,D+w', f'{FROMDIR}/', f'{TODIR}/'],
checkdir, TODIR)
-def check_permcopy(chmod_arg, start_mode, expected):
+def check_permcopy(chmod_arg, start_mode, expected, is_dir=False):
rmtree(FROMDIR)
rmtree(TODIR)
makepath(FROMDIR)
- (FROMDIR / 'permcopy').write_text('permcopy\n')
- os.chmod(FROMDIR / 'permcopy', start_mode)
+ permcopy = FROMDIR / 'permcopy'
+ if is_dir:
+ permcopy.mkdir()
+ else:
+ permcopy.write_text('permcopy\n')
+ os.chmod(permcopy, start_mode)
run_rsync('-avv', f'--chmod={chmod_arg}', f'{FROMDIR}/', f'{TODIR}/')
check_perms(TODIR / 'permcopy', expected)
check_permcopy('g=o,o=', 0o647, 'rw-rwx---')
check_permcopy('g=u', 0o741, 'rwxrwx--x')
check_permcopy('g-o', 0o775, 'rwx-w-r-x')
+check_permcopy('u=g', 0o4755, 'r-xr-xr-x')
+check_permcopy('g=u', 0o2755, 'rwxrwxr-x')
+check_permcopy('o=u', 0o1750, 'rwxr-xrwx', is_dir=True)
rmtree(FROMDIR)
rmtree(TODIR)