10f66f451Sopenharmony_ci/* gzip.c - gzip/gunzip/zcat 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2017 The Android Open Source Project 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/gzip.html 60f66f451Sopenharmony_ci * GZIP RFC: http://www.ietf.org/rfc/rfc1952.txt 70f66f451Sopenharmony_ci * 80f66f451Sopenharmony_ci * todo: qtv --rsyncable 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ci// gzip.net version allows all options for all commands. 110f66f451Sopenharmony_ciUSE_GZIP(NEWTOY(gzip, "ncdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN)) 120f66f451Sopenharmony_ciUSE_GUNZIP(NEWTOY(gunzip, "cdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN)) 130f66f451Sopenharmony_ciUSE_ZCAT(NEWTOY(zcat, "cdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN)) 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ciconfig GZIP 160f66f451Sopenharmony_ci bool "gzip" 170f66f451Sopenharmony_ci default n 180f66f451Sopenharmony_ci help 190f66f451Sopenharmony_ci usage: gzip [-19cdfk] [FILE...] 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci Compress files. With no files, compresses stdin to stdout. 220f66f451Sopenharmony_ci On success, the input files are removed and replaced by new 230f66f451Sopenharmony_ci files with the .gz suffix. 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci -c Output to stdout 260f66f451Sopenharmony_ci -d Decompress (act as gunzip) 270f66f451Sopenharmony_ci -f Force: allow overwrite of output file 280f66f451Sopenharmony_ci -k Keep input files (default is to remove) 290f66f451Sopenharmony_ci -# Compression level 1-9 (1:fastest, 6:default, 9:best) 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ciconfig GUNZIP 320f66f451Sopenharmony_ci bool "gunzip" 330f66f451Sopenharmony_ci default y 340f66f451Sopenharmony_ci help 350f66f451Sopenharmony_ci usage: gunzip [-cfk] [FILE...] 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci Decompress files. With no files, decompresses stdin to stdout. 380f66f451Sopenharmony_ci On success, the input files are removed and replaced by new 390f66f451Sopenharmony_ci files without the .gz suffix. 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci -c Output to stdout (act as zcat) 420f66f451Sopenharmony_ci -f Force: allow read from tty 430f66f451Sopenharmony_ci -k Keep input files (default is to remove) 440f66f451Sopenharmony_ci 450f66f451Sopenharmony_ciconfig ZCAT 460f66f451Sopenharmony_ci bool "zcat" 470f66f451Sopenharmony_ci default y 480f66f451Sopenharmony_ci help 490f66f451Sopenharmony_ci usage: zcat [FILE...] 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci Decompress files to stdout. Like `gzip -dc`. 520f66f451Sopenharmony_ci 530f66f451Sopenharmony_ci -f Force: allow read from tty 540f66f451Sopenharmony_ci*/ 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci#define FORCE_FLAGS 570f66f451Sopenharmony_ci#define FOR_gzip 580f66f451Sopenharmony_ci#include "toys.h" 590f66f451Sopenharmony_ci 600f66f451Sopenharmony_ciGLOBALS( 610f66f451Sopenharmony_ci int level; 620f66f451Sopenharmony_ci) 630f66f451Sopenharmony_ci 640f66f451Sopenharmony_ci// Use assembly optimized zlib code? 650f66f451Sopenharmony_ci#if CFG_TOYBOX_LIBZ 660f66f451Sopenharmony_ci#include <zlib.h> 670f66f451Sopenharmony_ci 680f66f451Sopenharmony_ci// Read from in_fd, write to out_fd, decompress if dd else compress 690f66f451Sopenharmony_cistatic int do_deflate(int in_fd, int out_fd, int dd, int level) 700f66f451Sopenharmony_ci{ 710f66f451Sopenharmony_ci int len, err = 0; 720f66f451Sopenharmony_ci char *b = "r"; 730f66f451Sopenharmony_ci gzFile gz; 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_ci if (!dd) { 760f66f451Sopenharmony_ci sprintf(b = toybuf, "w%d", level); 770f66f451Sopenharmony_ci if (out_fd == 1) out_fd = xdup(out_fd); 780f66f451Sopenharmony_ci } 790f66f451Sopenharmony_ci if (!(gz = gzdopen(dd ? in_fd : out_fd, b))) perror_exit("gzdopen"); 800f66f451Sopenharmony_ci if (dd) { 810f66f451Sopenharmony_ci if (gzdirect(gz)) error_exit("not gzip"); 820f66f451Sopenharmony_ci while ((len = gzread(gz, toybuf, sizeof(toybuf))) > 0) 830f66f451Sopenharmony_ci if (len != writeall(out_fd, toybuf, len)) break; 840f66f451Sopenharmony_ci } else { 850f66f451Sopenharmony_ci while ((len = read(in_fd, toybuf, sizeof(toybuf))) > 0) 860f66f451Sopenharmony_ci if (len != gzwrite(gz, toybuf, len)) break; 870f66f451Sopenharmony_ci } 880f66f451Sopenharmony_ci 890f66f451Sopenharmony_ci err = !!len; 900f66f451Sopenharmony_ci if (len>0 || err == Z_ERRNO) perror_msg(dd ? "write" : "read"); 910f66f451Sopenharmony_ci if (len<0) 920f66f451Sopenharmony_ci error_msg("%s%s: %s", "gz", dd ? "read" : "write", gzerror(gz, &len)); 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci if (gzclose(gz) != Z_OK) perror_msg("gzclose"), err++; 950f66f451Sopenharmony_ci 960f66f451Sopenharmony_ci return err; 970f66f451Sopenharmony_ci} 980f66f451Sopenharmony_ci 990f66f451Sopenharmony_ci// Use toybox's builtin lib/deflate.c 1000f66f451Sopenharmony_ci#else 1010f66f451Sopenharmony_ci 1020f66f451Sopenharmony_ci// Read from in_fd, write to out_fd, decompress if dd else compress 1030f66f451Sopenharmony_cistatic int do_deflate(int in_fd, int out_fd, int dd, int level) 1040f66f451Sopenharmony_ci{ 1050f66f451Sopenharmony_ci int x; 1060f66f451Sopenharmony_ci 1070f66f451Sopenharmony_ci if (dd) WOULD_EXIT(x, gunzip_fd(in_fd, out_fd)); 1080f66f451Sopenharmony_ci else WOULD_EXIT(x, gzip_fd(in_fd, out_fd)); 1090f66f451Sopenharmony_ci 1100f66f451Sopenharmony_ci return x; 1110f66f451Sopenharmony_ci} 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci#endif 1140f66f451Sopenharmony_ci 1150f66f451Sopenharmony_cistatic void do_gzip(int ifd, char *in) 1160f66f451Sopenharmony_ci{ 1170f66f451Sopenharmony_ci struct stat sb; 1180f66f451Sopenharmony_ci char *out = 0; 1190f66f451Sopenharmony_ci int ofd = 0; 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_ci // Are we writing to stdout? 1220f66f451Sopenharmony_ci if (!ifd || FLAG(c)) ofd = 1; 1230f66f451Sopenharmony_ci if (isatty(ifd)) { 1240f66f451Sopenharmony_ci if (!FLAG(f)) return error_msg("%s:need -f to read TTY"+3*!!ifd, in); 1250f66f451Sopenharmony_ci else ofd = 1; 1260f66f451Sopenharmony_ci } 1270f66f451Sopenharmony_ci 1280f66f451Sopenharmony_ci // Are we reading file.gz to write to file? 1290f66f451Sopenharmony_ci if (!ofd) { 1300f66f451Sopenharmony_ci if (fstat(ifd, &sb)) return perror_msg("%s", in); 1310f66f451Sopenharmony_ci 1320f66f451Sopenharmony_ci // Add or remove .gz suffix as necessary 1330f66f451Sopenharmony_ci if (!FLAG(d)) out = xmprintf("%s%s", in, ".gz"); 1340f66f451Sopenharmony_ci else if ((out = strend(in, ".gz"))>in) out = xstrndup(in, out-in); 1350f66f451Sopenharmony_ci else return error_msg("no .gz: %s", in); 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci ofd = xcreate(out, O_CREAT|O_WRONLY|WARN_ONLY|(O_EXCL*!FLAG(f)),sb.st_mode); 1380f66f451Sopenharmony_ci if (ofd == -1) return; 1390f66f451Sopenharmony_ci } 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci if (do_deflate(ifd, ofd, FLAG(d), TT.level)) in = out; 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci if (out) { 1440f66f451Sopenharmony_ci struct timespec times[] = {sb.st_atim, sb.st_mtim}; 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci if (utimensat(AT_FDCWD, out, times, 0)) perror_exit("utimensat"); 1470f66f451Sopenharmony_ci if (chmod(out, sb.st_mode)) perror_exit("chmod"); 1480f66f451Sopenharmony_ci close(ofd); 1490f66f451Sopenharmony_ci if (!FLAG(k) && in && unlink(in)) perror_msg("unlink %s", in); 1500f66f451Sopenharmony_ci free(out); 1510f66f451Sopenharmony_ci } 1520f66f451Sopenharmony_ci} 1530f66f451Sopenharmony_ci 1540f66f451Sopenharmony_civoid gzip_main(void) 1550f66f451Sopenharmony_ci{ 1560f66f451Sopenharmony_ci // This depends on 1-9 being at the end of the option list 1570f66f451Sopenharmony_ci for (TT.level = 0; TT.level<9; TT.level++) 1580f66f451Sopenharmony_ci if ((toys.optflags>>TT.level)&1) break; 1590f66f451Sopenharmony_ci if (!(TT.level = 9-TT.level)) TT.level = 6; 1600f66f451Sopenharmony_ci 1610f66f451Sopenharmony_ci loopfiles(toys.optargs, do_gzip); 1620f66f451Sopenharmony_ci} 1630f66f451Sopenharmony_ci 1640f66f451Sopenharmony_civoid gunzip_main(void) 1650f66f451Sopenharmony_ci{ 1660f66f451Sopenharmony_ci toys.optflags |= FLAG_d; 1670f66f451Sopenharmony_ci gzip_main(); 1680f66f451Sopenharmony_ci} 1690f66f451Sopenharmony_ci 1700f66f451Sopenharmony_civoid zcat_main(void) 1710f66f451Sopenharmony_ci{ 1720f66f451Sopenharmony_ci toys.optflags |= (FLAG_c|FLAG_d); 1730f66f451Sopenharmony_ci gzip_main(); 1740f66f451Sopenharmony_ci} 175