"C:\foo" names the root of drive C, but "C:foo" names foo relative to
whatever the current directory on C happens to be. Classifying the
second as absolute means it is resolved from a root it does not name.
Rejecting absolute names was also the only thing keeping a
drive-relative name out of a patch, so is_safe_patch_path() now refuses
a colon itself. A colon never appears in a Windows file name, since
"file:stream" names an alternate data stream of "file" rather than a
file of that name.
Quoted paths encode each filename byte with at most three octal digits.
Accumulate in a wider type and reject values above 0377 instead of
relying on an implicit narrowing conversion and wraparound.
A name taken from a patch was used as is, so an absolute name or one
which kept a '..' component after -p stripping could read and write
anywhere on the filesystem.
This seems to have been settled on as 'unsafe', so refuse such paths
after stripping, so that stripping may still turn an unsafe name into a
safe one.
In particular, this has the nice side effect of slightly simplifying
parse_git_header_name to not have a dead check for the git header.
We are also able to remove LineParser::end() and LineParser::current()
with these changes.
Finally, this allows us to get rid of the substr with magic number
checks when parsing file names.
I discovered this when trying to test implementing support for non-ASCII
filenames for patch file paths when comparing these files using the diff
tool. Apparently these may not be UTF8 encoded, and may instead be
expressed in octal.
Which appears to be what git uses, as opposed to what I have mainly been
testing against using GNU diff.
This took a while to figure out as originally I did not realise that the
git style patches were placing a trailing tab after the filename in for
these patches. The tab seems to be the only way which we can possibly
distinguish these filenames from a timestamp since we also support using
spaces as a timestamp to filename separator.