plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

bzip2.c (3850B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include "bzlib.h"
      5 
      6 static	int	bzipf(char*, int);
      7 static	int	bzip(char*, long, int, Biobuf*);
      8 
      9 static	Biobuf	bout;
     10 static	int	level;
     11 static	int	debug;
     12 static	int	verbose;
     13 
     14 
     15 static void
     16 usage(void)
     17 {
     18 	fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n");
     19 	exits("usage");
     20 }
     21 
     22 void
     23 main(int argc, char **argv)
     24 {
     25 	int i, ok, stdout;
     26 	char **oargv;
     27 
     28 	oargv = argv;
     29 	level = 6;
     30 	stdout = 0;
     31 	ARGBEGIN{
     32 	case 'D':
     33 		debug++;
     34 		break;
     35 	case 'v':
     36 		verbose++;
     37 		break;
     38 	case 'c':
     39 		stdout++;
     40 		break;
     41 	case 'f':
     42 		/* force */
     43 		break;
     44 	case 'd':
     45 		/*
     46 		 * gnu tar expects bzip2 -d to decompress
     47 		 * humor it.  ugh.
     48 		 */
     49 		/* remove -d from command line - magic! */
     50 		if(strcmp(argv[0], "-d") == 0){
     51 			while(*argv++)
     52 				*(argv-1) = *argv;
     53 		}else
     54 			memmove(_args-1, _args, strlen(_args)+1);
     55 		exec("bunzip2", oargv);
     56 		sysfatal("exec bunzip2 failed");
     57 		break;
     58 	case '1': case '2': case '3': case '4':
     59 	case '5': case '6': case '7': case '8': case '9':
     60 		level = ARGC() - '0';
     61 		break;
     62 	default:
     63 		usage();
     64 		break;
     65 	}ARGEND
     66 
     67 	if(argc == 0){
     68 		Binit(&bout, 1, OWRITE);
     69 		ok = bzip(nil, time(0), 0, &bout);
     70 		Bterm(&bout);
     71 	}else{
     72 		ok = 1;
     73 		for(i = 0; i < argc; i++)
     74 			ok &= bzipf(argv[i], stdout);
     75 	}
     76 	exits(ok ? nil: "errors");
     77 }
     78 
     79 static int
     80 bzipf(char *file, int stdout)
     81 {
     82 	Dir *dir;
     83 	char ofile[128], *f, *s;
     84 	int ifd, ofd, ok;
     85 
     86 	ifd = open(file, OREAD);
     87 	if(ifd < 0){
     88 		fprint(2, "bzip2: can't open %s: %r\n", file);
     89 		return 0;
     90 	}
     91 	dir = dirfstat(ifd);
     92 	if(dir == nil){
     93 		fprint(2, "bzip2: can't stat %s: %r\n", file);
     94 		close(ifd);
     95 		return 0;
     96 	}
     97 	if(dir->mode & DMDIR){
     98 		fprint(2, "bzip2: can't compress a directory\n");
     99 		close(ifd);
    100 		free(dir);
    101 		return 0;
    102 	}
    103 
    104 	if(stdout){
    105 		ofd = 1;
    106 		strcpy(ofile, "<stdout>");
    107 	}else{
    108 		f = strrchr(file, '/');
    109 		if(f != nil)
    110 			f++;
    111 		else
    112 			f = file;
    113 		s = strrchr(f, '.');
    114 		if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
    115 			*s = '\0';
    116 			snprint(ofile, sizeof(ofile), "%s.tbz", f);
    117 		}else
    118 			snprint(ofile, sizeof(ofile), "%s.bz2", f);
    119 		ofd = create(ofile, OWRITE, 0666);
    120 		if(ofd < 0){
    121 			fprint(2, "bzip2: can't open %s: %r\n", ofile);
    122 			free(dir);
    123 			close(ifd);
    124 			return 0;
    125 		}
    126 	}
    127 
    128 	if(verbose)
    129 		fprint(2, "compressing %s to %s\n", file, ofile);
    130 
    131 	Binit(&bout, ofd, OWRITE);
    132 	ok = bzip(file, dir->mtime, ifd, &bout);
    133 	if(!ok || Bflush(&bout) < 0){
    134 		fprint(2, "bzip2: error writing %s: %r\n", ofile);
    135 		if(!stdout)
    136 			remove(ofile);
    137 	}
    138 	Bterm(&bout);
    139 	free(dir);
    140 	close(ifd);
    141 	close(ofd);
    142 	return ok;
    143 }
    144 
    145 static int
    146 bzip(char *file, long mtime, int ifd, Biobuf *bout)
    147 {
    148 	int e, n, done, onemore;
    149 	char buf[8192];
    150 	char obuf[8192];
    151 	Biobuf bin;
    152 	bz_stream strm;
    153 
    154 	USED(file);
    155 	USED(mtime);
    156 
    157 	memset(&strm, 0, sizeof strm);
    158 	BZ2_bzCompressInit(&strm, level, verbose, 0);
    159 
    160 	strm.next_in = buf;
    161 	strm.avail_in = 0;
    162 	strm.next_out = obuf;
    163 	strm.avail_out = sizeof obuf;
    164 
    165 	done = 0;
    166 	Binit(&bin, ifd, OREAD);
    167 
    168 	/*
    169 	 * onemore is a crummy hack to go 'round the loop
    170 	 * once after we finish, to flush the output buffer.
    171 	 */
    172 	onemore = 1;
    173 	SET(e);
    174 	do {
    175 		if(!done && strm.avail_in < sizeof buf) {
    176 			if(strm.avail_in)
    177 				memmove(buf, strm.next_in, strm.avail_in);
    178 
    179 			n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
    180 			if(n <= 0)
    181 				done = 1;
    182 			else
    183 				strm.avail_in += n;
    184 			strm.next_in = buf;
    185 		}
    186 		if(strm.avail_out < sizeof obuf) {
    187 			Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out);
    188 			strm.next_out = obuf;
    189 			strm.avail_out = sizeof obuf;
    190 		}
    191 
    192 		if(onemore == 0)
    193 			break;
    194 	} while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--);
    195 
    196 	if(e != BZ_STREAM_END) {
    197 		fprint(2, "bzip2: compress failed\n");
    198 		return 0;
    199 	}
    200 
    201 	if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
    202 		fprint(2, "bzip2: compress end failed (can't happen)\n");
    203 		return 0;
    204 	}
    205 
    206 	Bterm(&bin);
    207 
    208 	return 1;
    209 }