plan9port

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

unvac.c (6517B)


      1 #include "stdinc.h"
      2 #include <fcall.h>	/* dirmodefmt */
      3 #include "vac.h"
      4 
      5 #ifndef PLAN9PORT
      6 #pragma varargck type "t" ulong
      7 #endif
      8 
      9 VacFs *fs;
     10 int tostdout;
     11 int diff;
     12 int nwant;
     13 char **want;
     14 int *found;
     15 int chatty;
     16 VtConn *conn;
     17 int errors;
     18 int settimes;
     19 int table;
     20 
     21 int mtimefmt(Fmt*);
     22 void unvac(VacFile*, char*, VacDir*);
     23 
     24 void
     25 usage(void)
     26 {
     27 	fprint(2, "usage: unvac [-TVcdtv] [-h host] file.vac [file ...]\n");
     28 	threadexitsall("usage");
     29 }
     30 
     31 struct
     32 {
     33 	vlong data;
     34 	vlong skipdata;
     35 } stats;
     36 
     37 void
     38 threadmain(int argc, char *argv[])
     39 {
     40 	int i, printstats;
     41 	char *host;
     42 	VacFile *f;
     43 
     44 	fmtinstall('H', encodefmt);
     45 	fmtinstall('V', vtscorefmt);
     46 	fmtinstall('F', vtfcallfmt);
     47 	fmtinstall('t', mtimefmt);
     48 	fmtinstall('M', dirmodefmt);
     49 
     50 	host = nil;
     51 	printstats = 0;
     52 
     53 	ARGBEGIN{
     54 	case 'T':
     55 		settimes = 1;
     56 		break;
     57 	case 'V':
     58 		chattyventi = 1;
     59 		break;
     60 	case 'c':
     61 		tostdout++;
     62 		break;
     63 	case 'd':
     64 		diff++;
     65 		break;
     66 	case 'h':
     67 		host = EARGF(usage());
     68 		break;
     69 	case 's':
     70 		printstats++;
     71 		break;
     72 	case 't':
     73 		table++;
     74 		break;
     75 	case 'v':
     76 		chatty++;
     77 		break;
     78 	default:
     79 		usage();
     80 	}ARGEND
     81 
     82 	if(argc < 1)
     83 		usage();
     84 
     85 	if(tostdout && diff){
     86 		fprint(2, "cannot use -c with -d\n");
     87 		usage();
     88 	}
     89 
     90 	conn = vtdial(host);
     91 	if(conn == nil)
     92 		sysfatal("could not connect to server: %r");
     93 
     94 	if(vtconnect(conn) < 0)
     95 		sysfatal("vtconnect: %r");
     96 
     97 	fs = vacfsopen(conn, argv[0], VtOREAD, 128<<20);
     98 	if(fs == nil)
     99 		sysfatal("vacfsopen: %r");
    100 
    101 	nwant = argc-1;
    102 	want = argv+1;
    103 	found = vtmallocz(nwant*sizeof found[0]);
    104 
    105 	if((f = vacfsgetroot(fs)) == nil)
    106 		sysfatal("vacfsgetroot: %r");
    107 
    108 	unvac(f, nil, nil);
    109 	for(i=0; i<nwant; i++){
    110 		if(want[i] && !found[i]){
    111 			fprint(2, "warning: didn't find %s\n", want[i]);
    112 			errors++;
    113 		}
    114 	}
    115 	if(errors)
    116 		threadexitsall("errors");
    117 	if(printstats)
    118 		fprint(2, "%lld bytes read, %lld bytes skipped\n",
    119 			stats.data, stats.skipdata);
    120 	threadexitsall(0);
    121 }
    122 
    123 int
    124 writen(int fd, char *buf, int n)
    125 {
    126 	int m;
    127 	int oldn;
    128 
    129 	oldn = n;
    130 	while(n > 0){
    131 		m = write(fd, buf, n);
    132 		if(m <= 0)
    133 			return -1;
    134 		buf += m;
    135 		n -= m;
    136 	}
    137 	return oldn;
    138 }
    139 
    140 int
    141 wantfile(char *name)
    142 {
    143 	int i, namelen, n;
    144 
    145 	if(nwant == 0)
    146 		return 1;
    147 
    148 	namelen = strlen(name);
    149 	for(i=0; i<nwant; i++){
    150 		if(want[i] == nil)
    151 			continue;
    152 		n = strlen(want[i]);
    153 		if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
    154 			return 1;
    155 		if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, namelen) == 0)
    156 			return 1;
    157 		if(n == namelen && memcmp(name, want[i], n) == 0){
    158 			found[i] = 1;
    159 			return 1;
    160 		}
    161 	}
    162 	return 0;
    163 }
    164 
    165 void
    166 unvac(VacFile *f, char *name, VacDir *vdir)
    167 {
    168 	static char buf[65536];
    169 	int fd, n, m,  bsize;
    170 	ulong mode, mode9;
    171 	char *newname;
    172 	char *what;
    173 	vlong off;
    174 	Dir d, *dp;
    175 	VacDirEnum *vde;
    176 	VacDir newvdir;
    177 	VacFile *newf;
    178 
    179 	if(vdir)
    180 		mode = vdir->mode;
    181 	else
    182 		mode = vacfilegetmode(f);
    183 
    184 	if(vdir){
    185 		if(table){
    186 			if(chatty){
    187 				mode9 = vdir->mode&0777;
    188 				if(mode&ModeDir)
    189 					mode9 |= DMDIR;
    190 				if(mode&ModeAppend)
    191 					mode9 |= DMAPPEND;
    192 				if(mode&ModeExclusive)
    193 					mode9 |= DMEXCL;
    194 #ifdef PLAN9PORT
    195 				if(mode&ModeLink)
    196 					mode9 |= DMSYMLINK;
    197 				if(mode&ModeNamedPipe)
    198 					mode9 |= DMNAMEDPIPE;
    199 				if(mode&ModeSetUid)
    200 					mode9 |= DMSETUID;
    201 				if(mode&ModeSetGid)
    202 					mode9 |= DMSETGID;
    203 				if(mode&ModeDevice)
    204 					mode9 |= DMDEVICE;
    205 #endif
    206 				print("%M %-10s %-10s %11lld %t %s\n",
    207 					mode9, vdir->uid, vdir->gid, vdir->size,
    208 					vdir->mtime, name);
    209 			}else
    210 				print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
    211 		}
    212 		else if(chatty)
    213 			fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
    214 	}
    215 
    216 	if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
    217 		if(table)
    218 			return;
    219 		if(mode&ModeDevice)
    220 			what = "device";
    221 		else if(mode&ModeLink)
    222 			what = "link";
    223 		else if(mode&ModeNamedPipe)
    224 			what = "named pipe";
    225 		else if(mode&ModeExclusive)
    226 			what = "lock";
    227 		else
    228 			what = "unknown type of file";
    229 		fprint(2, "warning: ignoring %s %s\n", what, name);
    230 		return;
    231 	}
    232 
    233 	if(mode&ModeDir){
    234 		if((vde = vdeopen(f)) == nil){
    235 			fprint(2, "vdeopen %s: %r", name);
    236 			errors++;
    237 			return;
    238 		}
    239 		if(!table && !tostdout && vdir){
    240 			// create directory
    241 			if((dp = dirstat(name)) == nil){
    242 				if((fd = create(name, OREAD, DMDIR|0700|(mode&0777))) < 0){
    243 					fprint(2, "mkdir %s: %r\n", name);
    244 					vdeclose(vde);
    245 				}
    246 				close(fd);
    247 			}else{
    248 				if(!(dp->mode&DMDIR)){
    249 					fprint(2, "%s already exists and is not a directory\n", name);
    250 					errors++;
    251 					free(dp);
    252 					vdeclose(vde);
    253 					return;
    254 				}
    255 				free(dp);
    256 			}
    257 		}
    258 		while(vderead(vde, &newvdir) > 0){
    259 			if(name == nil)
    260 				newname = newvdir.elem;
    261 			else
    262 				newname = smprint("%s/%s", name, newvdir.elem);
    263 			if(wantfile(newname)){
    264 				if((newf = vacfilewalk(f, newvdir.elem)) == nil){
    265 					fprint(2, "walk %s: %r\n", name);
    266 					errors++;
    267 				}else if(newf == f){
    268 					fprint(2, "walk loop: %s\n", newname);
    269 					vacfiledecref(newf);
    270 				}else{
    271 					unvac(newf, newname, &newvdir);
    272 					vacfiledecref(newf);
    273 				}
    274 			}
    275 			if(newname != newvdir.elem)
    276 				free(newname);
    277 			vdcleanup(&newvdir);
    278 		}
    279 		vdeclose(vde);
    280 	}else{
    281 		if(!table){
    282 			off = 0;
    283 			if(tostdout)
    284 				fd = dup(1, -1);
    285 			else if(diff && (fd = open(name, ORDWR)) >= 0){
    286 				bsize = vacfiledsize(f);
    287 				while((n = readn(fd, buf, bsize)) > 0){
    288 					if(sha1matches(f, off/bsize, (uchar*)buf, n)){
    289 						off += n;
    290 						stats.skipdata += n;
    291 						continue;
    292 					}
    293 					seek(fd, off, 0);
    294 					if((m = vacfileread(f, buf, n, off)) < 0)
    295 						break;
    296 					if(writen(fd, buf, m) != m){
    297 						fprint(2, "write %s: %r\n", name);
    298 						goto Err;
    299 					}
    300 					off += m;
    301 					stats.data += m;
    302 					if(m < n){
    303 						nulldir(&d);
    304 						d.length = off;
    305 						if(dirfwstat(fd, &d) < 0){
    306 							fprint(2, "dirfwstat %s: %r\n", name);
    307 							goto Err;
    308 						}
    309 						break;
    310 					}
    311 				}
    312 			}
    313 			else if((fd = create(name, OWRITE, mode&0777)) < 0){
    314 				fprint(2, "create %s: %r\n", name);
    315 				errors++;
    316 				return;
    317 			}
    318 			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
    319 				if(writen(fd, buf, n) != n){
    320 					fprint(2, "write %s: %r\n", name);
    321 				Err:
    322 					errors++;
    323 					close(fd);
    324 					remove(name);
    325 					return;
    326 				}
    327 				off += n;
    328 				stats.data += n;
    329 			}
    330 			close(fd);
    331 		}
    332 	}
    333 	if(vdir && settimes && !tostdout){
    334 		nulldir(&d);
    335 		d.mtime = vdir->mtime;
    336 		if(dirwstat(name, &d) < 0)
    337 			fprint(2, "warning: setting mtime on %s: %r", name);
    338 	}
    339 }
    340 
    341 int
    342 mtimefmt(Fmt *f)
    343 {
    344 	Tm *tm;
    345 
    346 	tm = localtime(va_arg(f->args, ulong));
    347 	fmtprint(f, "%04d-%02d-%02d %02d:%02d",
    348 		tm->year+1900, tm->mon+1, tm->mday,
    349 		tm->hour, tm->min);
    350 	return 0;
    351 }