xref: /plan9/sys/src/cmd/disk/9660/sysuse.c (revision 73ee67a1775bb9176ad6f77775e030678f092526)
180ee5cbfSDavid du Colombier /*
280ee5cbfSDavid du Colombier  * To understand this code, see Rock Ridge Interchange Protocol
380ee5cbfSDavid du Colombier  * standard 1.12 and System Use Sharing Protocol version 1.12
480ee5cbfSDavid du Colombier  * (search for rrip112.ps and susp112.ps on the web).
580ee5cbfSDavid du Colombier  *
680ee5cbfSDavid du Colombier  * Even better, go read something else.
780ee5cbfSDavid du Colombier  */
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier #include <u.h>
1080ee5cbfSDavid du Colombier #include <libc.h>
1180ee5cbfSDavid du Colombier #include <bio.h>
1280ee5cbfSDavid du Colombier #include <libsec.h>
1380ee5cbfSDavid du Colombier #include "iso9660.h"
1480ee5cbfSDavid du Colombier 
1580ee5cbfSDavid du Colombier static long mode(Direc*, int);
1680ee5cbfSDavid du Colombier static long nlink(Direc*);
1780ee5cbfSDavid du Colombier static ulong suspdirflags(Direc*, int);
18*73ee67a1SDavid du Colombier static ulong CputsuspCE(Cdimg *cd, vlong offset);
1980ee5cbfSDavid du Colombier static int CputsuspER(Cdimg*, int);
2080ee5cbfSDavid du Colombier static int CputsuspRR(Cdimg*, int, int);
2180ee5cbfSDavid du Colombier static int CputsuspSP(Cdimg*, int);
2280ee5cbfSDavid du Colombier //static int CputsuspST(Cdimg*, int);
2380ee5cbfSDavid du Colombier static int Cputrripname(Cdimg*, char*, int, char*, int);
2480ee5cbfSDavid du Colombier static int CputrripSL(Cdimg*, int, int, char*, int);
2580ee5cbfSDavid du Colombier static int CputrripPX(Cdimg*, Direc*, int, int);
2680ee5cbfSDavid du Colombier static int CputrripTF(Cdimg*, Direc*, int, int);
2780ee5cbfSDavid du Colombier 
2880ee5cbfSDavid du Colombier /*
2980ee5cbfSDavid du Colombier  * Patch the length field in a CE record.
3080ee5cbfSDavid du Colombier  */
3180ee5cbfSDavid du Colombier static void
setcelen(Cdimg * cd,vlong woffset,ulong len)32*73ee67a1SDavid du Colombier setcelen(Cdimg *cd, vlong woffset, ulong len)
3380ee5cbfSDavid du Colombier {
34*73ee67a1SDavid du Colombier 	vlong o;
3580ee5cbfSDavid du Colombier 
3680ee5cbfSDavid du Colombier 	o = Cwoffset(cd);
3780ee5cbfSDavid du Colombier 	Cwseek(cd, woffset);
3880ee5cbfSDavid du Colombier 	Cputn(cd, len, 4);
3980ee5cbfSDavid du Colombier 	Cwseek(cd, o);
4080ee5cbfSDavid du Colombier }
4180ee5cbfSDavid du Colombier 
4280ee5cbfSDavid du Colombier /*
4380ee5cbfSDavid du Colombier  * Rock Ridge data is put into little blockettes, which can be
4480ee5cbfSDavid du Colombier  * at most 256 bytes including a one-byte length.  Some number
4580ee5cbfSDavid du Colombier  * of blockettes get packed together into a normal 2048-byte block.
4680ee5cbfSDavid du Colombier  * Blockettes cannot cross block boundaries.
4780ee5cbfSDavid du Colombier  *
4880ee5cbfSDavid du Colombier  * A Cbuf is a blockette buffer.  Len contains
4980ee5cbfSDavid du Colombier  * the length of the buffer written so far, and we can
5080ee5cbfSDavid du Colombier  * write up to 254-28.
5180ee5cbfSDavid du Colombier  *
5280ee5cbfSDavid du Colombier  * We only have one active Cbuf at a time; cdimg.rrcontin is the byte
5380ee5cbfSDavid du Colombier  * offset of the beginning of that Cbuf.
5480ee5cbfSDavid du Colombier  *
5580ee5cbfSDavid du Colombier  * The blockette can be at most 255 bytes.  The last 28
5680ee5cbfSDavid du Colombier  * will be (in the worst case) a CE record pointing at
5780ee5cbfSDavid du Colombier  * a new blockette.  If we do write 255 bytes though,
5880ee5cbfSDavid du Colombier  * we'll try to pad it out to be even, and overflow.
5980ee5cbfSDavid du Colombier  * So the maximum is 254-28.
6080ee5cbfSDavid du Colombier  *
6180ee5cbfSDavid du Colombier  * Ceoffset contains the offset to be used with setcelen
6280ee5cbfSDavid du Colombier  * to patch the CE pointing at the Cbuf once we know how
6380ee5cbfSDavid du Colombier  * long the Cbuf is.
6480ee5cbfSDavid du Colombier  */
6580ee5cbfSDavid du Colombier typedef struct Cbuf Cbuf;
6680ee5cbfSDavid du Colombier struct Cbuf {
6780ee5cbfSDavid du Colombier 	int	len;		/* written so far, of 254-28 */
68*73ee67a1SDavid du Colombier 	uvlong	ceoffset;
6980ee5cbfSDavid du Colombier };
7080ee5cbfSDavid du Colombier 
7180ee5cbfSDavid du Colombier static int
freespace(Cbuf * cp)7280ee5cbfSDavid du Colombier freespace(Cbuf *cp)
7380ee5cbfSDavid du Colombier {
7480ee5cbfSDavid du Colombier 	return (254-28) - cp->len;
7580ee5cbfSDavid du Colombier }
7680ee5cbfSDavid du Colombier 
7780ee5cbfSDavid du Colombier static Cbuf*
ensurespace(Cdimg * cd,int n,Cbuf * co,Cbuf * cn,int dowrite)7880ee5cbfSDavid du Colombier ensurespace(Cdimg *cd, int n, Cbuf *co, Cbuf *cn, int dowrite)
7980ee5cbfSDavid du Colombier {
80*73ee67a1SDavid du Colombier 	uvlong end;
8180ee5cbfSDavid du Colombier 
8280ee5cbfSDavid du Colombier 	if(co->len+n <= 254-28) {
8380ee5cbfSDavid du Colombier 		co->len += n;
8480ee5cbfSDavid du Colombier 		return co;
8580ee5cbfSDavid du Colombier 	}
8680ee5cbfSDavid du Colombier 
8780ee5cbfSDavid du Colombier 	co->len += 28;
8880ee5cbfSDavid du Colombier 	assert(co->len <= 254);
8980ee5cbfSDavid du Colombier 
9080ee5cbfSDavid du Colombier 	if(dowrite == 0) {
9180ee5cbfSDavid du Colombier 		cn->len = n;
9280ee5cbfSDavid du Colombier 		return cn;
9380ee5cbfSDavid du Colombier 	}
9480ee5cbfSDavid du Colombier 
9580ee5cbfSDavid du Colombier 	/*
9680ee5cbfSDavid du Colombier 	 * the current blockette is full; update cd->rrcontin and then
9780ee5cbfSDavid du Colombier  	 * write a CE record to finish it.  Unfortunately we need to
9880ee5cbfSDavid du Colombier 	 * figure out which block will be next before we write the CE.
9980ee5cbfSDavid du Colombier 	 */
10080ee5cbfSDavid du Colombier 	end = Cwoffset(cd)+28;
10180ee5cbfSDavid du Colombier 
10280ee5cbfSDavid du Colombier 	/*
10380ee5cbfSDavid du Colombier 	 * if we're in a continuation blockette, update rrcontin.
10480ee5cbfSDavid du Colombier 	 * also, write our length into the field of the CE record
10580ee5cbfSDavid du Colombier 	 * that points at us.
10680ee5cbfSDavid du Colombier 	 */
10780ee5cbfSDavid du Colombier 	if(cd->rrcontin+co->len == end) {
10880ee5cbfSDavid du Colombier 		assert(cd->rrcontin != 0);
10980ee5cbfSDavid du Colombier 		assert(co == cn);
11080ee5cbfSDavid du Colombier 		cd->rrcontin += co->len;
11180ee5cbfSDavid du Colombier 		setcelen(cd, co->ceoffset, co->len);
11280ee5cbfSDavid du Colombier 	} else
11380ee5cbfSDavid du Colombier 		assert(co != cn);
11480ee5cbfSDavid du Colombier 
11580ee5cbfSDavid du Colombier 	/*
11680ee5cbfSDavid du Colombier 	 * if the current continuation block can't fit another
11780ee5cbfSDavid du Colombier 	 * blockette, then start a new continuation block.
11880ee5cbfSDavid du Colombier 	 * rrcontin = 0 (mod Blocksize) means we just finished
11980ee5cbfSDavid du Colombier 	 * one, not that we've just started one.
12080ee5cbfSDavid du Colombier 	 */
12180ee5cbfSDavid du Colombier 	if(cd->rrcontin%Blocksize == 0
12280ee5cbfSDavid du Colombier 	|| cd->rrcontin/Blocksize != (cd->rrcontin+256)/Blocksize) {
123*73ee67a1SDavid du Colombier 		cd->rrcontin = (vlong)cd->nextblock * Blocksize;
12480ee5cbfSDavid du Colombier 		cd->nextblock++;
12580ee5cbfSDavid du Colombier 	}
12680ee5cbfSDavid du Colombier 
12780ee5cbfSDavid du Colombier 	cn->ceoffset = CputsuspCE(cd, cd->rrcontin);
12880ee5cbfSDavid du Colombier 
12980ee5cbfSDavid du Colombier 	assert(Cwoffset(cd) == end);
13080ee5cbfSDavid du Colombier 
13180ee5cbfSDavid du Colombier 	cn->len = n;
13280ee5cbfSDavid du Colombier 	Cwseek(cd, cd->rrcontin);
13380ee5cbfSDavid du Colombier 	assert(cd->rrcontin != 0);
13480ee5cbfSDavid du Colombier 
13580ee5cbfSDavid du Colombier 	return cn;
13680ee5cbfSDavid du Colombier }
13780ee5cbfSDavid du Colombier 
13880ee5cbfSDavid du Colombier /*
13980ee5cbfSDavid du Colombier  * Put down the name, but we might need to break it
14080ee5cbfSDavid du Colombier  * into chunks so that each chunk fits in 254-28-5 bytes.
14180ee5cbfSDavid du Colombier  * What a crock.
14280ee5cbfSDavid du Colombier  *
14380ee5cbfSDavid du Colombier  * The new Plan 9 format uses strings of this form too,
14480ee5cbfSDavid du Colombier  * since they're already there.
14580ee5cbfSDavid du Colombier  */
14680ee5cbfSDavid du Colombier Cbuf*
Cputstring(Cdimg * cd,Cbuf * cp,Cbuf * cn,char * nm,char * p,int flags,int dowrite)14780ee5cbfSDavid du Colombier Cputstring(Cdimg *cd, Cbuf *cp, Cbuf *cn, char *nm, char *p, int flags, int dowrite)
14880ee5cbfSDavid du Colombier {
14980ee5cbfSDavid du Colombier 	char buf[256], *q;
15080ee5cbfSDavid du Colombier 	int free;
15180ee5cbfSDavid du Colombier 
15280ee5cbfSDavid du Colombier 	for(; p[0] != '\0'; p = q) {
15380ee5cbfSDavid du Colombier 		cp = ensurespace(cd, 5+1, cp, cn, dowrite);
15480ee5cbfSDavid du Colombier 		cp->len -= 5+1;
15580ee5cbfSDavid du Colombier 		free = freespace(cp);
15680ee5cbfSDavid du Colombier 		assert(5+1 <= free && free < 256);
15780ee5cbfSDavid du Colombier 
15880ee5cbfSDavid du Colombier 		strncpy(buf, p, free-5);
15980ee5cbfSDavid du Colombier 		buf[free-5] = '\0';
16080ee5cbfSDavid du Colombier 		q = p+strlen(buf);
16180ee5cbfSDavid du Colombier 		p = buf;
16280ee5cbfSDavid du Colombier 
16380ee5cbfSDavid du Colombier 		ensurespace(cd, 5+strlen(p), cp, nil, dowrite);	/* nil: better not use this. */
16480ee5cbfSDavid du Colombier 		Cputrripname(cd, nm, flags | (q[0] ? NMcontinue : 0), p, dowrite);
16580ee5cbfSDavid du Colombier 	}
16680ee5cbfSDavid du Colombier 	return cp;
16780ee5cbfSDavid du Colombier }
16880ee5cbfSDavid du Colombier 
16980ee5cbfSDavid du Colombier /*
17080ee5cbfSDavid du Colombier  * Write a Rock Ridge SUSP set of records for a directory entry.
17180ee5cbfSDavid du Colombier  */
17280ee5cbfSDavid du Colombier int
Cputsysuse(Cdimg * cd,Direc * d,int dot,int dowrite,int initlen)17380ee5cbfSDavid du Colombier Cputsysuse(Cdimg *cd, Direc *d, int dot, int dowrite, int initlen)
17480ee5cbfSDavid du Colombier {
17580ee5cbfSDavid du Colombier 	char buf[256], buf0[256], *nextpath, *p, *path, *q;
17680ee5cbfSDavid du Colombier 	int flags, free, m, what;
177*73ee67a1SDavid du Colombier 	uvlong o;
17880ee5cbfSDavid du Colombier 	Cbuf cn, co, *cp;
17980ee5cbfSDavid du Colombier 
18080ee5cbfSDavid du Colombier 	assert(cd != nil);
18180ee5cbfSDavid du Colombier 	assert((initlen&1) == 0);
18280ee5cbfSDavid du Colombier 
18380ee5cbfSDavid du Colombier 	if(dot == DTroot)
18480ee5cbfSDavid du Colombier 		return 0;
18580ee5cbfSDavid du Colombier 
18680ee5cbfSDavid du Colombier 	co.len = initlen;
18780ee5cbfSDavid du Colombier 
18880ee5cbfSDavid du Colombier 	o = Cwoffset(cd);
18980ee5cbfSDavid du Colombier 
19080ee5cbfSDavid du Colombier 	assert(dowrite==0 || Cwoffset(cd) == o+co.len-initlen);
19180ee5cbfSDavid du Colombier 	cp = &co;
19280ee5cbfSDavid du Colombier 
19380ee5cbfSDavid du Colombier 	if (dot == DTrootdot) {
19480ee5cbfSDavid du Colombier 		m = CputsuspSP(cd, 0);
19580ee5cbfSDavid du Colombier 		cp = ensurespace(cd, m, cp, &cn, dowrite);
19680ee5cbfSDavid du Colombier 		CputsuspSP(cd, dowrite);
19780ee5cbfSDavid du Colombier 
19880ee5cbfSDavid du Colombier 		m = CputsuspER(cd, 0);
19980ee5cbfSDavid du Colombier 		cp = ensurespace(cd, m, cp, &cn, dowrite);
20080ee5cbfSDavid du Colombier 		CputsuspER(cd, dowrite);
20180ee5cbfSDavid du Colombier 	}
20280ee5cbfSDavid du Colombier 
20380ee5cbfSDavid du Colombier 	/*
20480ee5cbfSDavid du Colombier 	 * In a perfect world, we'd be able to omit the NM
20580ee5cbfSDavid du Colombier 	 * entries when our name was all lowercase and conformant,
20680ee5cbfSDavid du Colombier 	 * but OpenBSD insists on uppercasing (really, not lowercasing)
20780ee5cbfSDavid du Colombier 	 * the ISO9660 names.
20880ee5cbfSDavid du Colombier 	 */
20980ee5cbfSDavid du Colombier 	what = RR_PX | RR_TF | RR_NM;
21080ee5cbfSDavid du Colombier 	if(d != nil && (d->mode & CHLINK))
21180ee5cbfSDavid du Colombier 		what |= RR_SL;
21280ee5cbfSDavid du Colombier 
21380ee5cbfSDavid du Colombier 	m = CputsuspRR(cd, what, 0);
21480ee5cbfSDavid du Colombier 	cp = ensurespace(cd, m, cp, &cn, dowrite);
21580ee5cbfSDavid du Colombier 	CputsuspRR(cd, what, dowrite);
21680ee5cbfSDavid du Colombier 
21780ee5cbfSDavid du Colombier 	if(what & RR_PX) {
21880ee5cbfSDavid du Colombier 		m = CputrripPX(cd, d, dot, 0);
21980ee5cbfSDavid du Colombier 		cp = ensurespace(cd, m, cp, &cn, dowrite);
22080ee5cbfSDavid du Colombier 		CputrripPX(cd, d, dot, dowrite);
22180ee5cbfSDavid du Colombier 	}
22280ee5cbfSDavid du Colombier 
22380ee5cbfSDavid du Colombier 	if(what & RR_NM) {
22480ee5cbfSDavid du Colombier 		if(dot == DTiden)
22580ee5cbfSDavid du Colombier 			p = d->name;
22680ee5cbfSDavid du Colombier 		else if(dot == DTdotdot)
22780ee5cbfSDavid du Colombier 			p = "..";
22880ee5cbfSDavid du Colombier 		else
22980ee5cbfSDavid du Colombier 			p = ".";
23080ee5cbfSDavid du Colombier 
23180ee5cbfSDavid du Colombier 		flags = suspdirflags(d, dot);
23280ee5cbfSDavid du Colombier 		assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
23380ee5cbfSDavid du Colombier 		cp = Cputstring(cd, cp, &cn, "NM", p, flags, dowrite);
23480ee5cbfSDavid du Colombier 	}
23580ee5cbfSDavid du Colombier 
23680ee5cbfSDavid du Colombier 	/*
23780ee5cbfSDavid du Colombier 	 * Put down the symbolic link.  This is even more of a crock.
23880ee5cbfSDavid du Colombier 	 * Not only are the individual elements potentially split,
23980ee5cbfSDavid du Colombier 	 * but the whole path itself can be split across SL blocks.
24080ee5cbfSDavid du Colombier 	 * To keep the code simple as possible (really), we write
24180ee5cbfSDavid du Colombier 	 * only one element per SL block, wasting 6 bytes per element.
24280ee5cbfSDavid du Colombier 	 */
24380ee5cbfSDavid du Colombier 	if(what & RR_SL) {
24480ee5cbfSDavid du Colombier 		for(path=d->symlink; path[0] != '\0'; path=nextpath) {
24580ee5cbfSDavid du Colombier 			/* break off one component */
24680ee5cbfSDavid du Colombier 			if((nextpath = strchr(path, '/')) == nil)
24780ee5cbfSDavid du Colombier 				nextpath = path+strlen(path);
24880ee5cbfSDavid du Colombier 			strncpy(buf0, path, nextpath-path);
24980ee5cbfSDavid du Colombier 			buf0[nextpath-path] = '\0';
25080ee5cbfSDavid du Colombier 			if(nextpath[0] == '/')
25180ee5cbfSDavid du Colombier 				nextpath++;
25280ee5cbfSDavid du Colombier 			p = buf0;
25380ee5cbfSDavid du Colombier 
25480ee5cbfSDavid du Colombier 			/* write the name, perhaps broken into pieces */
25580ee5cbfSDavid du Colombier 			if(strcmp(p, "") == 0)
25680ee5cbfSDavid du Colombier 				flags = NMroot;
25780ee5cbfSDavid du Colombier 			else if(strcmp(p, ".") == 0)
25880ee5cbfSDavid du Colombier 				flags = NMcurrent;
25980ee5cbfSDavid du Colombier 			else if(strcmp(p, "..") == 0)
26080ee5cbfSDavid du Colombier 				flags = NMparent;
26180ee5cbfSDavid du Colombier 			else
26280ee5cbfSDavid du Colombier 				flags = 0;
26380ee5cbfSDavid du Colombier 
26480ee5cbfSDavid du Colombier 			/* the do-while handles the empty string properly */
26580ee5cbfSDavid du Colombier 			do {
26680ee5cbfSDavid du Colombier 				/* must have room for at least 1 byte of name */
26780ee5cbfSDavid du Colombier 				cp = ensurespace(cd, 7+1, cp, &cn, dowrite);
26880ee5cbfSDavid du Colombier 				cp->len -= 7+1;
26980ee5cbfSDavid du Colombier 				free = freespace(cp);
27080ee5cbfSDavid du Colombier 				assert(7+1 <= free && free < 256);
27180ee5cbfSDavid du Colombier 
27280ee5cbfSDavid du Colombier 				strncpy(buf, p, free-7);
27380ee5cbfSDavid du Colombier 				buf[free-7] = '\0';
27480ee5cbfSDavid du Colombier 				q = p+strlen(buf);
27580ee5cbfSDavid du Colombier 				p = buf;
27680ee5cbfSDavid du Colombier 
27780ee5cbfSDavid du Colombier 				/* nil: better not need to expand */
27880ee5cbfSDavid du Colombier 				assert(7+strlen(p) <= free);
27980ee5cbfSDavid du Colombier 				ensurespace(cd, 7+strlen(p), cp, nil, dowrite);
28080ee5cbfSDavid du Colombier 				CputrripSL(cd, nextpath[0], flags | (q[0] ? NMcontinue : 0), p, dowrite);
28180ee5cbfSDavid du Colombier 				p = q;
28280ee5cbfSDavid du Colombier 			} while(p[0] != '\0');
28380ee5cbfSDavid du Colombier 		}
28480ee5cbfSDavid du Colombier 	}
28580ee5cbfSDavid du Colombier 
28680ee5cbfSDavid du Colombier 	assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
28780ee5cbfSDavid du Colombier 
28880ee5cbfSDavid du Colombier 	if(what & RR_TF) {
28980ee5cbfSDavid du Colombier 		m = CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, 0);
29080ee5cbfSDavid du Colombier 		cp = ensurespace(cd, m, cp, &cn, dowrite);
29180ee5cbfSDavid du Colombier 		CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, dowrite);
29280ee5cbfSDavid du Colombier 	}
29380ee5cbfSDavid du Colombier 	assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
29480ee5cbfSDavid du Colombier 
29580ee5cbfSDavid du Colombier 	if(cp == &cn && dowrite) {
29680ee5cbfSDavid du Colombier 		/* seek out of continuation, but mark our place */
29780ee5cbfSDavid du Colombier 		cd->rrcontin = Cwoffset(cd);
29880ee5cbfSDavid du Colombier 		setcelen(cd, cn.ceoffset, cn.len);
29980ee5cbfSDavid du Colombier 		Cwseek(cd, o+co.len-initlen);
30080ee5cbfSDavid du Colombier 	}
30180ee5cbfSDavid du Colombier 
30280ee5cbfSDavid du Colombier 	if(co.len & 1) {
30380ee5cbfSDavid du Colombier 		co.len++;
30480ee5cbfSDavid du Colombier 		if(dowrite)
30580ee5cbfSDavid du Colombier 			Cputc(cd, 0);
30680ee5cbfSDavid du Colombier 	}
30780ee5cbfSDavid du Colombier 
30880ee5cbfSDavid du Colombier 	if(dowrite) {
30980ee5cbfSDavid du Colombier 		if(Cwoffset(cd) != o+co.len-initlen)
310*73ee67a1SDavid du Colombier 			fprint(2, "offset %llud o+co.len-initlen %llud\n",
311*73ee67a1SDavid du Colombier 				Cwoffset(cd), o+co.len-initlen);
31280ee5cbfSDavid du Colombier 		assert(Cwoffset(cd) == o+co.len-initlen);
31380ee5cbfSDavid du Colombier 	} else
31480ee5cbfSDavid du Colombier 		assert(Cwoffset(cd) == o);
31580ee5cbfSDavid du Colombier 
31680ee5cbfSDavid du Colombier 	assert(co.len <= 255);
31780ee5cbfSDavid du Colombier 	return co.len - initlen;
31880ee5cbfSDavid du Colombier }
31980ee5cbfSDavid du Colombier 
32080ee5cbfSDavid du Colombier static char SUSPrrip[10] = "RRIP_1991A";
32180ee5cbfSDavid du Colombier static char SUSPdesc[84] = "RRIP <more garbage here>";
32280ee5cbfSDavid du Colombier static char SUSPsrc[135] = "RRIP <more garbage here>";
32380ee5cbfSDavid du Colombier 
32480ee5cbfSDavid du Colombier static ulong
CputsuspCE(Cdimg * cd,vlong offset)325*73ee67a1SDavid du Colombier CputsuspCE(Cdimg *cd, vlong offset)
32680ee5cbfSDavid du Colombier {
327*73ee67a1SDavid du Colombier 	vlong o, x;
32880ee5cbfSDavid du Colombier 
329*73ee67a1SDavid du Colombier 	chat("writing SUSP CE record pointing to %ld, %ld\n",
330*73ee67a1SDavid du Colombier 		offset/Blocksize, offset%Blocksize);
33180ee5cbfSDavid du Colombier 	o = Cwoffset(cd);
33280ee5cbfSDavid du Colombier 	Cputc(cd, 'C');
33380ee5cbfSDavid du Colombier 	Cputc(cd, 'E');
33480ee5cbfSDavid du Colombier 	Cputc(cd, 28);
33580ee5cbfSDavid du Colombier 	Cputc(cd, 1);
33680ee5cbfSDavid du Colombier 	Cputn(cd, offset/Blocksize, 4);
33780ee5cbfSDavid du Colombier 	Cputn(cd, offset%Blocksize, 4);
33880ee5cbfSDavid du Colombier 	x = Cwoffset(cd);
33980ee5cbfSDavid du Colombier 	Cputn(cd, 0, 4);
34080ee5cbfSDavid du Colombier 	assert(Cwoffset(cd) == o+28);
34180ee5cbfSDavid du Colombier 
34280ee5cbfSDavid du Colombier 	return x;
34380ee5cbfSDavid du Colombier }
34480ee5cbfSDavid du Colombier 
34580ee5cbfSDavid du Colombier static int
CputsuspER(Cdimg * cd,int dowrite)34680ee5cbfSDavid du Colombier CputsuspER(Cdimg *cd, int dowrite)
34780ee5cbfSDavid du Colombier {
34880ee5cbfSDavid du Colombier 	assert(cd != nil);
34980ee5cbfSDavid du Colombier 
35080ee5cbfSDavid du Colombier 	if(dowrite) {
35180ee5cbfSDavid du Colombier 		chat("writing SUSP ER record\n");
35280ee5cbfSDavid du Colombier 		Cputc(cd, 'E');           /* ER field marker */
35380ee5cbfSDavid du Colombier 		Cputc(cd, 'R');
35480ee5cbfSDavid du Colombier 		Cputc(cd, 26);            /* Length          */
35580ee5cbfSDavid du Colombier 		Cputc(cd, 1);             /* Version         */
35680ee5cbfSDavid du Colombier 		Cputc(cd, 10);            /* LEN_ID          */
35780ee5cbfSDavid du Colombier 		Cputc(cd, 4);             /* LEN_DESC        */
35880ee5cbfSDavid du Colombier 		Cputc(cd, 4);             /* LEN_SRC         */
35980ee5cbfSDavid du Colombier 		Cputc(cd, 1);             /* EXT_VER         */
36080ee5cbfSDavid du Colombier 		Cputs(cd, SUSPrrip, 10);  /* EXT_ID          */
36180ee5cbfSDavid du Colombier 		Cputs(cd, SUSPdesc, 4);   /* EXT_DESC        */
36280ee5cbfSDavid du Colombier 		Cputs(cd, SUSPsrc, 4);    /* EXT_SRC         */
36380ee5cbfSDavid du Colombier 	}
36480ee5cbfSDavid du Colombier 	return 8+10+4+4;
36580ee5cbfSDavid du Colombier }
36680ee5cbfSDavid du Colombier 
36780ee5cbfSDavid du Colombier static int
CputsuspRR(Cdimg * cd,int what,int dowrite)36880ee5cbfSDavid du Colombier CputsuspRR(Cdimg *cd, int what, int dowrite)
36980ee5cbfSDavid du Colombier {
37080ee5cbfSDavid du Colombier 	assert(cd != nil);
37180ee5cbfSDavid du Colombier 
37280ee5cbfSDavid du Colombier 	if(dowrite) {
37380ee5cbfSDavid du Colombier 		Cputc(cd, 'R');           /* RR field marker */
37480ee5cbfSDavid du Colombier 		Cputc(cd, 'R');
37580ee5cbfSDavid du Colombier 		Cputc(cd, 5);             /* Length          */
37680ee5cbfSDavid du Colombier 		Cputc(cd, 1);		  /* Version number  */
37780ee5cbfSDavid du Colombier 		Cputc(cd, what);          /* Flags           */
37880ee5cbfSDavid du Colombier 	}
37980ee5cbfSDavid du Colombier 	return 5;
38080ee5cbfSDavid du Colombier }
38180ee5cbfSDavid du Colombier 
38280ee5cbfSDavid du Colombier static int
CputsuspSP(Cdimg * cd,int dowrite)38380ee5cbfSDavid du Colombier CputsuspSP(Cdimg *cd, int dowrite)
38480ee5cbfSDavid du Colombier {
38580ee5cbfSDavid du Colombier 	assert(cd!=0);
38680ee5cbfSDavid du Colombier 
38780ee5cbfSDavid du Colombier 	if(dowrite) {
38880ee5cbfSDavid du Colombier chat("writing SUSP SP record\n");
38980ee5cbfSDavid du Colombier 		Cputc(cd, 'S');           /* SP field marker */
39080ee5cbfSDavid du Colombier 		Cputc(cd, 'P');
39180ee5cbfSDavid du Colombier 		Cputc(cd, 7);             /* Length          */
39280ee5cbfSDavid du Colombier 		Cputc(cd, 1);             /* Version         */
39380ee5cbfSDavid du Colombier 		Cputc(cd, 0xBE);          /* Magic           */
39480ee5cbfSDavid du Colombier 		Cputc(cd, 0xEF);
39580ee5cbfSDavid du Colombier 		Cputc(cd, 0);
39680ee5cbfSDavid du Colombier 	}
39780ee5cbfSDavid du Colombier 
39880ee5cbfSDavid du Colombier 	return 7;
39980ee5cbfSDavid du Colombier }
40080ee5cbfSDavid du Colombier 
40180ee5cbfSDavid du Colombier #ifdef NOTUSED
40280ee5cbfSDavid du Colombier static int
CputsuspST(Cdimg * cd,int dowrite)40380ee5cbfSDavid du Colombier CputsuspST(Cdimg *cd, int dowrite)
40480ee5cbfSDavid du Colombier {
40580ee5cbfSDavid du Colombier 	assert(cd!=0);
40680ee5cbfSDavid du Colombier 
40780ee5cbfSDavid du Colombier 	if(dowrite) {
40880ee5cbfSDavid du Colombier 		Cputc(cd, 'S');           /* ST field marker */
40980ee5cbfSDavid du Colombier 		Cputc(cd, 'T');
41080ee5cbfSDavid du Colombier 		Cputc(cd, 4);             /* Length          */
41180ee5cbfSDavid du Colombier 		Cputc(cd, 1);             /* Version         */
41280ee5cbfSDavid du Colombier 	}
41380ee5cbfSDavid du Colombier 	return 4;
41480ee5cbfSDavid du Colombier }
41580ee5cbfSDavid du Colombier #endif
41680ee5cbfSDavid du Colombier 
41780ee5cbfSDavid du Colombier static ulong
suspdirflags(Direc * d,int dot)41880ee5cbfSDavid du Colombier suspdirflags(Direc *d, int dot)
41980ee5cbfSDavid du Colombier {
42080ee5cbfSDavid du Colombier 	uchar flags;
42180ee5cbfSDavid du Colombier 
42280ee5cbfSDavid du Colombier 	USED(d);
42380ee5cbfSDavid du Colombier 	flags = 0;
42480ee5cbfSDavid du Colombier 	switch(dot) {
42580ee5cbfSDavid du Colombier 	default:
42680ee5cbfSDavid du Colombier 		assert(0);
42780ee5cbfSDavid du Colombier 	case DTdot:
42880ee5cbfSDavid du Colombier 	case DTrootdot:
42980ee5cbfSDavid du Colombier 		flags |= NMcurrent;
43080ee5cbfSDavid du Colombier 		break;
43180ee5cbfSDavid du Colombier 	case DTdotdot:
43280ee5cbfSDavid du Colombier 		flags |= NMparent;
43380ee5cbfSDavid du Colombier 		break;
43480ee5cbfSDavid du Colombier 	case DTroot:
43580ee5cbfSDavid du Colombier 		flags |= NMvolroot;
43680ee5cbfSDavid du Colombier 		break;
43780ee5cbfSDavid du Colombier 	case DTiden:
43880ee5cbfSDavid du Colombier 		break;
43980ee5cbfSDavid du Colombier 	}
44080ee5cbfSDavid du Colombier 	return flags;
44180ee5cbfSDavid du Colombier }
44280ee5cbfSDavid du Colombier 
44380ee5cbfSDavid du Colombier static int
Cputrripname(Cdimg * cd,char * nm,int flags,char * name,int dowrite)44480ee5cbfSDavid du Colombier Cputrripname(Cdimg *cd, char *nm, int flags, char *name, int dowrite)
44580ee5cbfSDavid du Colombier {
44680ee5cbfSDavid du Colombier 	int l;
44780ee5cbfSDavid du Colombier 
44880ee5cbfSDavid du Colombier 	l = strlen(name);
44980ee5cbfSDavid du Colombier 	if(dowrite) {
45080ee5cbfSDavid du Colombier 		Cputc(cd, nm[0]);                   /* NM field marker */
45180ee5cbfSDavid du Colombier 		Cputc(cd, nm[1]);
45280ee5cbfSDavid du Colombier 		Cputc(cd, l+5);        /* Length          */
45380ee5cbfSDavid du Colombier 		Cputc(cd, 1);                     /* Version         */
45480ee5cbfSDavid du Colombier 		Cputc(cd, flags);                 /* Flags           */
45580ee5cbfSDavid du Colombier 		Cputs(cd, name, l);    /* Alternate name  */
45680ee5cbfSDavid du Colombier 	}
45780ee5cbfSDavid du Colombier 	return 5+l;
45880ee5cbfSDavid du Colombier }
45980ee5cbfSDavid du Colombier 
46080ee5cbfSDavid du Colombier static int
CputrripSL(Cdimg * cd,int contin,int flags,char * name,int dowrite)46180ee5cbfSDavid du Colombier CputrripSL(Cdimg *cd, int contin, int flags, char *name, int dowrite)
46280ee5cbfSDavid du Colombier {
46380ee5cbfSDavid du Colombier 	int l;
46480ee5cbfSDavid du Colombier 
46580ee5cbfSDavid du Colombier 	l = strlen(name);
46680ee5cbfSDavid du Colombier 	if(dowrite) {
46780ee5cbfSDavid du Colombier 		Cputc(cd, 'S');
46880ee5cbfSDavid du Colombier 		Cputc(cd, 'L');
46980ee5cbfSDavid du Colombier 		Cputc(cd, l+7);
47080ee5cbfSDavid du Colombier 		Cputc(cd, 1);
47180ee5cbfSDavid du Colombier 		Cputc(cd, contin ? 1 : 0);
47280ee5cbfSDavid du Colombier 		Cputc(cd, flags);
47380ee5cbfSDavid du Colombier 		Cputc(cd, l);
47480ee5cbfSDavid du Colombier 		Cputs(cd, name, l);
47580ee5cbfSDavid du Colombier 	}
47680ee5cbfSDavid du Colombier 	return 7+l;
47780ee5cbfSDavid du Colombier }
47880ee5cbfSDavid du Colombier 
47980ee5cbfSDavid du Colombier static int
CputrripPX(Cdimg * cd,Direc * d,int dot,int dowrite)48080ee5cbfSDavid du Colombier CputrripPX(Cdimg *cd, Direc *d, int dot, int dowrite)
48180ee5cbfSDavid du Colombier {
48280ee5cbfSDavid du Colombier 	assert(cd!=0);
48380ee5cbfSDavid du Colombier 
48480ee5cbfSDavid du Colombier 	if(dowrite) {
48580ee5cbfSDavid du Colombier 		Cputc(cd, 'P');             /* PX field marker */
48680ee5cbfSDavid du Colombier 		Cputc(cd, 'X');
48780ee5cbfSDavid du Colombier 		Cputc(cd, 36);              /* Length          */
48880ee5cbfSDavid du Colombier 		Cputc(cd, 1);               /* Version         */
48980ee5cbfSDavid du Colombier 
49080ee5cbfSDavid du Colombier 		Cputn(cd, mode(d, dot), 4); /* POSIX File mode */
49180ee5cbfSDavid du Colombier 		Cputn(cd, nlink(d), 4);     /* POSIX st_nlink  */
49280ee5cbfSDavid du Colombier 		Cputn(cd, d?d->uidno:0, 4);  /* POSIX st_uid    */
49380ee5cbfSDavid du Colombier 		Cputn(cd, d?d->gidno:0, 4);  /* POSIX st_gid    */
49480ee5cbfSDavid du Colombier 	}
49580ee5cbfSDavid du Colombier 
49680ee5cbfSDavid du Colombier 	return 36;
49780ee5cbfSDavid du Colombier }
49880ee5cbfSDavid du Colombier 
49980ee5cbfSDavid du Colombier static int
CputrripTF(Cdimg * cd,Direc * d,int type,int dowrite)50080ee5cbfSDavid du Colombier CputrripTF(Cdimg *cd, Direc *d, int type, int dowrite)
50180ee5cbfSDavid du Colombier {
50280ee5cbfSDavid du Colombier 	int i, length;
50380ee5cbfSDavid du Colombier 
50480ee5cbfSDavid du Colombier 	assert(cd!=0);
50580ee5cbfSDavid du Colombier 	assert(!(type & TFlongform));
50680ee5cbfSDavid du Colombier 
50780ee5cbfSDavid du Colombier 	length = 0;
50880ee5cbfSDavid du Colombier 	for(i=0; i<7; i++)
50980ee5cbfSDavid du Colombier 		if (type & (1<<i))
51080ee5cbfSDavid du Colombier 			length++;
51180ee5cbfSDavid du Colombier 	assert(length == 4);
51280ee5cbfSDavid du Colombier 
51380ee5cbfSDavid du Colombier 	if(dowrite) {
51480ee5cbfSDavid du Colombier 		Cputc(cd, 'T');				/* TF field marker */
51580ee5cbfSDavid du Colombier 		Cputc(cd, 'F');
51680ee5cbfSDavid du Colombier 		Cputc(cd, 5+7*length);		/* Length		 */
51780ee5cbfSDavid du Colombier 		Cputc(cd, 1);				/* Version		 */
51880ee5cbfSDavid du Colombier 		Cputc(cd, type);					/* Flags (types)	 */
51980ee5cbfSDavid du Colombier 
52080ee5cbfSDavid du Colombier 		if (type & TFcreation)
52180ee5cbfSDavid du Colombier 			Cputdate(cd, d?d->ctime:0);
52280ee5cbfSDavid du Colombier 		if (type & TFmodify)
52380ee5cbfSDavid du Colombier 			Cputdate(cd, d?d->mtime:0);
52480ee5cbfSDavid du Colombier 		if (type & TFaccess)
52580ee5cbfSDavid du Colombier 			Cputdate(cd, d?d->atime:0);
52680ee5cbfSDavid du Colombier 		if (type & TFattributes)
52780ee5cbfSDavid du Colombier 			Cputdate(cd, d?d->ctime:0);
52880ee5cbfSDavid du Colombier 
52980ee5cbfSDavid du Colombier 	//	if (type & TFbackup)
53080ee5cbfSDavid du Colombier 	//		Cputdate(cd, 0);
53180ee5cbfSDavid du Colombier 	//	if (type & TFexpiration)
53280ee5cbfSDavid du Colombier 	//		Cputdate(cd, 0);
53380ee5cbfSDavid du Colombier 	//	if (type & TFeffective)
53480ee5cbfSDavid du Colombier 	//		Cputdate(cd, 0);
53580ee5cbfSDavid du Colombier 	}
53680ee5cbfSDavid du Colombier 	return 5+7*length;
53780ee5cbfSDavid du Colombier }
53880ee5cbfSDavid du Colombier 
53980ee5cbfSDavid du Colombier 
54092f2054cSDavid du Colombier #define NONPXMODES  (DMDIR | DMAPPEND | DMEXCL | DMMOUNT)
54180ee5cbfSDavid du Colombier #define POSIXMODEMASK (0177777)
54280ee5cbfSDavid du Colombier #ifndef S_IFMT
54380ee5cbfSDavid du Colombier #define S_IFMT  (0170000)
54480ee5cbfSDavid du Colombier #endif
54580ee5cbfSDavid du Colombier #ifndef S_IFDIR
54680ee5cbfSDavid du Colombier #define S_IFDIR (0040000)
54780ee5cbfSDavid du Colombier #endif
54880ee5cbfSDavid du Colombier #ifndef S_IFREG
54980ee5cbfSDavid du Colombier #define S_IFREG (0100000)
55080ee5cbfSDavid du Colombier #endif
55180ee5cbfSDavid du Colombier #ifndef S_IFLNK
55280ee5cbfSDavid du Colombier #define S_IFLNK (0120000)
55380ee5cbfSDavid du Colombier #endif
55480ee5cbfSDavid du Colombier #undef  ISTYPE
55580ee5cbfSDavid du Colombier #define ISTYPE(mode, mask)  (((mode) & S_IFMT) == (mask))
55680ee5cbfSDavid du Colombier #ifndef S_ISDIR
55780ee5cbfSDavid du Colombier #define S_ISDIR(mode) ISTYPE(mode, S_IFDIR)
55880ee5cbfSDavid du Colombier #endif
55980ee5cbfSDavid du Colombier #ifndef S_ISREG
56080ee5cbfSDavid du Colombier #define S_ISREG(mode) ISTYPE(mode, S_IREG)
56180ee5cbfSDavid du Colombier #endif
56280ee5cbfSDavid du Colombier #ifndef S_ISLNK
56380ee5cbfSDavid du Colombier #define S_ISLNK(mode) ISTYPE(mode, S_ILNK)
56480ee5cbfSDavid du Colombier #endif
56580ee5cbfSDavid du Colombier 
56680ee5cbfSDavid du Colombier 
56780ee5cbfSDavid du Colombier static long
mode(Direc * d,int dot)56880ee5cbfSDavid du Colombier mode(Direc *d, int dot)
56980ee5cbfSDavid du Colombier {
57080ee5cbfSDavid du Colombier 	long mode;
57180ee5cbfSDavid du Colombier 
57280ee5cbfSDavid du Colombier 	if (!d)
57380ee5cbfSDavid du Colombier 		return 0;
57480ee5cbfSDavid du Colombier 
57580ee5cbfSDavid du Colombier 	if ((dot != DTroot) && (dot != DTrootdot)) {
57680ee5cbfSDavid du Colombier 		mode = (d->mode & ~(NONPXMODES));
5779a747e4fSDavid du Colombier 		if (d->mode & DMDIR)
57880ee5cbfSDavid du Colombier 			mode |= S_IFDIR;
57980ee5cbfSDavid du Colombier 		else if (d->mode & CHLINK)
58080ee5cbfSDavid du Colombier 			mode |= S_IFLNK;
58180ee5cbfSDavid du Colombier 		else
58280ee5cbfSDavid du Colombier 			mode |= S_IFREG;
58380ee5cbfSDavid du Colombier 	} else
58480ee5cbfSDavid du Colombier 		mode = S_IFDIR | (0755);
58580ee5cbfSDavid du Colombier 
58680ee5cbfSDavid du Colombier 	mode &= POSIXMODEMASK;
58780ee5cbfSDavid du Colombier 
58880ee5cbfSDavid du Colombier 	/* Botch: not all POSIX types supported yet */
58980ee5cbfSDavid du Colombier 	assert(mode & (S_IFDIR|S_IFREG));
59080ee5cbfSDavid du Colombier 
59180ee5cbfSDavid du Colombier chat("writing PX record mode field %ulo with dot %d and name \"%s\"\n", mode, dot, d->name);
59280ee5cbfSDavid du Colombier 
59380ee5cbfSDavid du Colombier 	return mode;
59480ee5cbfSDavid du Colombier }
59580ee5cbfSDavid du Colombier 
59680ee5cbfSDavid du Colombier static long
nlink(Direc * d)59780ee5cbfSDavid du Colombier nlink(Direc *d)   /* Trump up the nlink field for POSIX compliance */
59880ee5cbfSDavid du Colombier {
59980ee5cbfSDavid du Colombier 	int i;
60080ee5cbfSDavid du Colombier 	long n;
60180ee5cbfSDavid du Colombier 
60280ee5cbfSDavid du Colombier 	if (!d)
60380ee5cbfSDavid du Colombier 		return 0;
60480ee5cbfSDavid du Colombier 
60580ee5cbfSDavid du Colombier 	n = 1;
6069a747e4fSDavid du Colombier 	if (d->mode & DMDIR)   /* One for "." and one more for ".." */
60780ee5cbfSDavid du Colombier 		n++;
60880ee5cbfSDavid du Colombier 
60980ee5cbfSDavid du Colombier 	for(i=0; i<d->nchild; i++)
6109a747e4fSDavid du Colombier 		if (d->child[i].mode & DMDIR)
61180ee5cbfSDavid du Colombier 			n++;
61280ee5cbfSDavid du Colombier 
61380ee5cbfSDavid du Colombier 	return n;
61480ee5cbfSDavid du Colombier }
61580ee5cbfSDavid du Colombier 
616