38FILE_RCSID(
"@(#)$File: compress.c,v 1.157 2023/05/21 15:59:58 christos Exp $")
57#ifdef HAVE_SYS_IOCTL_H
63#if defined(HAVE_SYS_TIME_H)
66#if defined(HAVE_ZLIB_H) && defined(PHP_FILEINFO_UNCOMPRESS)
67#define BUILTIN_DECOMPRESS
73#if defined(PHP_FILEINFO_UNCOMPRESS)
78#if defined(HAVE_LZMA_H) && defined(XZLIBSUPPORT)
83#if defined(HAVE_ZSTD_H) && defined(ZSTDLIBSUPPORT)
84#define BUILTIN_ZSTDLIB
86#include <zstd_errors.h>
89#if defined(HAVE_LZLIB_H) && defined(LZLIBSUPPORT)
96#define DPRINTF(...) do { \
98 tty = open("/dev/tty", O_RDWR); \
101 dprintf(tty, __VA_ARGS__); \
113static const char zlibcode[] =
114 "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
116static const char *zlib_args[] = {
"python",
"-c", zlibcode,
NULL };
119zlibcmp(
const unsigned char *
buf)
121 unsigned short x = 1;
122 unsigned char *
s =
CAST(
unsigned char *,
CAST(
void *, &x));
124 if ((
buf[0] & 0xf) != 8 || (
buf[0] & 0x80) != 0)
127 x =
buf[0] | (
buf[1] << 8);
129 x =
buf[1] | (
buf[0] << 8);
136#ifdef PHP_FILEINFO_UNCOMPRESS
139lzmacmp(
const unsigned char *
buf)
143 if (
buf[12] &&
buf[12] != 0xff)
148#define gzip_flags "-cd"
149#define lzip_flags gzip_flags
151static const char *gzip_args[] = {
152 "gzip", gzip_flags,
NULL
154static const char *uncompress_args[] = {
155 "uncompress",
"-c",
NULL
157static const char *bzip2_args[] = {
160static const char *lzip_args[] = {
161 "lzip", lzip_flags,
NULL
163static const char *xz_args[] = {
166static const char *lrzip_args[] = {
167 "lrzip",
"-qdf",
"-",
NULL
169static const char *lz4_args[] = {
172static const char *zstd_args[] = {
182 int (*
func)(
const unsigned char *);
195 { { .magic =
"\037\235" }, 2, gzip_args,
NULL },
198 { { .magic =
"\037\235" }, 2, uncompress_args,
NULL },
199 { { .magic =
"\037\213" }, 2, gzip_args, do_zlib },
200 { { .magic =
"\037\236" }, 2, gzip_args,
NULL },
201 { { .magic =
"\037\240" }, 2, gzip_args,
NULL },
203 { { .magic =
"\037\036" }, 2, gzip_args,
NULL },
204 { { .magic =
"PK\3\4" }, 4, gzip_args,
NULL },
206 { { .magic =
"BZh" }, 3, bzip2_args, do_bzlib },
207 { { .magic =
"LZIP" }, 4, lzip_args,
NULL },
208 { { .magic =
"\3757zXZ\0" },6, xz_args,
NULL },
209 { { .magic =
"LRZI" }, 4, lrzip_args,
NULL },
210 { { .magic =
"\004\"M\030" },4, lz4_args,
NULL },
211 { { .magic =
"\x28\xB5\x2F\xFD" }, 4, zstd_args,
NULL },
212 { { .func = lzmacmp }, -13, xz_args,
NULL },
214 { { .func = zlibcmp }, -2, zlib_args,
NULL },
225file_private int uncompressbuf(
int,
size_t,
size_t,
int,
const unsigned char *,
226 unsigned char **,
size_t *);
227#ifdef BUILTIN_DECOMPRESS
228file_private int uncompresszlib(
const unsigned char *,
unsigned char **,
size_t,
230file_private int uncompressgzipped(
const unsigned char *,
unsigned char **,
size_t,
234file_private int uncompressbzlib(
const unsigned char *,
unsigned char **,
size_t,
238file_private int uncompressxzlib(
const unsigned char *,
unsigned char **,
size_t,
241#ifdef BUILTIN_ZSTDLIB
242file_private int uncompresszstd(
const unsigned char *,
unsigned char **,
size_t,
246file_private int uncompresslzlib(
const unsigned char *,
unsigned char **,
size_t,
250static int makeerror(
unsigned char **,
size_t *,
const char *, ...)
255format_decompression_error(struct
magic_set *ms,
size_t i,
unsigned char *
buf)
267 return file_printf(ms,
"application/x-decompression-error-%s-%s",
274 unsigned char *newbuf =
NULL;
278 int urv, prv,
rv = 0;
281 const unsigned char *
buf =
CAST(
const unsigned char *, b->
fbuf);
282 size_t nbytes = b->
flen;
284 struct sigaction sig_act;
289 for (i = 0; i < ncompr; i++) {
291 if (nbytes <
CAST(
size_t,
abs(compr[i].maglen)))
293 if (compr[i].maglen < 0) {
294 zm = (*compr[i].u.func)(
buf);
296 zm = memcmp(
buf, compr[i].
u.magic,
297 CAST(
size_t, compr[i].maglen)) == 0;
306 struct sigaction new_act;
307 memset(&new_act, 0,
sizeof(new_act));
309 sa_saved = sigaction(
SIGPIPE, &new_act, &sig_act) != -1;
315 (ms->
flags & MAGIC_NO_COMPRESS_FORK),
buf, &newbuf, &nsz);
317 (
char *)newbuf, nsz);
323 prv = format_decompression_error(ms, i, newbuf);
335 mime ?
" compressed-encoding=" :
" (")) == -1)
372 if (sa_saved && sig_act.sa_handler !=
SIG_IGN)
386swrite(
int fd,
const void *
buf,
size_t n)
414#if defined(FIONREAD) && !defined(__MINGW32__)
422#if defined(FIONREAD) && !defined(__MINGW32__)
423 if (canbepipe && (ioctl(
fd, FIONREAD, &t) == -1 || t == 0)) {
426 for (cnt = 0;; cnt++) {
428 struct timeval tout = {0, 100 * 1000};
438 selrv = select(
fd + 1, &check,
NULL,
NULL, &tout);
442 }
else if (selrv == 0 && cnt >= 5) {
448 (
void)ioctl(
fd, FIONREAD, &t);
451 if (t > 0 &&
CAST(
size_t, t) <
n) {
501 tfd = open(
ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
519 "cannot create temporary file for pipe copy");
523 if (swrite(tfd, startbuf, nbytes) !=
CAST(ssize_t, nbytes))
527 if (swrite(tfd,
buf,
CAST(
size_t, r)) != r)
547 if ((
fd = dup2(tfd,
fd)) == -1) {
558#ifdef PHP_FILEINFO_UNCOMPRESS
559#ifdef BUILTIN_DECOMPRESS
561#define FHCRC (1 << 1)
562#define FEXTRA (1 << 2)
563#define FNAME (1 << 3)
564#define FCOMMENT (1 << 4)
568uncompressgzipped(
const unsigned char *old,
unsigned char **newch,
569 size_t bytes_max,
size_t *
n,
int extra
__attribute__((__unused__)))
572 size_t data_start = 10;
581 if (data_start + 1 >= *
n)
583 data_start += 2 + old[data_start] + old[data_start + 1] * 256;
586 while(data_start < *
n && old[data_start])
590 if (flg & FCOMMENT) {
591 while(data_start < *
n && old[data_start])
598 if (data_start >= *
n)
603 return uncompresszlib(old, newch, bytes_max,
n, 0);
605 return makeerror(newch,
n,
"File too short");
609uncompresszlib(
const unsigned char *old,
unsigned char **newch,
610 size_t bytes_max,
size_t *
n,
int zlib)
615 DPRINTF(
"builtin zlib decompression\n");
616 z.next_in =
CCAST(Bytef *, old);
617 z.avail_in =
CAST(uint32_t, *
n);
619 z.avail_out =
CAST(
unsigned int, bytes_max);
625 rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
629 rc = inflate(&z, Z_SYNC_FLUSH);
630 if (rc != Z_OK && rc != Z_STREAM_END) {
635 *
n =
CAST(
size_t, z.total_out);
645 return makeerror(newch,
n,
"%s", z.msg ? z.msg : zError(rc));
651uncompressbzlib(
const unsigned char *old,
unsigned char **newch,
652 size_t bytes_max,
size_t *
n,
int extra
__attribute__((__unused__)))
657 DPRINTF(
"builtin bzlib decompression\n");
658 memset(&bz, 0,
sizeof(bz));
659 rc = BZ2_bzDecompressInit(&bz, 0, 0);
663 bz.next_in =
CCAST(
char *,
RCAST(
const char *, old));
664 bz.avail_in =
CAST(uint32_t, *
n);
665 bz.next_out =
RCAST(
char *, *newch);
666 bz.avail_out =
CAST(
unsigned int, bytes_max);
668 rc = BZ2_bzDecompress(&bz);
669 if (rc != BZ_OK && rc != BZ_STREAM_END) {
670 BZ2_bzDecompressEnd(&bz);
676 *
n =
CAST(
size_t, bz.total_out_lo32);
677 rc = BZ2_bzDecompressEnd(&bz);
686 return makeerror(newch,
n,
"bunzip error %d", rc);
692uncompressxzlib(
const unsigned char *old,
unsigned char **newch,
693 size_t bytes_max,
size_t *
n,
int extra
__attribute__((__unused__)))
698 DPRINTF(
"builtin xzlib decompression\n");
699 memset(&xz, 0,
sizeof(xz));
700 rc = lzma_auto_decoder(&xz, UINT64_MAX, 0);
704 xz.next_in =
CCAST(
const uint8_t *, old);
705 xz.avail_in =
CAST(uint32_t, *
n);
706 xz.next_out =
RCAST(uint8_t *, *newch);
707 xz.avail_out =
CAST(
unsigned int, bytes_max);
709 rc = lzma_code(&xz, LZMA_RUN);
710 if (rc != LZMA_OK && rc != LZMA_STREAM_END) {
715 *
n =
CAST(
size_t, xz.total_out);
724 return makeerror(newch,
n,
"unxz error %d", rc);
728#ifdef BUILTIN_ZSTDLIB
730uncompresszstd(
const unsigned char *old,
unsigned char **newch,
731 size_t bytes_max,
size_t *
n,
int extra
__attribute__((__unused__)))
738 DPRINTF(
"builtin zstd decompression\n");
739 if ((zstd = ZSTD_createDStream()) ==
NULL) {
740 return makeerror(newch,
n,
"No ZSTD decompression stream, %s",
744 rc = ZSTD_DCtx_reset(zstd, ZSTD_reset_session_only);
745 if (ZSTD_isError(rc))
748 in.src =
CCAST(
const void *, old);
752 out.size = bytes_max;
755 rc = ZSTD_decompressStream(zstd, &
out, &in);
756 if (ZSTD_isError(rc))
761 ZSTD_freeDStream(zstd);
768 ZSTD_freeDStream(zstd);
769 return makeerror(newch,
n,
"zstd error %d", ZSTD_getErrorCode(rc));
775uncompresslzlib(
const unsigned char *old,
unsigned char **newch,
776 size_t bytes_max,
size_t *
n,
int extra
__attribute__((__unused__)))
779 size_t old_remaining = *
n;
780 size_t new_remaining = bytes_max;
781 size_t total_read = 0;
783 struct LZ_Decoder *dec;
787 DPRINTF(
"builtin lzlib decompression\n");
788 dec = LZ_decompress_open();
790 return makeerror(newch,
n,
"unable to allocate LZ_Decoder");
792 if (LZ_decompress_errno(dec) != LZ_ok)
799 if (old_remaining > 0) {
800 int wr = LZ_decompress_write(dec, old, old_remaining);
807 int rd = LZ_decompress_read(dec, bufp, new_remaining);
814 if (rd < 0 || LZ_decompress_errno(dec) != LZ_ok)
816 if (new_remaining == 0)
818 if (old_remaining == 0 && rd == 0)
822 LZ_decompress_close(dec);
830 err = LZ_decompress_errno(dec);
831 LZ_decompress_close(dec);
832 return makeerror(newch,
n,
"lzlib error: %s", LZ_strerror(
err));
838makeerror(
unsigned char **
buf,
size_t *
len,
const char *fmt, ...)
844 DPRINTF(
"Makeerror %s\n", fmt);
861closefd(
int *
fd,
size_t i)
873 for (i = 0; i < 2; i++)
878movedesc(
void *
v,
int i,
int fd)
882#ifdef HAVE_POSIX_SPAWNP
883 posix_spawn_file_actions_t *fa =
RCAST(posix_spawn_file_actions_t *,
v);
884 posix_spawn_file_actions_adddup2(fa,
fd, i);
885 posix_spawn_file_actions_addclose(fa,
fd);
887 if (dup2(
fd, i) == -1) {
896closedesc(
void *
v,
int fd)
898#ifdef HAVE_POSIX_SPAWNP
899 posix_spawn_file_actions_t *fa =
RCAST(posix_spawn_file_actions_t *,
v);
900 posix_spawn_file_actions_addclose(fa,
fd);
907handledesc(
void *
v,
int fd,
int fdp[3][2])
935writechild(
int fd,
const void *old,
size_t n)
950 if (swrite(
fd, old,
n) !=
CAST(ssize_t,
n)) {
961filter_error(
unsigned char *ubuf, ssize_t
n)
968 while (isspace(
CAST(
unsigned char, *
buf)))
977 while (isspace(
CAST(
unsigned char, *
p)))
982 DPRINTF(
"Filter error after[[[%s]]]\n", (
char *)ubuf);
984 *ubuf = toupper(*ubuf);
989methodname(
size_t method)
992#ifdef BUILTIN_DECOMPRESS
1006#ifdef BUILTIN_ZSTDLIB
1015 return compr[method].argv[0];
1020getdecompressor(
size_t method))(
const unsigned char *,
unsigned char **, size_t,
1024#ifdef BUILTIN_DECOMPRESS
1026 return uncompressgzipped;
1028 return uncompresszlib;
1032 return uncompressbzlib;
1037 return uncompressxzlib;
1039#ifdef BUILTIN_ZSTDLIB
1041 return uncompresszstd;
1045 return uncompresslzlib;
1053uncompressbuf(
int fd,
size_t bytes_max,
size_t method,
int nofork,
1054 const unsigned char *old,
unsigned char **newch,
size_t*
n)
1059 pid_t writepid = -1;
1063#ifdef HAVE_POSIX_SPAWNP
1064 posix_spawn_file_actions_t fa;
1066 int (*decompress)(
const unsigned char *,
unsigned char **,
1067 size_t,
size_t *, int) = getdecompressor(method);
1069 *newch =
CAST(
unsigned char *,
emalloc(bytes_max + 1));
1071 return makeerror(newch,
n,
"No buffer, %s", strerror(
errno));
1075 return makeerror(newch,
n,
1076 "Fork is required to uncompress, but disabled");
1078 return (*decompress)(old, newch, bytes_max,
n, 1);
1085 fdp[i][0] = fdp[i][1] = -1;
1106 return makeerror(newch,
n,
"Cannot create pipe, %s",
1110 args =
RCAST(
char *
const *,
RCAST(intptr_t, compr[method].argv));
1111#ifdef HAVE_POSIX_SPAWNP
1112 posix_spawn_file_actions_init(&fa);
1114 handledesc(&fa,
fd, fdp);
1116 DPRINTF(
"Executing %s\n", compr[method].argv[0]);
1117 status = posix_spawnp(&pid, compr[method].argv[0], &fa,
NULL,
1120 posix_spawn_file_actions_destroy(&fa);
1123 return makeerror(newch,
n,
"Cannot posix_spawn `%s', %s",
1124 compr[method].argv[0], strerror(
errno));
1132 return makeerror(newch,
n,
"Cannot vfork, %s",
1141 handledesc(
NULL,
fd, fdp);
1142 DPRINTF(
"Executing %s\n", compr[method].argv[0]);
1144 (
void)execvp(compr[method].argv[0],
args);
1146 compr[method].argv[0], strerror(
errno));
1147 _exit(EXIT_FAILURE);
1158 if (writepid == (pid_t)-1) {
1159 rv = makeerror(newch,
n,
"Write to child failed, %s",
1161 DPRINTF(
"Write to child failed\n");
1176 if (
CAST(
size_t, r) == bytes_max) {
1182 DPRINTF(
"Closing stdout for bytes_max\n");
1187 DPRINTF(
"Got stuff from stderr %s\n", *newch);
1189 r = filter_error(*newch, r);
1194 rv = makeerror(newch,
n,
"Read stderr failed, %s",
1200 (*newch)[*
n] =
'\0';
1206 w = waitpid(pid, &
status, 0);
1209 rv = makeerror(newch,
n,
"Wait failed, %s", strerror(
errno));
1211 }
else if (!WIFEXITED(
status)) {
1213 }
else if (WEXITSTATUS(
status) != 0) {
1221 w = waitpid(writepid, &
status, 0);
unlink(string $filename, $context=null)
getenv(?string $name=null, bool $local_only=false)
strrchr(string $haystack, string $needle, bool $before_needle=false)
strchr(string $haystack, string $needle, bool $before_needle=false)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
file_protected int file_printf(struct magic_set *, const char *,...) __attribute__((__format__(__printf__
file_protected int file_clear_closexec(int)
file_protected int file_pipe2file(struct magic_set *, int, const void *, size_t)
file_protected ssize_t sread(int, void *, size_t, int)
file_protected int file_pipe_closexec(int *)
file_protected file_pushbuf_t * file_push_buffer(struct magic_set *)
file_protected int file_buffer(struct magic_set *, php_stream *, zend_stat_t *, const char *, const void *, size_t)
file_protected void file_error(struct magic_set *, int, const char *,...) __attribute__((__format__(__printf__
file_protected char * file_pop_buffer(struct magic_set *, file_pushbuf_t *)
file_protected void file_badseek(struct magic_set *)
#define MAGIC_COMPRESS_TRANSP
exit(string|int $status=0)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)