I found quite a lot of bugs, so I ended up pretty much rewriting as I
followed the spec¹.
Now, it works as follows:
- Determine a mask (who) of bits that can be modified for the subsequent
operations. If none are specified, select all file mode bits.
- In a loop, determine which operation (+, -, =) to apply.
- If the next character is a permcopy (u, g, o), set the new permissions
(perm) corresponding to the bits set in the user, group or other parts
of the existing mode.
- Otherwise, set the new permissions by looping through the next r, w,
x, s, t characters.
- Now, the set of bits we want to add or remove is (who & perm). Set or
remove these bits according the the operation (first clearing the
appropriate bits if the operation is =).
- Continue from the top if the next character is a comma, otherwise,
process the next operation.
I tested this on some made up inputs, and I believe it is working
correctly now:
parsemode("g+w", 0644, 0), before: 0606, now: 0664, fixed
parsemode("u+rx", 0222, 0), before: 0077, now: 0722, fixed
parsemode("+x", 0644, 023), before: 0754, now: 0754, still works
parsemode("+w", 0444, 022), before: 0644, now: 0644, still works
parsemode("+w", 0444, 0), before: 0666, now: 0666, still works
parsemode("+s", 0755, 0), before: 0755, now: 6755, fixed
parsemode("u+s", 0755, 0), before: 0055, now: 4755, fixed
parsemode("g+s", 0755, 0), before: 0705, now: 2755, fixed
parsemode("g=u", 0700, 0), before: 0000, now: 0770, fixed
parsemode("go=u-w", 0700, 0), before: 0000, now: 0755, fixed
parsemode("o+u-g", 0641, 0), before: 0000, now: 0643, fixed
parsemode("u=rx,o+w,g-r", 0654, 0) before: error, now: 0516, fixed
parsemode(",", 0654, 0), before: error, now: error, still works
¹ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/chmod.html
Otherwise, a pattern with a '$' anchor will never match and POSIX says that
"By default, an input line shall be selected if any pattern ... matches any
part of the line excluding the terminating <newline>"
POSIX recommends that "For backwards-compatibility, a typeflag value of
binary zero ( '\0' ) should be recognized as meaning a regular file when
extracting files from the archive".
patch taken from openbsd.
Ingo Schwarze says:
If you call the col(1) utility with the -f option, permitting forward
half-line feeds in the output stream, and the input stream actually
contains half-line feeds in either direction, you end up with corrupt
output, containing meaningless escape-digitnine sequences instead of
the required escape-tab sequences.
$ hexdump -C half.txt
00000000 61 1b 09 62 1b 09 63 0a |a..b..c.|
00000008
$ col -f < half.txt | hexdump -C
00000000 61 1b 39 0d 20 62 1b 39 0d 20 20 63 0a |a.9. b.9. c.|
0000000d
Note how the third character changes from 0x09 to 0x39.
OK to commit the following fix? Don't worry, it isn't dangerous,
it only changes two *bits*, only a quarter of a byte.
The bug was introduced by the original author, Michael Rendell,
and committed by Keith Bostic on May 22, 1990 (SCCS rev. 5.1).
The following operating systems are affected:
* 4.3BSD Reno, BSD Net/2, 4.4BSD, 4.4BSD Lite1, 4.4BSD Lite2
* All versions of 386BSD, NetBSD, OpenBSD, FreeBSD and DragonFly
* All versions of Debian GNU/Linux and probably many other Linuxes
Evan Gates says:
After writing my own test[0] I checked and sbase already has test. I'm
including a patch to remove test from the TODO. I also noticed that
sbase's test handles a few specific cases incorrectly (documentation
at [1]).
test ! = foo
When there are 3 arguments and the second is a valid binary primary
test should perform that binary test. Only if the second argument is
not a valid binary primary and the first is ! should test negate the
two argument test. I've attached a patch that should fix this.
test ! ! !
test ! ! ! !
When there are 3 arguments and the second is not a valid primary and
the first is !, test should return the negation of the remaining two
argument test. In this case sbase's test works correctly for ! and ! !
but fails afterwards as it's not recursive. I don't yet have a patch
for this but I'm working on one.
Then again both of these areas may be places in which worse is better.
[0] 11329f3834/test.c?at=master
[1] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html