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
- for octal input: reset mode to 0.
- take umask into account.
- make '=rwx' etc work.
- we wont support crazy but valid modes like "a+rw,g=x,o=g"
- uudecode: use parsemode, mask is 0.
Signed-off-by: Hiltjo Posthuma <hiltjo@codemadness.org>