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

write.c (8762B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include <libsec.h>
      5 
      6 #include "iso9660.h"
      7 
      8 static void
      9 writelittlebig4(uchar *buf, ulong x)
     10 {
     11 	buf[0] = buf[7] = x;
     12 	buf[1] = buf[6] = x>>8;
     13 	buf[2] = buf[5] = x>>16;
     14 	buf[3] = buf[4] = x>>24;
     15 }
     16 
     17 void
     18 rewritedot(Cdimg *cd, Direc *d)
     19 {
     20 	uchar buf[Blocksize];
     21 	Cdir *c;
     22 
     23 	Creadblock(cd, buf, d->block, Blocksize);
     24 	c = (Cdir*)buf;
     25 	assert(c->len != 0);
     26 	assert(c->namelen == 1 && c->name[0] == '\0');	/* dot */
     27 	writelittlebig4(c->dloc, d->block);
     28 	writelittlebig4(c->dlen, d->length);
     29 
     30 	Cwseek(cd, d->block*Blocksize);
     31 	Cwrite(cd, buf, Blocksize);
     32 }
     33 
     34 void
     35 rewritedotdot(Cdimg *cd, Direc *d, Direc *dparent)
     36 {
     37 	uchar buf[Blocksize];
     38 	Cdir *c;
     39 
     40 	Creadblock(cd, buf, d->block, Blocksize);
     41 	c = (Cdir*)buf;
     42 	assert(c->len != 0);
     43 	assert(c->namelen == 1 && c->name[0] == '\0');	/* dot */
     44 
     45 	c = (Cdir*)(buf+c->len);
     46 	assert(c->len != 0);
     47 	assert(c->namelen == 1 && c->name[0] == '\001');	/* dotdot*/
     48 
     49 	writelittlebig4(c->dloc, dparent->block);
     50 	writelittlebig4(c->dlen, dparent->length);
     51 
     52 	Cwseek(cd, d->block*Blocksize);
     53 	Cwrite(cd, buf, Blocksize);
     54 }
     55 
     56 /*
     57  * Write each non-directory file.  We copy the file to
     58  * the cd image, and then if it turns out that we've
     59  * seen this stream of bits before, we push the next block
     60  * pointer back.  This ensures consistency between the MD5s
     61  * and the data on the CD image.  MD5 summing on one pass
     62  * and copying on another would not ensure this.
     63  */
     64 void
     65 writefiles(Dump *d, Cdimg *cd, Direc *direc)
     66 {
     67 	int i;
     68 	uchar buf[8192], digest[MD5dlen];
     69 	ulong length, n, start;
     70 	Biobuf *b;
     71 	DigestState *s;
     72 	Dumpdir *dd;
     73 
     74 	if(direc->mode & DMDIR) {
     75 		for(i=0; i<direc->nchild; i++)
     76 			writefiles(d, cd, &direc->child[i]);
     77 		return;
     78 	}
     79 
     80 	assert(direc->block == 0);
     81 
     82 	if((b = Bopen(direc->srcfile, OREAD)) == nil){
     83 		fprint(2, "warning: cannot open '%s': %r\n", direc->srcfile);
     84 		direc->block = 0;
     85 		direc->length = 0;
     86 		return;
     87 	}
     88 
     89 	start = cd->nextblock;
     90 	assert(start != 0);
     91 
     92 	Cwseek(cd, start*Blocksize);
     93 
     94 	s = md5(nil, 0, nil, nil);
     95 	length = 0;
     96 	while((n = Bread(b, buf, sizeof buf)) > 0) {
     97 		md5(buf, n, nil, s);
     98 		Cwrite(cd, buf, n);
     99 		length += n;
    100 	}
    101 	md5(nil, 0, digest, s);
    102 	Bterm(b);
    103 	Cpadblock(cd);
    104 
    105 	if(length != direc->length) {
    106 		fprint(2, "warning: %s changed size underfoot\n", direc->srcfile);
    107 		direc->length = length;
    108 	}
    109 
    110 	if(length == 0)
    111 		direc->block = 0;
    112 	else if((dd = lookupmd5(d, digest))) {
    113 		assert(dd->length == length);
    114 		assert(dd->block != 0);
    115 		direc->block = dd->block;
    116 		cd->nextblock = start;
    117 	} else {
    118 		direc->block = start;
    119 		if(chatty > 1)
    120 			fprint(2, "lookup %.16H %lud (%s) failed\n", digest, length, direc->name);
    121 		insertmd5(d, atom(direc->name), digest, start, length);
    122 	}
    123 }
    124 
    125 /*
    126  * Write a directory tree.  We work from the leaves,
    127  * and patch the dotdot pointers afterward.
    128  */
    129 static void
    130 _writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
    131 {
    132 	int i, l, ll;
    133 	ulong start, next;
    134 
    135 	if((d->mode & DMDIR) == 0)
    136 		return;
    137 
    138 	if(chatty)
    139 		fprint(2, "%*s%s\n", 4*level, "", d->name);
    140 
    141 	for(i=0; i<d->nchild; i++)
    142 		_writedirs(cd, &d->child[i], put, level+1);
    143 
    144 	l = 0;
    145 	l += put(cd, d, (level == 0) ? DTrootdot : DTdot, 0, l);
    146 	l += put(cd, nil, DTdotdot, 0, l);
    147 	for(i=0; i<d->nchild; i++)
    148 		l += put(cd, &d->child[i], DTiden, 0, l);
    149 
    150 	start = cd->nextblock;
    151 	cd->nextblock += (l+Blocksize-1)/Blocksize;
    152 	next = cd->nextblock;
    153 
    154 	Cwseek(cd, start*Blocksize);
    155 	ll = 0;
    156 	ll += put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, ll);
    157 	ll += put(cd, nil, DTdotdot, 1, ll);
    158 	for(i=0; i<d->nchild; i++)
    159 		ll += put(cd, &d->child[i], DTiden, 1, ll);
    160 	assert(ll == l);
    161 	Cpadblock(cd);
    162 	assert(Cwoffset(cd) == next*Blocksize);
    163 
    164 	d->block = start;
    165 	d->length = (next - start) * Blocksize;
    166 	rewritedot(cd, d);
    167 	rewritedotdot(cd, d, d);
    168 
    169 	for(i=0; i<d->nchild; i++)
    170 		if(d->child[i].mode & DMDIR)
    171 			rewritedotdot(cd, &d->child[i], d);
    172 }
    173 
    174 void
    175 writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
    176 {
    177 	/*
    178 	 * If we're writing a mk9660 image, then the root really
    179 	 * is the root, so start at level 0.  If we're writing a dump image,
    180 	 * then the "root" is really going to be two levels down once
    181 	 * we patch in the dump hierarchy above it, so start at level non-zero.
    182 	 */
    183 	if(chatty)
    184 		fprint(2, ">>> writedirs\n");
    185 	_writedirs(cd, d, put, mk9660 ? 0 : 1);
    186 }
    187 
    188 
    189 /*
    190  * Write the dump tree.  This is like writedirs but once we get to
    191  * the roots of the individual days we just patch the parent dotdot blocks.
    192  */
    193 static void
    194 _writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
    195 {
    196 	int i;
    197 	ulong start;
    198 
    199 	switch(level) {
    200 	case 0:
    201 		/* write root, list of years, also conform.map */
    202 		for(i=0; i<d->nchild; i++)
    203 			if(d->child[i].mode & DMDIR)
    204 				_writedumpdirs(cd, &d->child[i], put, level+1);
    205 		chat("write dump root dir at %lud\n", cd->nextblock);
    206 		goto Writedir;
    207 
    208 	case 1:	/* write year, list of days */
    209 		for(i=0; i<d->nchild; i++)
    210 			_writedumpdirs(cd, &d->child[i], put, level+1);
    211 		chat("write dump %s dir at %lud\n", d->name, cd->nextblock);
    212 		goto Writedir;
    213 
    214 	Writedir:
    215 		start = cd->nextblock;
    216 		Cwseek(cd, start*Blocksize);
    217 
    218 		put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, Cwoffset(cd));
    219 		put(cd, nil, DTdotdot, 1, Cwoffset(cd));
    220 		for(i=0; i<d->nchild; i++)
    221 			put(cd, &d->child[i], DTiden, 1, Cwoffset(cd));
    222 		Cpadblock(cd);
    223 
    224 		d->block = start;
    225 		d->length = (cd->nextblock - start) * Blocksize;
    226 
    227 		rewritedot(cd, d);
    228 		rewritedotdot(cd, d, d);
    229 
    230 		for(i=0; i<d->nchild; i++)
    231 			if(d->child[i].mode & DMDIR)
    232 				rewritedotdot(cd, &d->child[i], d);
    233 		break;
    234 
    235 	case 2:	/* write day: already written, do nothing */
    236 		break;
    237 
    238 	default:
    239 		assert(0);
    240 	}
    241 }
    242 
    243 void
    244 writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
    245 {
    246 	_writedumpdirs(cd, d, put, 0);
    247 }
    248 
    249 static int
    250 Cputplan9(Cdimg *cd, Direc *d, int dot, int dowrite)
    251 {
    252 	int l, n;
    253 
    254 	if(dot != DTiden)
    255 		return 0;
    256 
    257 	l = 0;
    258 	if(d->flags & Dbadname) {
    259 		n = strlen(d->name);
    260 		l += 1+n;
    261 		if(dowrite) {
    262 			Cputc(cd, n);
    263 			Cputs(cd, d->name, n);
    264 		}
    265 	} else {
    266 		l++;
    267 		if(dowrite)
    268 			Cputc(cd, 0);
    269 	}
    270 
    271 	n = strlen(d->uid);
    272 	l += 1+n;
    273 	if(dowrite) {
    274 		Cputc(cd, n);
    275 		Cputs(cd, d->uid, n);
    276 	}
    277 
    278 	n = strlen(d->gid);
    279 	l += 1+n;
    280 	if(dowrite) {
    281 		Cputc(cd, n);
    282 		Cputs(cd, d->gid, n);
    283 	}
    284 
    285 	if(l & 1) {
    286 		l++;
    287 		if(dowrite)
    288 			Cputc(cd, 0);
    289 	}
    290 	l += 8;
    291 	if(dowrite)
    292 		Cputn(cd, d->mode, 4);
    293 
    294 	return l;
    295 }
    296 
    297 /*
    298  * Write a directory entry.
    299  */
    300 static int
    301 genputdir(Cdimg *cd, Direc *d, int dot, int joliet, int dowrite, int offset)
    302 {
    303 	int f, n, l, lp;
    304 	long o;
    305 
    306 	f = 0;
    307 	if(dot != DTiden || (d->mode & DMDIR))
    308 		f |= 2;
    309 
    310 	n = 1;
    311 	if(dot == DTiden) {
    312 		if(joliet)
    313 			n = 2*utflen(d->confname);
    314 		else
    315 			n = strlen(d->confname);
    316 	}
    317 
    318 	l = 33+n;
    319 	if(l & 1)
    320 		l++;
    321 	assert(l <= 255);
    322 
    323 	if(joliet == 0) {
    324 		if(cd->flags & CDplan9)
    325 			l += Cputplan9(cd, d, dot, 0);
    326 		else if(cd->flags & CDrockridge)
    327 			l += Cputsysuse(cd, d, dot, 0, l);
    328 		assert(l <= 255);
    329 	}
    330 
    331 	if(dowrite == 0) {
    332 		if(Blocksize - offset%Blocksize < l)
    333 			l += Blocksize - offset%Blocksize;
    334 		return l;
    335 	}
    336 
    337 	assert(offset%Blocksize == Cwoffset(cd)%Blocksize);
    338 
    339 	o = Cwoffset(cd);
    340 	lp = 0;
    341 	if(Blocksize - Cwoffset(cd)%Blocksize < l) {
    342 		lp = Blocksize - Cwoffset(cd)%Blocksize;
    343 		Cpadblock(cd);
    344 	}
    345 
    346 	Cputc(cd, l);			/* length of directory record */
    347 	Cputc(cd, 0);			/* extended attribute record length */
    348 	if(d) {
    349 		if((d->mode & DMDIR) == 0)
    350 			assert(d->length == 0 || d->block >= 18);
    351 
    352 		Cputn(cd, d->block, 4);		/* location of extent */
    353 		Cputn(cd, d->length, 4);		/* data length */
    354 	} else {
    355 		Cputn(cd, 0, 4);
    356 		Cputn(cd, 0, 4);
    357 	}
    358 	Cputdate(cd, d ? d->mtime : now);		/* recorded date */
    359 	Cputc(cd, f);			/* file flags */
    360 	Cputc(cd, 0);			/* file unit size */
    361 	Cputc(cd, 0);			/* interleave gap size */
    362 	Cputn(cd, 1, 2);	       	/* volume sequence number */
    363 	Cputc(cd, n);			/* length of file identifier */
    364 
    365 	if(dot == DTiden) {		/* identifier */
    366 		if(joliet)
    367 			Cputrscvt(cd, d->confname, n);
    368 		else
    369 			Cputs(cd, d->confname, n);
    370 	}else
    371 	if(dot == DTdotdot)
    372 		Cputc(cd, 1);
    373 	else
    374 		Cputc(cd, 0);
    375 
    376 	if(Cwoffset(cd) & 1)			/* pad */
    377 		Cputc(cd, 0);
    378 
    379 	if(joliet == 0) {
    380 		if(cd->flags & CDplan9)
    381 			Cputplan9(cd, d, dot, 1);
    382 		else if(cd->flags & CDrockridge)
    383 			Cputsysuse(cd, d, dot, 1, Cwoffset(cd)-(o+lp));
    384 	}
    385 
    386 	assert(o+lp+l == Cwoffset(cd));
    387 	return lp+l;
    388 }
    389 
    390 int
    391 Cputisodir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
    392 {
    393 	return genputdir(cd, d, dot, 0, dowrite, offset);
    394 }
    395 
    396 int
    397 Cputjolietdir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
    398 {
    399 	return genputdir(cd, d, dot, 1, dowrite, offset);
    400 }
    401 
    402 void
    403 Cputendvd(Cdimg *cd)
    404 {
    405 	Cputc(cd, 255);				/* volume descriptor set terminator */
    406 	Cputs(cd, "CD001", 5);			/* standard identifier */
    407 	Cputc(cd, 1);				/* volume descriptor version */
    408 	Cpadblock(cd);
    409 }