xref: /plan9/sys/src/cmd/disk/9660/ichar.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <libsec.h>
5 #include <ctype.h>
6 
7 #include "iso9660.h"
8 
9 /*
10  * ISO 9660 file names must be uppercase, digits, or underscore.
11  * We use lowercase, digits, and underscore, translating lower to upper
12  * in mkisostring, and upper to lower in isostring.
13  * Files with uppercase letters in their names are thus nonconforming.
14  * Conforming files also must have a basename
15  * at most 8 letters and at most one suffix of at most 3 letters.
16  */
17 char*
isostring(uchar * buf,int len)18 isostring(uchar *buf, int len)
19 {
20 	char *p, *q;
21 
22 	p = emalloc(len+1);
23 	memmove(p, buf, len);
24 	p[len] = '\0';
25 	while(len > 0 && p[len-1] == ' ')
26 		p[--len] = '\0';
27 	for(q=p; *q; q++)
28 		*q = tolower(*q);
29 
30 	q = atom(p);
31 	free(p);
32 	return q;
33 }
34 
35 int
isisofrog(char c)36 isisofrog(char c)
37 {
38 	if(c >= '0' && c <= '9')
39 		return 0;
40 	if(c >= 'a' && c <= 'z')
41 		return 0;
42 	if(c == '_')
43 		return 0;
44 
45 	return 1;
46 }
47 
48 int
isbadiso9660(char * s)49 isbadiso9660(char *s)
50 {
51 	char *p, *q;
52 	int i;
53 
54 	if((p = strchr(s, '.')) != nil) {
55 		if(p-s > 8)
56 			return 1;
57 		for(q=s; q<p; q++)
58 			if(isisofrog(*q))
59 				return 1;
60 		if(strlen(p+1) > 3)
61 			return 1;
62 		for(q=p+1; *q; q++)
63 			if(isisofrog(*q))
64 				return 1;
65 	} else {
66 		if(strlen(s) > 8)
67 			return 1;
68 		for(q=s; *q; q++)
69 			if(isisofrog(*q))
70 				return 1;
71 
72 		/*
73 		 * we rename files of the form [FD]dddddd
74 		 * so they don't interfere with us.
75 		 */
76 		if(strlen(s) == 7 && (s[0] == 'D' || s[0] == 'F')) {
77 			for(i=1; i<7; i++)
78 				if(s[i] < '0' || s[i] > '9')
79 					break;
80 			if(i == 7)
81 				return 1;
82 		}
83 	}
84 	return 0;
85 }
86 
87 /*
88  * ISO9660 name comparison
89  *
90  * The standard algorithm is as follows:
91  *   Take the filenames without extensions, pad the shorter with 0x20s (spaces),
92  *   and do strcmp.  If they are equal, go on.
93  *   Take the extensions, pad the shorter with 0x20s (spaces),
94  *   and do strcmp.  If they are equal, go on.
95  *   Compare the version numbers.
96  *
97  * Since Plan 9 names are not allowed to contain characters 0x00-0x1F,
98  * the padded comparisons are equivalent to using strcmp directly.
99  * We still need to handle the base and extension differently,
100  * so that .foo sorts before !foo.foo.
101  */
102 int
isocmp(const void * va,const void * vb)103 isocmp(const void *va, const void *vb)
104 {
105 	int i;
106 	char s1[32], s2[32], *b1, *b2, *e1, *e2;
107 	const Direc *a, *b;
108 
109 	a = va;
110 	b = vb;
111 
112 	strecpy(s1, s1+sizeof s1, a->confname);
113 	b1 = s1;
114 	strecpy(s2, s2+sizeof s2, b->confname);
115 	b2 = s2;
116 	if((e1 = strchr(b1, '.')) != nil)
117 		*e1++ = '\0';
118 	else
119 		e1 = "";
120 	if((e2 = strchr(b2, '.')) != nil)
121 		*e2++ = '\0';
122 	else
123 		e2 = "";
124 
125 	if((i = strcmp(b1, b2)) != 0)
126 		return i;
127 
128 	return strcmp(e1, e2);
129 }
130 
131 static char*
mkisostring(char * isobuf,int n,char * s)132 mkisostring(char *isobuf, int n, char *s)
133 {
134 	char *p, *q, *eq;
135 
136 	eq = isobuf+n;
137 	for(p=s, q=isobuf; *p && q < eq; p++)
138 		if('a' <= *p && *p <= 'z')
139 			*q++ = *p+'A'-'a';
140 		else
141 			*q++ = *p;
142 
143 	while(q < eq)
144 		*q++ = ' ';
145 
146 	return isobuf;
147 }
148 
149 void
Cputisopvd(Cdimg * cd,Cdinfo info)150 Cputisopvd(Cdimg *cd, Cdinfo info)
151 {
152 	char buf[130];
153 
154 	Cputc(cd, 1);				/* primary volume descriptor */
155 	Cputs(cd, "CD001", 5);			/* standard identifier */
156 	Cputc(cd, 1);				/* volume descriptor version */
157 	Cputc(cd, 0);				/* unused */
158 
159 	assert(~info.flags & (CDplan9|CDrockridge));
160 
161 	/* system identifier */
162 	strcpy(buf, "");
163 	if(info.flags & CDplan9)
164 		strcat(buf, "plan 9 ");
165 	if(info.flags & CDrockridge)
166 		strcat(buf, "rrip ");
167 	if(info.flags & CDbootable)
168 		strcat(buf, "boot ");
169 	if(info.flags & CDconform)
170 		strcat(buf, "iso9660");
171 	else
172 		strcat(buf, "utf8");
173 
174 	struprcpy(buf, buf);
175 	Cputs(cd, buf, 32);
176 
177 	Cputs(cd, mkisostring(buf, 32, info.volumename), 32);			/* volume identifier */
178 
179 	Crepeat(cd, 0, 8);				/* unused */
180 	Cputn(cd, 0, 4);				/* volume space size */
181 	Crepeat(cd, 0, 32);				/* unused */
182 	Cputn(cd, 1, 2);				/* volume set size */
183 	Cputn(cd, 1, 2);				/* volume sequence number */
184 	Cputn(cd, Blocksize, 2);			/* logical block size */
185 	Cputn(cd, 0, 4);				/* path table size */
186 	Cputnl(cd, 0, 4);				/* location of Lpath */
187 	Cputnl(cd, 0, 4);				/* location of optional Lpath */
188 	Cputnm(cd, 0, 4);				/* location of Mpath */
189 	Cputnm(cd, 0, 4);				/* location of optional Mpath */
190 	Cputisodir(cd, nil, DTroot, 1, Cwoffset(cd));			/* root directory */
191 
192 	Cputs(cd, mkisostring(buf, 128, info.volumeset), 128);		/* volume set identifier */
193 	Cputs(cd, mkisostring(buf, 128, info.publisher), 128);			/* publisher identifier */
194 	Cputs(cd, mkisostring(buf, 128, info.preparer), 128);			/* data preparer identifier */
195 	Cputs(cd, mkisostring(buf, 128, info.application), 128);		/* application identifier */
196 
197 	Cputs(cd, "", 37);			/* copyright notice */
198 	Cputs(cd, "", 37);			/* abstract */
199 	Cputs(cd, "", 37);			/* bibliographic file */
200 	Cputdate1(cd, now);				/* volume creation date */
201 	Cputdate1(cd, now);				/* volume modification date */
202 	Cputdate1(cd, 0);				/* volume expiration date */
203 	Cputdate1(cd, 0);				/* volume effective date */
204 	Cputc(cd, 1);				/* file structure version */
205 	Cpadblock(cd);
206 }
207