Fix %{uncompress:...} double-expanding arguments + other miscellania

%{uncompress:...} is fairly complicated as far as builtin macros go:
it needs to first expand its argument to discover the actual file
its supposed to look at, then determine whether the file exists and
what sort of compression to use, then determine the macro to use
for decompressing that kind of file, expand said macro and finally
catenate the expanded argument to the lot. That's a lot of goo to
do inline doFoo(), so refactor it into a separate function.

Up to now the last step was implemented by re-expanding the argument
too, which makes it impossible to reliably handle paths with percent
signs. Just expand the command, and catenate the argument as deity
intended.

Additionally make behavior with empty argument consistent with other
builtins: %{uncompress:} expands to nothing instead of printing out
an error message with an empty filename.
This commit is contained in:
Panu Matilainen 2020-02-10 12:31:21 +02:00
parent 94623389ba
commit 227cddca88
2 changed files with 80 additions and 45 deletions

View File

@ -144,6 +144,8 @@ static void doSP(MacroBuf mb, int chkexist, int negate,
const char * f, size_t fn, const char * g, size_t gn); const char * f, size_t fn, const char * g, size_t gn);
static void doTrace(MacroBuf mb, int chkexist, int negate, static void doTrace(MacroBuf mb, int chkexist, int negate,
const char * f, size_t fn, const char * g, size_t gn); const char * f, size_t fn, const char * g, size_t gn);
static void doUncompress(MacroBuf mb, int chkexist, int negate,
const char * f, size_t fn, const char * g, size_t gn);
static const char * doDef(MacroBuf mb, const char * se); static const char * doDef(MacroBuf mb, const char * se);
static const char * doGlobal(MacroBuf mb, const char * se); static const char * doGlobal(MacroBuf mb, const char * se);
@ -577,7 +579,7 @@ static struct builtins_s {
{ STR_AND_LEN("suffix"), doFoo, NULL, 1 }, { STR_AND_LEN("suffix"), doFoo, NULL, 1 },
{ STR_AND_LEN("trace"), doTrace, NULL, 0 }, { STR_AND_LEN("trace"), doTrace, NULL, 0 },
{ STR_AND_LEN("u2p"), doFoo, NULL, 1 }, { STR_AND_LEN("u2p"), doFoo, NULL, 1 },
{ STR_AND_LEN("uncompress"),doFoo, NULL, 1 }, { STR_AND_LEN("uncompress"),doUncompress, NULL, 1 },
{ STR_AND_LEN("undefine"), NULL, doUndefine, 0 }, { STR_AND_LEN("undefine"), NULL, doUndefine, 0 },
{ STR_AND_LEN("url2path"), doFoo, NULL, 1 }, { STR_AND_LEN("url2path"), doFoo, NULL, 1 },
{ STR_AND_LEN("verbose"), doFoo, NULL, 1 }, { STR_AND_LEN("verbose"), doFoo, NULL, 1 },
@ -1074,6 +1076,65 @@ doSP(MacroBuf mb, int chkexist, int negate,
free(buf); free(buf);
} }
static void doUncompress(MacroBuf mb, int chkexist, int negate,
const char * f, size_t fn, const char * g, size_t gn)
{
rpmCompressedMagic compressed = COMPRESSED_OTHER;
char *b, *be, *buf = NULL;
int c;
if (gn) {
expandThis(mb, g, gn, &buf);
for (b = buf; (c = *b) && isblank(c);)
b++;
for (be = b; (c = *be) && !isblank(c);)
be++;
*be++ = '\0';
}
if (gn == 0 || *b == '\0')
goto exit;
if (rpmFileIsCompressed(b, &compressed))
mb->error = 1;
switch (compressed) {
default:
case COMPRESSED_NOT:
expandMacro(mb, "%__cat ", 0);
break;
case COMPRESSED_OTHER:
expandMacro(mb, "%__gzip -dc ", 0);
break;
case COMPRESSED_BZIP2:
expandMacro(mb, "%__bzip2 -dc ", 0);
break;
case COMPRESSED_ZIP:
expandMacro(mb, "%__unzip ", 0);
break;
case COMPRESSED_LZMA:
case COMPRESSED_XZ:
expandMacro(mb, "%__xz -dc ", 0);
break;
case COMPRESSED_LZIP:
expandMacro(mb, "%__lzip -dc ", 0);
break;
case COMPRESSED_LRZIP:
expandMacro(mb, "%__lrzip -dqo- ", 0);
break;
case COMPRESSED_7ZIP:
expandMacro(mb, "%__7zip x ", 0);
break;
case COMPRESSED_ZSTD:
expandMacro(mb, "%__zstd -dc ", 0);
break;
}
mbAppendStr(mb, buf);
exit:
free(buf);
}
/** /**
* Execute macro primitives. * Execute macro primitives.
* @param mb macro expansion state * @param mb macro expansion state
@ -1089,8 +1150,7 @@ doFoo(MacroBuf mb, int chkexist, int negate, const char * f, size_t fn,
const char * g, size_t gn) const char * g, size_t gn)
{ {
char *buf = NULL; char *buf = NULL;
char *b = NULL, *be; char *b = NULL;
int c;
int verbose = (rpmIsVerbose() != 0); int verbose = (rpmIsVerbose() != 0);
int expand = (g != NULL && gn > 0); int expand = (g != NULL && gn > 0);
int expandagain = 1; int expandagain = 1;
@ -1158,47 +1218,6 @@ doFoo(MacroBuf mb, int chkexist, int negate, const char * f, size_t fn,
} else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) { } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
(void)urlPath(buf, (const char **)&b); (void)urlPath(buf, (const char **)&b);
if (*b == '\0') b = "/"; if (*b == '\0') b = "/";
} else if (STREQ("uncompress", f, fn)) {
rpmCompressedMagic compressed = COMPRESSED_OTHER;
for (b = buf; (c = *b) && isblank(c);)
b++;
for (be = b; (c = *be) && !isblank(c);)
be++;
*be++ = '\0';
if (rpmFileIsCompressed(b, &compressed))
mb->error = 1;
switch (compressed) {
default:
case COMPRESSED_NOT:
sprintf(be, "%%__cat %s", b);
break;
case COMPRESSED_OTHER:
sprintf(be, "%%__gzip -dc %s", b);
break;
case COMPRESSED_BZIP2:
sprintf(be, "%%__bzip2 -dc %s", b);
break;
case COMPRESSED_ZIP:
sprintf(be, "%%__unzip %s", b);
break;
case COMPRESSED_LZMA:
case COMPRESSED_XZ:
sprintf(be, "%%__xz -dc %s", b);
break;
case COMPRESSED_LZIP:
sprintf(be, "%%__lzip -dc %s", b);
break;
case COMPRESSED_LRZIP:
sprintf(be, "%%__lrzip -dqo- %s", b);
break;
case COMPRESSED_7ZIP:
sprintf(be, "%%__7zip x %s", b);
break;
case COMPRESSED_ZSTD:
sprintf(be, "%%__zstd -dc %s", b);
break;
}
b = be;
} else if (STREQ("getenv", f, fn)) { } else if (STREQ("getenv", f, fn)) {
b = getenv(buf); b = getenv(buf);
} else if (STREQ("getconfdir", f, fn)) { } else if (STREQ("getconfdir", f, fn)) {

View File

@ -189,7 +189,7 @@ runroot rpm \
]) ])
AT_CLEANUP AT_CLEANUP
AT_SETUP([uncompress macro]) AT_SETUP([uncompress macro 1])
AT_KEYWORDS([macros]) AT_KEYWORDS([macros])
AT_CHECK([ AT_CHECK([
runroot rpm \ runroot rpm \
@ -201,6 +201,18 @@ runroot rpm \
]) ])
AT_CLEANUP AT_CLEANUP
AT_SETUP([uncompress macro 2])
AT_KEYWORDS([macros])
AT_CHECK([
echo xxxxxxxxxxxxxxxxxxxxxxxxx > ${RPMTEST}/tmp/"some%%ath"
runroot rpm \
--eval "%{uncompress:/tmp/some%%%%ath}"
],
[0],
[/usr/bin/cat /tmp/some%%ath
])
AT_CLEANUP
AT_SETUP([basename macro]) AT_SETUP([basename macro])
AT_KEYWORDS([macros]) AT_KEYWORDS([macros])
AT_CHECK([ AT_CHECK([
@ -251,6 +263,8 @@ AT_CHECK([
runroot rpm --eval "%{dirname}" runroot rpm --eval "%{dirname}"
runroot rpm --eval "%{dirname:}" runroot rpm --eval "%{dirname:}"
runroot rpm --eval "%{dirname:dir}" runroot rpm --eval "%{dirname:dir}"
runroot rpm --eval "%{uncompress}"
runroot rpm --eval "%{uncompress:}"
runroot rpm --eval "%{getncpus:}" runroot rpm --eval "%{getncpus:}"
runroot rpm --eval "%{getncpus:5}" runroot rpm --eval "%{getncpus:5}"
runroot rpm --eval "%{define:}" runroot rpm --eval "%{define:}"
@ -259,8 +273,10 @@ runroot rpm --eval "%{dump:foo}"
[1], [1],
[ [
dir dir
], ],
[error: %dirname: argument expected [error: %dirname: argument expected
error: %uncompress: argument expected
error: %getncpus: unexpected argument error: %getncpus: unexpected argument
error: %getncpus: unexpected argument error: %getncpus: unexpected argument
error: %define: unexpected argument error: %define: unexpected argument