plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

mkext.c (5827B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 
      5 #define mkdir plan9mkdir
      6 
      7 enum{
      8 	LEN	= 8*1024,
      9 	NFLDS	= 6,		/* filename, modes, uid, gid, mtime, bytes */
     10 };
     11 
     12 int	selected(char*, int, char*[]);
     13 void	mkdirs(char*, char*);
     14 void	mkdir(char*, ulong, ulong, char*, char*);
     15 void	extract(char*, ulong, ulong, char*, char*, uvlong);
     16 void	seekpast(uvlong);
     17 void	error(char*, ...);
     18 void	warn(char*, ...);
     19 void	usage(void);
     20 #pragma varargck argpos warn 1
     21 #pragma varargck argpos error 1
     22 
     23 Biobuf	bin;
     24 uchar	binbuf[2*LEN];
     25 char	linebuf[LEN];
     26 int	uflag;
     27 int	hflag;
     28 int	vflag;
     29 int	Tflag;
     30 
     31 void
     32 main(int argc, char **argv)
     33 {
     34 	Biobuf bout;
     35 	char *fields[NFLDS], name[2*LEN], *p, *namep;
     36 	char *uid, *gid;
     37 	ulong mode, mtime;
     38 	uvlong bytes;
     39 
     40 	quotefmtinstall();
     41 	namep = name;
     42 	ARGBEGIN{
     43 	case 'd':
     44 		p = ARGF();
     45 		if(strlen(p) >= LEN)
     46 			error("destination fs name too long\n");
     47 		strcpy(name, p);
     48 		namep = name + strlen(name);
     49 		break;
     50 	case 'h':
     51 		hflag = 1;
     52 		Binit(&bout, 1, OWRITE);
     53 		break;
     54 	case 'u':
     55 		uflag = 1;
     56 		Tflag = 1;
     57 		break;
     58 	case 'T':
     59 		Tflag = 1;
     60 		break;
     61 	case 'v':
     62 		vflag = 1;
     63 		break;
     64 	default:
     65 		usage();
     66 	}ARGEND
     67 
     68 	Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
     69 	while(p = Brdline(&bin, '\n')){
     70 		p[Blinelen(&bin)-1] = '\0';
     71 		strcpy(linebuf, p);
     72 		p = linebuf;
     73 		if(strcmp(p, "end of archive") == 0){
     74 			Bterm(&bout);
     75 			fprint(2, "done\n");
     76 			exits(0);
     77 		}
     78 		if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
     79 			warn("too few fields in file header");
     80 			continue;
     81 		}
     82 		p = unquotestrdup(fields[0]);
     83 		strcpy(namep, p);
     84 		free(p);
     85 		mode = strtoul(fields[1], 0, 8);
     86 		uid = fields[2];
     87 		gid = fields[3];
     88 		mtime = strtoul(fields[4], 0, 10);
     89 		bytes = strtoull(fields[5], 0, 10);
     90 		if(argc){
     91 			if(!selected(namep, argc, argv)){
     92 				if(bytes)
     93 					seekpast(bytes);
     94 				continue;
     95 			}
     96 			mkdirs(name, namep);
     97 		}
     98 		if(hflag){
     99 			Bprint(&bout, "%q %luo %q %q %lud %llud\n",
    100 				name, mode, uid, gid, mtime, bytes);
    101 			if(bytes)
    102 				seekpast(bytes);
    103 			continue;
    104 		}
    105 		if(mode & DMDIR)
    106 			mkdir(name, mode, mtime, uid, gid);
    107 		else
    108 			extract(name, mode, mtime, uid, gid, bytes);
    109 	}
    110 	fprint(2, "premature end of archive\n");
    111 	exits("premature end of archive");
    112 }
    113 
    114 int
    115 fileprefix(char *prefix, char *s)
    116 {
    117 	while(*prefix)
    118 		if(*prefix++ != *s++)
    119 			return 0;
    120 	if(*s && *s != '/')
    121 		return 0;
    122 	return 1;
    123 }
    124 
    125 int
    126 selected(char *s, int argc, char *argv[])
    127 {
    128 	int i;
    129 
    130 	for(i=0; i<argc; i++)
    131 		if(fileprefix(argv[i], s))
    132 			return 1;
    133 	return 0;
    134 }
    135 
    136 void
    137 mkdirs(char *name, char *namep)
    138 {
    139 	char buf[2*LEN], *p;
    140 	int fd;
    141 
    142 	strcpy(buf, name);
    143 	for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
    144 		if(p[1] == '\0')
    145 			return;
    146 		*p = 0;
    147 		fd = create(buf, OREAD, 0775|DMDIR);
    148 		close(fd);
    149 		*p = '/';
    150 	}
    151 }
    152 
    153 void
    154 mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
    155 {
    156 	Dir *d, xd;
    157 	int fd;
    158 	char *p;
    159 	char olderr[256];
    160 
    161 	fd = create(name, OREAD, mode);
    162 	if(fd < 0){
    163 		rerrstr(olderr, sizeof(olderr));
    164 		if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
    165 			free(d);
    166 			warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
    167 			return;
    168 		}
    169 		free(d);
    170 	}
    171 	close(fd);
    172 
    173 	d = &xd;
    174 	nulldir(d);
    175 	p = utfrrune(name, L'/');
    176 	if(p)
    177 		p++;
    178 	else
    179 		p = name;
    180 	d->name = p;
    181 	if(uflag){
    182 		d->uid = uid;
    183 		d->gid = gid;
    184 	}
    185 	if(Tflag)
    186 		d->mtime = mtime;
    187 	d->mode = mode;
    188 	if(dirwstat(name, d) < 0)
    189 		warn("can't set modes for %q: %r", name);
    190 
    191 	if(uflag||Tflag){
    192 		if((d = dirstat(name)) == nil){
    193 			warn("can't reread modes for %q: %r", name);
    194 			return;
    195 		}
    196 		if(Tflag && d->mtime != mtime)
    197 			warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime);
    198 		if(uflag && strcmp(uid, d->uid))
    199 			warn("%q: uid mismatch %q %q", name, uid, d->uid);
    200 		if(uflag && strcmp(gid, d->gid))
    201 			warn("%q: gid mismatch %q %q", name, gid, d->gid);
    202 	}
    203 }
    204 
    205 void
    206 extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes)
    207 {
    208 	Dir d, *nd;
    209 	Biobuf *b;
    210 	char buf[LEN];
    211 	char *p;
    212 	ulong n;
    213 	uvlong tot;
    214 
    215 	if(vflag)
    216 		print("x %q %llud bytes\n", name, bytes);
    217 
    218 	b = Bopen(name, OWRITE);
    219 	if(!b){
    220 		warn("can't make file %q: %r", name);
    221 		seekpast(bytes);
    222 		return;
    223 	}
    224 	for(tot = 0; tot < bytes; tot += n){
    225 		n = sizeof buf;
    226 		if(tot + n > bytes)
    227 			n = bytes - tot;
    228 		n = Bread(&bin, buf, n);
    229 		if(n <= 0)
    230 			error("premature eof reading %q", name);
    231 		if(Bwrite(b, buf, n) != n)
    232 			warn("error writing %q: %r", name);
    233 	}
    234 
    235 	nulldir(&d);
    236 	p = utfrrune(name, '/');
    237 	if(p)
    238 		p++;
    239 	else
    240 		p = name;
    241 	d.name = p;
    242 	if(uflag){
    243 		d.uid = uid;
    244 		d.gid = gid;
    245 	}
    246 	if(Tflag)
    247 		d.mtime = mtime;
    248 	d.mode = mode;
    249 	Bflush(b);
    250 	if(dirfwstat(Bfildes(b), &d) < 0)
    251 		warn("can't set modes for %q: %r", name);
    252 	if(uflag||Tflag){
    253 		if((nd = dirfstat(Bfildes(b))) == nil)
    254 			warn("can't reread modes for %q: %r", name);
    255 		else{
    256 			if(Tflag && nd->mtime != mtime)
    257 				warn("%q: time mismatch %lud %lud\n",
    258 					name, mtime, nd->mtime);
    259 			if(uflag && strcmp(uid, nd->uid))
    260 				warn("%q: uid mismatch %q %q",
    261 					name, uid, nd->uid);
    262 			if(uflag && strcmp(gid, nd->gid))
    263 				warn("%q: gid mismatch %q %q",
    264 					name, gid, nd->gid);
    265 			free(nd);
    266 		}
    267 	}
    268 	Bterm(b);
    269 }
    270 
    271 void
    272 seekpast(uvlong bytes)
    273 {
    274 	char buf[LEN];
    275 	long n;
    276 	uvlong tot;
    277 
    278 	for(tot = 0; tot < bytes; tot += n){
    279 		n = sizeof buf;
    280 		if(tot + n > bytes)
    281 			n = bytes - tot;
    282 		n = Bread(&bin, buf, n);
    283 		if(n < 0)
    284 			error("premature eof");
    285 	}
    286 }
    287 
    288 void
    289 error(char *fmt, ...)
    290 {
    291 	char buf[1024];
    292 	va_list arg;
    293 
    294 	sprint(buf, "%q: ", argv0);
    295 	va_start(arg, fmt);
    296 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
    297 	va_end(arg);
    298 	fprint(2, "%s\n", buf);
    299 	exits(0);
    300 }
    301 
    302 void
    303 warn(char *fmt, ...)
    304 {
    305 	char buf[1024];
    306 	va_list arg;
    307 
    308 	sprint(buf, "%q: ", argv0);
    309 	va_start(arg, fmt);
    310 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
    311 	va_end(arg);
    312 	fprint(2, "%s\n", buf);
    313 }
    314 
    315 void
    316 usage(void)
    317 {
    318 	fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
    319 	exits("usage");
    320 }