Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * To understand this code, see Rock Ridge Interchange Protocol
3
 * standard 1.12 and System Use Sharing Protocol version 1.12
4
 * (search for rrip112.ps and susp112.ps on the web).
5
 *
6
 * Even better, go read something else.
7
 */
8
 
9
#include <u.h>
10
#include <libc.h>
11
#include <bio.h>
12
#include <libsec.h>
13
#include "iso9660.h"
14
 
15
static long mode(Direc*, int);
16
static long nlink(Direc*);
17
static ulong suspdirflags(Direc*, int);
18
static ulong CputsuspCE(Cdimg *cd, vlong offset);
19
static int CputsuspER(Cdimg*, int);
20
static int CputsuspRR(Cdimg*, int, int);
21
static int CputsuspSP(Cdimg*, int);
22
//static int CputsuspST(Cdimg*, int);
23
static int Cputrripname(Cdimg*, char*, int, char*, int);
24
static int CputrripSL(Cdimg*, int, int, char*, int);
25
static int CputrripPX(Cdimg*, Direc*, int, int);
26
static int CputrripTF(Cdimg*, Direc*, int, int);
27
 
28
/*
29
 * Patch the length field in a CE record.
30
 */
31
static void
32
setcelen(Cdimg *cd, vlong woffset, ulong len)
33
{
34
	vlong o;
35
 
36
	o = Cwoffset(cd);
37
	Cwseek(cd, woffset);
38
	Cputn(cd, len, 4);
39
	Cwseek(cd, o);
40
}
41
 
42
/*
43
 * Rock Ridge data is put into little blockettes, which can be
44
 * at most 256 bytes including a one-byte length.  Some number
45
 * of blockettes get packed together into a normal 2048-byte block.
46
 * Blockettes cannot cross block boundaries. 
47
 *
48
 * A Cbuf is a blockette buffer.  Len contains 
49
 * the length of the buffer written so far, and we can
50
 * write up to 254-28.  
51
 *
52
 * We only have one active Cbuf at a time; cdimg.rrcontin is the byte
53
 * offset of the beginning of that Cbuf.
54
 *
55
 * The blockette can be at most 255 bytes.  The last 28
56
 * will be (in the worst case) a CE record pointing at
57
 * a new blockette.  If we do write 255 bytes though,
58
 * we'll try to pad it out to be even, and overflow.
59
 * So the maximum is 254-28.
60
 *
61
 * Ceoffset contains the offset to be used with setcelen
62
 * to patch the CE pointing at the Cbuf once we know how
63
 * long the Cbuf is.
64
 */
65
typedef struct Cbuf Cbuf;
66
struct Cbuf {
67
	int	len;		/* written so far, of 254-28 */
68
	uvlong	ceoffset;
69
};
70
 
71
static int
72
freespace(Cbuf *cp)
73
{
74
	return (254-28) - cp->len;
75
}
76
 
77
static Cbuf*
78
ensurespace(Cdimg *cd, int n, Cbuf *co, Cbuf *cn, int dowrite)
79
{
80
	uvlong end;
81
 
82
	if(co->len+n <= 254-28) {
83
		co->len += n;
84
		return co;
85
	}
86
 
87
	co->len += 28;
88
	assert(co->len <= 254);
89
 
90
	if(dowrite == 0) {
91
		cn->len = n;
92
		return cn;
93
	}
94
 
95
	/*
96
	 * the current blockette is full; update cd->rrcontin and then
97
 	 * write a CE record to finish it.  Unfortunately we need to 
98
	 * figure out which block will be next before we write the CE.
99
	 */
100
	end = Cwoffset(cd)+28;
101
 
102
	/*
103
	 * if we're in a continuation blockette, update rrcontin.
104
	 * also, write our length into the field of the CE record
105
	 * that points at us.
106
	 */
107
	if(cd->rrcontin+co->len == end) {
108
		assert(cd->rrcontin != 0);
109
		assert(co == cn);
110
		cd->rrcontin += co->len;
111
		setcelen(cd, co->ceoffset, co->len);
112
	} else
113
		assert(co != cn);
114
 
115
	/*
116
	 * if the current continuation block can't fit another
117
	 * blockette, then start a new continuation block.
118
	 * rrcontin = 0 (mod Blocksize) means we just finished
119
	 * one, not that we've just started one.
120
	 */
121
	if(cd->rrcontin%Blocksize == 0
122
	|| cd->rrcontin/Blocksize != (cd->rrcontin+256)/Blocksize) {
123
		cd->rrcontin = (vlong)cd->nextblock * Blocksize;
124
		cd->nextblock++;
125
	}
126
 
127
	cn->ceoffset = CputsuspCE(cd, cd->rrcontin);
128
 
129
	assert(Cwoffset(cd) == end);
130
 
131
	cn->len = n;
132
	Cwseek(cd, cd->rrcontin);
133
	assert(cd->rrcontin != 0);
134
 
135
	return cn;
136
}
137
 
138
/*
139
 * Put down the name, but we might need to break it
140
 * into chunks so that each chunk fits in 254-28-5 bytes.
141
 * What a crock.
142
 *
143
 * The new Plan 9 format uses strings of this form too, 
144
 * since they're already there.
145
 */
146
Cbuf*
147
Cputstring(Cdimg *cd, Cbuf *cp, Cbuf *cn, char *nm, char *p, int flags, int dowrite)
148
{
149
	char buf[256], *q;
150
	int free;
151
 
152
	for(; p[0] != '\0'; p = q) {
153
		cp = ensurespace(cd, 5+1, cp, cn, dowrite);
154
		cp->len -= 5+1;
155
		free = freespace(cp);
156
		assert(5+1 <= free && free < 256);
157
 
158
		strncpy(buf, p, free-5);
159
		buf[free-5] = '\0';
160
		q = p+strlen(buf);
161
		p = buf;
162
 
163
		ensurespace(cd, 5+strlen(p), cp, nil, dowrite);	/* nil: better not use this. */
164
		Cputrripname(cd, nm, flags | (q[0] ? NMcontinue : 0), p, dowrite);
165
	}
166
	return cp;
167
}
168
 
169
/*
170
 * Write a Rock Ridge SUSP set of records for a directory entry.
171
 */
172
int
173
Cputsysuse(Cdimg *cd, Direc *d, int dot, int dowrite, int initlen)
174
{
175
	char buf[256], buf0[256], *nextpath, *p, *path, *q;
176
	int flags, free, m, what;
177
	uvlong o;
178
	Cbuf cn, co, *cp;
179
 
180
	assert(cd != nil);
181
	assert((initlen&1) == 0);
182
 
183
	if(dot == DTroot)
184
		return 0;
185
 
186
	co.len = initlen;
187
 
188
	o = Cwoffset(cd);
189
 
190
	assert(dowrite==0 || Cwoffset(cd) == o+co.len-initlen);
191
	cp = &co;
192
 
193
	if (dot == DTrootdot) {
194
		m = CputsuspSP(cd, 0);
195
		cp = ensurespace(cd, m, cp, &cn, dowrite);
196
		CputsuspSP(cd, dowrite);
197
 
198
		m = CputsuspER(cd, 0);
199
		cp = ensurespace(cd, m, cp, &cn, dowrite);
200
		CputsuspER(cd, dowrite);
201
	}
202
 
203
	/*
204
	 * In a perfect world, we'd be able to omit the NM
205
	 * entries when our name was all lowercase and conformant,
206
	 * but OpenBSD insists on uppercasing (really, not lowercasing)
207
	 * the ISO9660 names.
208
	 */
209
	what = RR_PX | RR_TF | RR_NM;
210
	if(d != nil && (d->mode & CHLINK))
211
		what |= RR_SL;
212
 
213
	m = CputsuspRR(cd, what, 0);
214
	cp = ensurespace(cd, m, cp, &cn, dowrite);	
215
	CputsuspRR(cd, what, dowrite);
216
 
217
	if(what & RR_PX) {
218
		m = CputrripPX(cd, d, dot, 0);
219
		cp = ensurespace(cd, m, cp, &cn, dowrite);
220
		CputrripPX(cd, d, dot, dowrite);
221
	}
222
 
223
	if(what & RR_NM) {
224
		if(dot == DTiden)
225
			p = d->name;
226
		else if(dot == DTdotdot)
227
			p = "..";
228
		else
229
			p = ".";
230
 
231
		flags = suspdirflags(d, dot);
232
		assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
233
		cp = Cputstring(cd, cp, &cn, "NM", p, flags, dowrite);
234
	}
235
 
236
	/*
237
	 * Put down the symbolic link.  This is even more of a crock.
238
	 * Not only are the individual elements potentially split, 
239
	 * but the whole path itself can be split across SL blocks.
240
	 * To keep the code simple as possible (really), we write
241
	 * only one element per SL block, wasting 6 bytes per element.
242
	 */
243
	if(what & RR_SL) {
244
		for(path=d->symlink; path[0] != '\0'; path=nextpath) {
245
			/* break off one component */
246
			if((nextpath = strchr(path, '/')) == nil)
247
				nextpath = path+strlen(path);
248
			strncpy(buf0, path, nextpath-path);
249
			buf0[nextpath-path] = '\0';
250
			if(nextpath[0] == '/')
251
				nextpath++;
252
			p = buf0;
253
 
254
			/* write the name, perhaps broken into pieces */
255
			if(strcmp(p, "") == 0)
256
				flags = NMroot;
257
			else if(strcmp(p, ".") == 0)
258
				flags = NMcurrent;
259
			else if(strcmp(p, "..") == 0)
260
				flags = NMparent;
261
			else
262
				flags = 0;
263
 
264
			/* the do-while handles the empty string properly */
265
			do {
266
				/* must have room for at least 1 byte of name */
267
				cp = ensurespace(cd, 7+1, cp, &cn, dowrite);
268
				cp->len -= 7+1;
269
				free = freespace(cp);
270
				assert(7+1 <= free && free < 256);
271
 
272
				strncpy(buf, p, free-7);
273
				buf[free-7] = '\0';
274
				q = p+strlen(buf);
275
				p = buf;
276
 
277
				/* nil: better not need to expand */
278
				assert(7+strlen(p) <= free);
279
				ensurespace(cd, 7+strlen(p), cp, nil, dowrite);
280
				CputrripSL(cd, nextpath[0], flags | (q[0] ? NMcontinue : 0), p, dowrite);
281
				p = q;
282
			} while(p[0] != '\0');
283
		}
284
	}
285
 
286
	assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
287
 
288
	if(what & RR_TF) {
289
		m = CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, 0);
290
		cp = ensurespace(cd, m, cp, &cn, dowrite);
291
		CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, dowrite);
292
	}
293
	assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
294
 
295
	if(cp == &cn && dowrite) {
296
		/* seek out of continuation, but mark our place */
297
		cd->rrcontin = Cwoffset(cd);
298
		setcelen(cd, cn.ceoffset, cn.len);
299
		Cwseek(cd, o+co.len-initlen);
300
	}
301
 
302
	if(co.len & 1) {
303
		co.len++;
304
		if(dowrite)
305
			Cputc(cd, 0);
306
	}
307
 
308
	if(dowrite) {
309
		if(Cwoffset(cd) != o+co.len-initlen)
310
			fprint(2, "offset %llud o+co.len-initlen %llud\n",
311
				Cwoffset(cd), o+co.len-initlen);
312
		assert(Cwoffset(cd) == o+co.len-initlen);
313
	} else
314
		assert(Cwoffset(cd) == o);
315
 
316
	assert(co.len <= 255);
317
	return co.len - initlen;
318
}
319
 
320
static char SUSPrrip[10] = "RRIP_1991A";
321
static char SUSPdesc[84] = "RRIP <more garbage here>";
322
static char SUSPsrc[135] = "RRIP <more garbage here>";
323
 
324
static ulong
325
CputsuspCE(Cdimg *cd, vlong offset)
326
{
327
	vlong o, x;
328
 
329
	chat("writing SUSP CE record pointing to %ld, %ld\n",
330
		offset/Blocksize, offset%Blocksize);
331
	o = Cwoffset(cd);
332
	Cputc(cd, 'C');
333
	Cputc(cd, 'E');
334
	Cputc(cd, 28);
335
	Cputc(cd, 1);
336
	Cputn(cd, offset/Blocksize, 4);
337
	Cputn(cd, offset%Blocksize, 4);
338
	x = Cwoffset(cd);
339
	Cputn(cd, 0, 4);
340
	assert(Cwoffset(cd) == o+28);
341
 
342
	return x;
343
}
344
 
345
static int
346
CputsuspER(Cdimg *cd, int dowrite)
347
{
348
	assert(cd != nil);
349
 
350
	if(dowrite) {
351
		chat("writing SUSP ER record\n");
352
		Cputc(cd, 'E');           /* ER field marker */
353
		Cputc(cd, 'R');
354
		Cputc(cd, 26);            /* Length          */
355
		Cputc(cd, 1);             /* Version         */
356
		Cputc(cd, 10);            /* LEN_ID          */
357
		Cputc(cd, 4);             /* LEN_DESC        */
358
		Cputc(cd, 4);             /* LEN_SRC         */
359
		Cputc(cd, 1);             /* EXT_VER         */
360
		Cputs(cd, SUSPrrip, 10);  /* EXT_ID          */
361
		Cputs(cd, SUSPdesc, 4);   /* EXT_DESC        */
362
		Cputs(cd, SUSPsrc, 4);    /* EXT_SRC         */
363
	}
364
	return 8+10+4+4;
365
}
366
 
367
static int
368
CputsuspRR(Cdimg *cd, int what, int dowrite)
369
{
370
	assert(cd != nil);
371
 
372
	if(dowrite) {
373
		Cputc(cd, 'R');           /* RR field marker */
374
		Cputc(cd, 'R');
375
		Cputc(cd, 5);             /* Length          */
376
		Cputc(cd, 1);		  /* Version number  */
377
		Cputc(cd, what);          /* Flags           */
378
	}
379
	return 5;
380
}
381
 
382
static int
383
CputsuspSP(Cdimg *cd, int dowrite)
384
{
385
	assert(cd!=0);
386
 
387
	if(dowrite) { 
388
chat("writing SUSP SP record\n");
389
		Cputc(cd, 'S');           /* SP field marker */
390
		Cputc(cd, 'P');
391
		Cputc(cd, 7);             /* Length          */
392
		Cputc(cd, 1);             /* Version         */
393
		Cputc(cd, 0xBE);          /* Magic           */
394
		Cputc(cd, 0xEF);
395
		Cputc(cd, 0);
396
	}
397
 
398
	return 7;
399
}
400
 
401
#ifdef NOTUSED
402
static int
403
CputsuspST(Cdimg *cd, int dowrite)
404
{
405
	assert(cd!=0);
406
 
407
	if(dowrite) {
408
		Cputc(cd, 'S');           /* ST field marker */
409
		Cputc(cd, 'T');
410
		Cputc(cd, 4);             /* Length          */
411
		Cputc(cd, 1);             /* Version         */	
412
	}
413
	return 4;
414
}
415
#endif
416
 
417
static ulong
418
suspdirflags(Direc *d, int dot)
419
{
420
	uchar flags;
421
 
422
	USED(d);
423
	flags = 0;
424
	switch(dot) {
425
	default:
426
		assert(0);
427
	case DTdot:
428
	case DTrootdot:
429
		flags |= NMcurrent;
430
		break;
431
	case DTdotdot:
432
		flags |= NMparent;
433
		break;
434
	case DTroot:
435
		flags |= NMvolroot;
436
		break;
437
	case DTiden:
438
		break;
439
	}
440
	return flags;
441
}
442
 
443
static int
444
Cputrripname(Cdimg *cd, char *nm, int flags, char *name, int dowrite)
445
{
446
	int l;
447
 
448
	l = strlen(name);
449
	if(dowrite) {
450
		Cputc(cd, nm[0]);                   /* NM field marker */
451
		Cputc(cd, nm[1]);
452
		Cputc(cd, l+5);        /* Length          */
453
		Cputc(cd, 1);                     /* Version         */
454
		Cputc(cd, flags);                 /* Flags           */
455
		Cputs(cd, name, l);    /* Alternate name  */
456
	}
457
	return 5+l;
458
}
459
 
460
static int
461
CputrripSL(Cdimg *cd, int contin, int flags, char *name, int dowrite)
462
{
463
	int l;
464
 
465
	l = strlen(name);
466
	if(dowrite) {
467
		Cputc(cd, 'S');
468
		Cputc(cd, 'L');
469
		Cputc(cd, l+7);
470
		Cputc(cd, 1);
471
		Cputc(cd, contin ? 1 : 0);
472
		Cputc(cd, flags);
473
		Cputc(cd, l);
474
		Cputs(cd, name, l);
475
	}
476
	return 7+l;
477
}
478
 
479
static int
480
CputrripPX(Cdimg *cd, Direc *d, int dot, int dowrite)
481
{
482
	assert(cd!=0);
483
 
484
	if(dowrite) {
485
		Cputc(cd, 'P');             /* PX field marker */
486
		Cputc(cd, 'X');
487
		Cputc(cd, 36);              /* Length          */
488
		Cputc(cd, 1);               /* Version         */
489
 
490
		Cputn(cd, mode(d, dot), 4); /* POSIX File mode */
491
		Cputn(cd, nlink(d), 4);     /* POSIX st_nlink  */
492
		Cputn(cd, d?d->uidno:0, 4);  /* POSIX st_uid    */
493
		Cputn(cd, d?d->gidno:0, 4);  /* POSIX st_gid    */
494
	}
495
 
496
	return 36;
497
}
498
 
499
static int
500
CputrripTF(Cdimg *cd, Direc *d, int type, int dowrite)
501
{
502
	int i, length;
503
 
504
	assert(cd!=0);
505
	assert(!(type & TFlongform));
506
 
507
	length = 0;
508
	for(i=0; i<7; i++)
509
		if (type & (1<<i))
510
			length++;
511
	assert(length == 4);
512
 
513
	if(dowrite) {
514
		Cputc(cd, 'T');				/* TF field marker */
515
		Cputc(cd, 'F');
516
		Cputc(cd, 5+7*length);		/* Length		 */
517
		Cputc(cd, 1);				/* Version		 */
518
		Cputc(cd, type);					/* Flags (types)	 */
519
 
520
		if (type & TFcreation)
521
			Cputdate(cd, d?d->ctime:0);
522
		if (type & TFmodify)
523
			Cputdate(cd, d?d->mtime:0);
524
		if (type & TFaccess)
525
			Cputdate(cd, d?d->atime:0);
526
		if (type & TFattributes)
527
			Cputdate(cd, d?d->ctime:0);
528
 
529
	//	if (type & TFbackup)
530
	//		Cputdate(cd, 0);
531
	//	if (type & TFexpiration)
532
	//		Cputdate(cd, 0);
533
	//	if (type & TFeffective)
534
	//		Cputdate(cd, 0);
535
	}
536
	return 5+7*length;
537
}
538
 
539
 
540
#define NONPXMODES  (DMDIR | DMAPPEND | DMEXCL | DMMOUNT)
541
#define POSIXMODEMASK (0177777)
542
#ifndef S_IFMT
543
#define S_IFMT  (0170000)
544
#endif
545
#ifndef S_IFDIR
546
#define S_IFDIR (0040000)
547
#endif
548
#ifndef S_IFREG
549
#define S_IFREG (0100000)
550
#endif
551
#ifndef S_IFLNK
552
#define S_IFLNK (0120000)
553
#endif
554
#undef  ISTYPE
555
#define ISTYPE(mode, mask)  (((mode) & S_IFMT) == (mask))
556
#ifndef S_ISDIR
557
#define S_ISDIR(mode) ISTYPE(mode, S_IFDIR)
558
#endif
559
#ifndef S_ISREG
560
#define S_ISREG(mode) ISTYPE(mode, S_IREG)
561
#endif
562
#ifndef S_ISLNK
563
#define S_ISLNK(mode) ISTYPE(mode, S_ILNK)
564
#endif
565
 
566
 
567
static long
568
mode(Direc *d, int dot)
569
{
570
	long mode;
571
 
572
	if (!d)
573
		return 0;
574
 
575
	if ((dot != DTroot) && (dot != DTrootdot)) {
576
		mode = (d->mode & ~(NONPXMODES));
577
		if (d->mode & DMDIR)
578
			mode |= S_IFDIR;
579
		else if (d->mode & CHLINK)
580
			mode |= S_IFLNK;
581
		else
582
			mode |= S_IFREG;
583
	} else
584
		mode = S_IFDIR | (0755);
585
 
586
	mode &= POSIXMODEMASK;
587
 
588
	/* Botch: not all POSIX types supported yet */
589
	assert(mode & (S_IFDIR|S_IFREG));
590
 
591
chat("writing PX record mode field %ulo with dot %d and name \"%s\"\n", mode, dot, d->name); 
592
 
593
	return mode;		
594
}
595
 
596
static long
597
nlink(Direc *d)   /* Trump up the nlink field for POSIX compliance */
598
{
599
	int i;
600
	long n;
601
 
602
	if (!d)
603
		return 0;
604
 
605
	n = 1;
606
	if (d->mode & DMDIR)   /* One for "." and one more for ".." */
607
		n++;
608
 
609
	for(i=0; i<d->nchild; i++)
610
		if (d->child[i].mode & DMDIR)
611
			n++;
612
 
613
	return n;
614
}
615