Some tar archives (eg. ftp://ftp.gnu.org/gnu/shtool/shtool-2.0.8.tar.gz)
use leading spaces instead of leading zeroes for numeric fields.
Although it is not allowed by the ustar specification, most tar
implementations recognize it as correct. But since 3ef6d4e4, we
replace all spaces by NULs here, not just trailing ones, which leads to
recognizing such archives as malformed. This fixes it: we now skip
over leading spaces, allowing strtol(3) to read those numeric fields.
Since musl 1.1.23, it too does not provide `major` and `minor` through
sys/types.h, so instead include sys/sysmacros.h based on the absence of
`major` rather than only on glibc.
Thanks to Rich Felker for the suggestion.
On glibc, major, minor, and makedev are all defined in
sys/sysmacros.h with types.h only including this for historical
reasons. A future release of glibc will remove this behaviour,
meaning that major, minor, and makedev will no longer be defined
for us without including sysmacros.h.
Previously, with -p, the specified directory and all of its parents
would be 0777&~filemask (regardless of the -m flag). POSIX says parent
directories must created as (0300|~filemask)&0777, and of course if -m
is set, the specified directory should be created with those
permissions.
Additionally, POSIX says that for symbolic_mode strings, + and - should
be interpretted relative to a default mode of 0777 (not 0).
Without -p, previously the directory would be created first with
0777&~filemask (before a chmod), but POSIX says that the directory shall
at no point in time have permissions less restrictive than the -m mode
argument.
Rather than dealing with mkdir removing the filemask bits by calling
chmod afterward, just clear the umask and remove the bits manually.
In the description of 3111908b03, it says
that the functions must be able to handle st being NULL, but recurse
always passes a valid pointer. The only function that was ever passed
NULL was rm(), but this was changed to go through recurse in
2f4ab52739, so now the checks are
pointless.
by re-ordering when chmod/chown is done, only a list of directories (not
all files) need be kept for fixing mtime.
this also fixes an issue where set-user-id files in a tar may not work. chmod
is done before chown and before the file is written. if ownership changes, or
the file is being written as a normal user, the setuid bit would be cleared.
also fixes ownership of symbolic links. previously a chown() was called,
which would change the ownership of the link target. lchown() is now
used for symbolic links.
renamed all ent, ent* functions to dir* as it better describes what they
do.
use timespec/utimensat instead of timeval/utimes to get AT_SYMLINK_NOFOLLOW
Rely on what the system provides. These are not standardized macros
but any relevant UNIX system will provide them.
We can revisit this in the future if something breaks.
When we selectively process entries from the archive, ensure that
we jump over the data section of each uninteresting entry before going
on to process the next entry. Not doing so, leaves the file stream
pointer in the wrong place.
This particular change does not have any immediate shortcomings.
We still print a warning to alert the user.
Exiting on a chown() failure caused problems when untarring
inside a restricted user namespace on Linux where the uid/gid
mappings were limited.