Don’t assume Linux-like S_IFREG

* boostrap.conf (gnulib_modules): Add assert-h.
* src/pch.c (fetchmode): Convert Git type to local file type.
This commit is contained in:
Paul Eggert 2024-09-07 13:08:56 -07:00
parent 0f8c62835f
commit 241e57ea5b
2 changed files with 42 additions and 10 deletions

View File

@ -19,6 +19,7 @@
# gnulib modules used by this package.
gnulib_modules="
argmatch
assert-h
attribute
backupfile
c-ctype

View File

@ -328,35 +328,66 @@ there_is_another_patch (bool need_header, mode_t *file_type)
return true;
}
/* Scan a Git-style mode from STR, and return the corresponding mode_t
suitable for use on this platform. Return 0 if the scan fails. */
static mode_t ATTRIBUTE_PURE
fetchmode (char const *str)
{
const char *s;
mode_t mode;
int mode;
while (c_isspace (*str))
str++;
for (s = str, mode = 0; s - str < 6; s++)
{
if (*s >= '0' && *s <= '7')
mode = (mode << 3) + (*s - '0');
else
{
mode = 0;
break;
}
if (! ('0' <= *s && *s <= '7'))
return 0;
mode = (mode << 3) + (*s - '0');
}
if (*s == '\r')
s++;
if (*s != '\n')
mode = 0;
return 0;
/* Check the file type. Also, convert Git numbering for file types
to this platform's numbering; ordinarily they are the same, but
POSIX does not require this. */
mode_t file_type;
switch (mode >> 9)
{
case 0100: file_type = S_IFREG; break;
#ifdef S_IFLNK
case 0120: file_type = S_IFLNK; break;
#endif
/* 'patch' can handle only files and symlinks, so fail with
other Git file types such as submodules. */
default: return 0;
}
/* 'patch' can deal only with regular files and symlinks. Because it
uses zero to indicate unknown or missing file types, S_IFLNK and
S_IFREG must be nonzero. This is true on all known platforms
although POSIX does not require it; check here to be sure. */
static_assert (S_IFLNK);
static_assert (S_IFREG);
mode_t m = file_type | (mode & S_IRWXUGO);
if (!m)
{
/* This can happen only on perverse platforms where, e.g.,
S_IFREG == 0. */
char numbuf[LINENUM_LENGTH_BOUND + 1];
fatal ("mode %.6s treated as missing at line %s: %s",
str, format_linenum (numbuf, p_input_line), patchbuf);
}
/* NOTE: The "diff --git" format always sets the file mode permission
bits of symlinks to 0. (On Linux, symlinks actually always have
0777 permissions, so this is not even consistent.) */
return mode;
return m;
}
static char *