| #include <u.h> | 
 | #include <libc.h> | 
 | #include <bio.h> | 
 | #include <libsec.h> | 
 | #include <ctype.h> | 
 |  | 
 | #include "iso9660.h" | 
 |  | 
 | /* | 
 |  * ISO 9660 file names must be uppercase, digits, or underscore. | 
 |  * We use lowercase, digits, and underscore, translating lower to upper | 
 |  * in mkisostring, and upper to lower in isostring. | 
 |  * Files with uppercase letters in their names are thus nonconforming. | 
 |  * Conforming files also must have a basename | 
 |  * at most 8 letters and at most one suffix of at most 3 letters. | 
 |  */ | 
 | char* | 
 | isostring(uchar *buf, int len) | 
 | { | 
 | 	char *p, *q; | 
 |  | 
 | 	p = emalloc(len+1); | 
 | 	memmove(p, buf, len); | 
 | 	p[len] = '\0'; | 
 | 	while(len > 0 && p[len-1] == ' ') | 
 | 		p[--len] = '\0'; | 
 | 	for(q=p; *q; q++) | 
 | 		*q = tolower((uchar)*q); | 
 | 	q = atom(p); | 
 | 	free(p); | 
 | 	return q; | 
 | } | 
 |  | 
 | int  | 
 | isisofrog(char c) | 
 | { | 
 | 	if(c >= '0' && c <= '9') | 
 | 		return 0; | 
 | 	if(c >= 'a' && c <= 'z') | 
 | 		return 0; | 
 | 	if(c == '_') | 
 | 		return 0; | 
 |  | 
 | 	return 1; | 
 | } | 
 |  | 
 | int | 
 | isbadiso9660(char *s) | 
 | { | 
 | 	char *p, *q; | 
 | 	int i; | 
 |  | 
 | 	if((p = strchr(s, '.')) != nil) { | 
 | 		if(p-s > 8) | 
 | 			return 1; | 
 | 		for(q=s; q<p; q++) | 
 | 			if(isisofrog(*q)) | 
 | 				return 1; | 
 | 		if(strlen(p+1) > 3) | 
 | 			return 1; | 
 | 		for(q=p+1; *q; q++) | 
 | 			if(isisofrog(*q)) | 
 | 				return 1; | 
 | 	} else { | 
 | 		if(strlen(s) > 8) | 
 | 			return 1; | 
 | 		for(q=s; *q; q++) | 
 | 			if(isisofrog(*q)) | 
 | 				return 1; | 
 |  | 
 | 		/* | 
 | 		 * we rename files of the form [FD]dddddd | 
 | 		 * so they don't interfere with us. | 
 | 		 */ | 
 | 		if(strlen(s) == 7 && (s[0] == 'D' || s[0] == 'F')) { | 
 | 			for(i=1; i<7; i++) | 
 | 				if(s[i] < '0' || s[i] > '9') | 
 | 					break; | 
 | 			if(i == 7) | 
 | 				return 1; | 
 | 		} | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * ISO9660 name comparison | 
 |  *  | 
 |  * The standard algorithm is as follows: | 
 |  *   Take the filenames without extensions, pad the shorter with 0x20s (spaces), | 
 |  *   and do strcmp.  If they are equal, go on. | 
 |  *   Take the extensions, pad the shorter with 0x20s (spaces), | 
 |  *   and do strcmp.  If they are equal, go on. | 
 |  *   Compare the version numbers. | 
 |  * | 
 |  * Since Plan 9 names are not allowed to contain characters 0x00-0x1F, | 
 |  * the padded comparisons are equivalent to using strcmp directly. | 
 |  * We still need to handle the base and extension differently, | 
 |  * so that .foo sorts before !foo.foo. | 
 |  */ | 
 | int | 
 | isocmp(const void *va, const void *vb) | 
 | { | 
 | 	int i; | 
 | 	char s1[32], s2[32], *b1, *b2, *e1, *e2; | 
 | 	const Direc *a, *b; | 
 |  | 
 | 	a = va; | 
 | 	b = vb; | 
 |  | 
 | 	strecpy(s1, s1+sizeof s1, a->confname); | 
 | 	b1 = s1; | 
 | 	strecpy(s2, s2+sizeof s2, b->confname); | 
 | 	b2 = s2; | 
 | 	if((e1 = strchr(b1, '.')) != nil) | 
 | 		*e1++ = '\0'; | 
 | 	else | 
 | 		e1 = ""; | 
 | 	if((e2 = strchr(b2, '.')) != nil) | 
 | 		*e2++ = '\0'; | 
 | 	else | 
 | 		e2 = ""; | 
 |  | 
 | 	if((i = strcmp(b1, b2)) != 0) | 
 | 		return i; | 
 |  | 
 | 	return strcmp(e1, e2); | 
 | } | 
 |  | 
 | static char* | 
 | mkisostring(char *isobuf, int n, char *s) | 
 | { | 
 | 	char *p, *q, *eq; | 
 |  | 
 | 	eq = isobuf+n; | 
 | 	for(p=s, q=isobuf; *p && q < eq; p++) | 
 | 		if('a' <= *p && *p <= 'z') | 
 | 			*q++ = *p+'A'-'a'; | 
 | 		else | 
 | 			*q++ = *p; | 
 |  | 
 | 	while(q < eq) | 
 | 		*q++ = ' '; | 
 |  | 
 | 	return isobuf; | 
 | } | 
 |  | 
 | void | 
 | Cputisopvd(Cdimg *cd, Cdinfo info) | 
 | { | 
 | 	char buf[130]; | 
 |  | 
 | 	Cputc(cd, 1);				/* primary volume descriptor */ | 
 | 	Cputs(cd, "CD001", 5);			/* standard identifier */ | 
 | 	Cputc(cd, 1);				/* volume descriptor version */ | 
 | 	Cputc(cd, 0);				/* unused */ | 
 |  | 
 | 	assert(~info.flags & (CDplan9|CDrockridge)); | 
 |  | 
 | 	/* system identifier */ | 
 | 	strcpy(buf, ""); | 
 | 	if(info.flags & CDplan9) | 
 | 		strcat(buf, "plan 9 "); | 
 | 	if(info.flags & CDrockridge) | 
 | 		strcat(buf, "rrip "); | 
 | 	if(info.flags & CDbootable) | 
 | 		strcat(buf, "boot "); | 
 | 	if(info.flags & CDconform) | 
 | 		strcat(buf, "iso9660"); | 
 | 	else | 
 | 		strcat(buf, "utf8"); | 
 | 	 | 
 | 	struprcpy(buf, buf); | 
 | 	Cputs(cd, buf, 32); | 
 |  | 
 | 	Cputs(cd, mkisostring(buf, 32, info.volumename), 32);			/* volume identifier */ | 
 |  | 
 | 	Crepeat(cd, 0, 8);				/* unused */ | 
 | 	Cputn(cd, 0, 4);				/* volume space size */ | 
 | 	Crepeat(cd, 0, 32);				/* unused */ | 
 | 	Cputn(cd, 1, 2);				/* volume set size */ | 
 | 	Cputn(cd, 1, 2);				/* volume sequence number */ | 
 | 	Cputn(cd, Blocksize, 2);			/* logical block size */ | 
 | 	Cputn(cd, 0, 4);				/* path table size */ | 
 | 	Cputnl(cd, 0, 4);				/* location of Lpath */ | 
 | 	Cputnl(cd, 0, 4);				/* location of optional Lpath */ | 
 | 	Cputnm(cd, 0, 4);				/* location of Mpath */ | 
 | 	Cputnm(cd, 0, 4);				/* location of optional Mpath */ | 
 | 	Cputisodir(cd, nil, DTroot, 1, Cwoffset(cd));			/* root directory */ | 
 |  | 
 | 	Cputs(cd, mkisostring(buf, 128, info.volumeset), 128);		/* volume set identifier */ | 
 | 	Cputs(cd, mkisostring(buf, 128, info.publisher), 128);			/* publisher identifier */ | 
 | 	Cputs(cd, mkisostring(buf, 128, info.preparer), 128);			/* data preparer identifier */ | 
 | 	Cputs(cd, mkisostring(buf, 128, info.application), 128);		/* application identifier */ | 
 |  | 
 | 	Cputs(cd, "", 37);			/* copyright notice */ | 
 | 	Cputs(cd, "", 37);			/* abstract */ | 
 | 	Cputs(cd, "", 37);			/* bibliographic file */ | 
 | 	Cputdate1(cd, now);				/* volume creation date */ | 
 | 	Cputdate1(cd, now);				/* volume modification date */ | 
 | 	Cputdate1(cd, 0);				/* volume expiration date */ | 
 | 	Cputdate1(cd, 0);				/* volume effective date */ | 
 | 	Cputc(cd, 1);				/* file structure version */ | 
 | 	Cpadblock(cd); | 
 | } |