The result is always correct but it might do redundant builds.
Not really an issue as sbase builds very fast. The alternative is
to track the header deps manually but this is already incomplete and
unlikely to be kept up to date.
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".