231 lines
4 KiB
C
231 lines
4 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <flate.h>
|
|
#include "gzip.h"
|
|
|
|
static int gzipf(char*, int);
|
|
static int gzip(char*, long, int, Biobuf*);
|
|
static int crcread(void *fd, void *buf, int n);
|
|
static int gzwrite(void *bout, void *buf, int n);
|
|
|
|
static Biobuf bout;
|
|
static ulong crc;
|
|
static ulong *crctab;
|
|
static int debug;
|
|
static int eof;
|
|
static int level;
|
|
static ulong totr;
|
|
static int verbose;
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");
|
|
exits("usage");
|
|
}
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i, ok, stdout;
|
|
char **oargv;
|
|
|
|
oargv = argv;
|
|
level = 6;
|
|
stdout = 0;
|
|
ARGBEGIN{
|
|
case 'D':
|
|
debug++;
|
|
break;
|
|
case 'd':
|
|
/*
|
|
* gnu tar expects gzip -d to decompress
|
|
* humor it. ugh.
|
|
*/
|
|
/* remove -d from command line - magic! */
|
|
if(strcmp(argv[0], "-d") == 0){
|
|
while(*argv++)
|
|
*(argv-1) = *argv;
|
|
}else
|
|
memmove(_args-1, _args, strlen(_args)+1);
|
|
exec("gunzip", oargv);
|
|
sysfatal("exec gunzip failed");
|
|
break;
|
|
case 'f':
|
|
/* force */
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
case 'c':
|
|
stdout = 1;
|
|
break;
|
|
case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
level = ARGC() - '0';
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}ARGEND
|
|
|
|
crctab = mkcrctab(GZCRCPOLY);
|
|
ok = deflateinit();
|
|
if(ok != FlateOk)
|
|
sysfatal("deflateinit failed: %s\n", flateerr(ok));
|
|
|
|
if(argc == 0){
|
|
Binit(&bout, 1, OWRITE);
|
|
ok = gzip(nil, time(0), 0, &bout);
|
|
Bterm(&bout);
|
|
}else{
|
|
ok = 1;
|
|
for(i = 0; i < argc; i++)
|
|
ok &= gzipf(argv[i], stdout);
|
|
}
|
|
exits(ok ? nil: "errors");
|
|
}
|
|
|
|
static int
|
|
gzipf(char *file, int stdout)
|
|
{
|
|
Dir *dir;
|
|
char ofile[256], *f, *s;
|
|
int ifd, ofd, ok;
|
|
|
|
ifd = open(file, OREAD);
|
|
if(ifd < 0){
|
|
fprint(2, "gzip: can't open %s: %r\n", file);
|
|
return 0;
|
|
}
|
|
dir = dirfstat(ifd);
|
|
if(dir == nil){
|
|
fprint(2, "gzip: can't stat %s: %r\n", file);
|
|
close(ifd);
|
|
return 0;
|
|
}
|
|
if(dir->mode & DMDIR){
|
|
fprint(2, "gzip: can't compress a directory\n");
|
|
close(ifd);
|
|
free(dir);
|
|
return 0;
|
|
}
|
|
|
|
if(stdout){
|
|
ofd = 1;
|
|
strcpy(ofile, "<stdout>");
|
|
}else{
|
|
f = strrchr(file, '/');
|
|
if(f != nil)
|
|
f++;
|
|
else
|
|
f = file;
|
|
s = strrchr(f, '.');
|
|
if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
|
|
*s = '\0';
|
|
snprint(ofile, sizeof(ofile), "%s.tgz", f);
|
|
}else
|
|
snprint(ofile, sizeof(ofile), "%s.gz", f);
|
|
ofd = create(ofile, OWRITE, 0666);
|
|
if(ofd < 0){
|
|
fprint(2, "gzip: can't open %s: %r\n", ofile);
|
|
close(ifd);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if(verbose)
|
|
fprint(2, "compressing %s to %s\n", file, ofile);
|
|
|
|
Binit(&bout, ofd, OWRITE);
|
|
ok = gzip(file, dir->mtime, ifd, &bout);
|
|
if(!ok || Bflush(&bout) < 0){
|
|
fprint(2, "gzip: error writing %s: %r\n", ofile);
|
|
if(!stdout)
|
|
remove(ofile);
|
|
}
|
|
Bterm(&bout);
|
|
free(dir);
|
|
close(ifd);
|
|
close(ofd);
|
|
return ok;
|
|
}
|
|
|
|
static int
|
|
gzip(char *file, long mtime, int ifd, Biobuf *bout)
|
|
{
|
|
int flags, err;
|
|
|
|
flags = 0;
|
|
Bputc(bout, GZMAGIC1);
|
|
Bputc(bout, GZMAGIC2);
|
|
Bputc(bout, GZDEFLATE);
|
|
|
|
if(file != nil)
|
|
flags |= GZFNAME;
|
|
Bputc(bout, flags);
|
|
|
|
Bputc(bout, mtime);
|
|
Bputc(bout, mtime>>8);
|
|
Bputc(bout, mtime>>16);
|
|
Bputc(bout, mtime>>24);
|
|
|
|
Bputc(bout, 0);
|
|
Bputc(bout, GZOSINFERNO);
|
|
|
|
if(flags & GZFNAME)
|
|
Bwrite(bout, file, strlen(file)+1);
|
|
|
|
crc = 0;
|
|
eof = 0;
|
|
totr = 0;
|
|
err = deflate(bout, gzwrite, (void*)(uintptr)ifd, crcread, level, debug);
|
|
if(err != FlateOk){
|
|
fprint(2, "gzip: deflate failed: %s\n", flateerr(err));
|
|
return 0;
|
|
}
|
|
|
|
Bputc(bout, crc);
|
|
Bputc(bout, crc>>8);
|
|
Bputc(bout, crc>>16);
|
|
Bputc(bout, crc>>24);
|
|
|
|
Bputc(bout, totr);
|
|
Bputc(bout, totr>>8);
|
|
Bputc(bout, totr>>16);
|
|
Bputc(bout, totr>>24);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
crcread(void *fd, void *buf, int n)
|
|
{
|
|
int nr, m;
|
|
|
|
nr = 0;
|
|
for(; !eof && n > 0; n -= m){
|
|
m = read((int)(uintptr)fd, (char*)buf+nr, n);
|
|
if(m <= 0){
|
|
eof = 1;
|
|
if(m < 0)
|
|
return -1;
|
|
break;
|
|
}
|
|
nr += m;
|
|
}
|
|
crc = blockcrc(crctab, crc, buf, nr);
|
|
totr += nr;
|
|
return nr;
|
|
}
|
|
|
|
static int
|
|
gzwrite(void *bout, void *buf, int n)
|
|
{
|
|
if(n != Bwrite(bout, buf, n)){
|
|
eof = 1;
|
|
return -1;
|
|
}
|
|
return n;
|
|
}
|