cd9660.c revision 1.1 1 /* $NetBSD: cd9660.c,v 1.1 1996/09/30 16:01:19 ws Exp $ */
2
3 /*
4 * Copyright (C) 1996 Wolfgang Solfrank.
5 * Copyright (C) 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Stand-alone ISO9660 file reading package.
36 *
37 * Note: This doesn't support Rock Ridge extensions, extended attributes,
38 * blocksizes other than 2048 bytes, multi-extent files, etc.
39 */
40 #include <sys/param.h>
41
42 #include <lib/libkern/libkern.h>
43
44 /* THIS IS AN UGLY HACK!!! XXX */
45 struct fid;
46 struct mbuf;
47 struct nameidata;
48 struct netexport { int x; };
49 struct proc;
50 struct statfs;
51 struct ucred;
52 #include <isofs/cd9660/iso.h>
53 /* These once were in iso.h, but got deleted??? */
54 extern __inline int
55 isonum_722(p)
56 unsigned char *p;
57 {
58 return ((char)*p << 8)|p[1];
59 }
60
61 extern __inline int
62 isonum_732(p)
63 unsigned char *p;
64 {
65 return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
66 }
67
68 #include "stand.h"
69 #include "cd9660.h"
70
71 struct file {
72 off_t off; /* Current offset within file */
73 daddr_t bno; /* Starting block number */
74 off_t size; /* Size of file */
75 };
76
77 struct ptable_ent {
78 char namlen [ISODCL( 1, 1)]; /* 711 */
79 char extlen [ISODCL( 2, 2)]; /* 711 */
80 char block [ISODCL( 3, 6)]; /* 732 */
81 char parent [ISODCL( 7, 8)]; /* 722 */
82 char name [1];
83 };
84 #define PTFIXSZ 8
85 #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
86
87 #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
88
89 static int
90 toupper(c)
91 int c;
92 {
93 return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
94 }
95
96 static int
97 pnmatch(path, pp)
98 char *path;
99 struct ptable_ent *pp;
100 {
101 char *cp;
102 int i;
103
104 cp = pp->name;
105 for (i = isonum_711(pp->namlen); --i >= 0; path++, cp++) {
106 if (toupper(*path) == *cp)
107 continue;
108 return 0;
109 }
110 if (*path != '/')
111 return 0;
112 return 1;
113 }
114
115 static int
116 dirmatch(path, dp)
117 char *path;
118 struct iso_directory_record *dp;
119 {
120 char *cp;
121 int i;
122
123 /* This needs to be a regular file */
124 if (dp->flags[0] & 6)
125 return 0;
126
127 cp = dp->name;
128 for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) {
129 if (!*path)
130 break;
131 if (toupper(*path) == *cp)
132 continue;
133 return 0;
134 }
135 if (*path)
136 return 0;
137 /*
138 * Allow stripping of trailing dots and the version number.
139 * Note that this will find the first instead of the last version
140 * of a file.
141 */
142 if (i >= 0 && (*cp == ';' || *cp == '.')) {
143 /* This is to prevent matching of numeric extensions */
144 if (*cp == '.' && cp[1] != ';')
145 return 0;
146 while (--i >= 0)
147 if (*++cp != ';' && (*cp < '0' || *cp > '9'))
148 return 0;
149 }
150 return 1;
151 }
152
153 int
154 cd9660_open(path, f)
155 char *path;
156 struct open_file *f;
157 {
158 struct file *fp = 0;
159 void *buf;
160 struct iso_primary_descriptor *vd;
161 size_t buf_size, read, psize, dsize;
162 daddr_t bno;
163 int parent, ent;
164 struct ptable_ent *pp;
165 struct iso_directory_record *dp;
166 int rc;
167
168 /* First find the volume descriptor */
169 buf = alloc(buf_size = ISO_DEFAULT_BLOCK_SIZE);
170 vd = buf;
171 for (bno = 16;; bno++) {
172 twiddle();
173 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
174 ISO_DEFAULT_BLOCK_SIZE, buf, &read);
175 if (rc)
176 goto out;
177 if (read != ISO_DEFAULT_BLOCK_SIZE) {
178 rc = EIO;
179 goto out;
180 }
181 rc = EINVAL;
182 if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
183 goto out;
184 if (isonum_711(vd->type) == ISO_VD_END)
185 goto out;
186 if (isonum_711(vd->type) == ISO_VD_PRIMARY)
187 break;
188 }
189 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
190 goto out;
191
192 /* Now get the path table and lookup the directory of the file */
193 bno = isonum_732(vd->type_m_path_table);
194 psize = isonum_733(vd->path_table_size);
195
196 if (psize > ISO_DEFAULT_BLOCK_SIZE) {
197 free(buf, ISO_DEFAULT_BLOCK_SIZE);
198 buf = alloc(buf_size = roundup(psize, ISO_DEFAULT_BLOCK_SIZE));
199 }
200
201 twiddle();
202 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
203 buf_size, buf, &read);
204 if (rc)
205 goto out;
206 if (read != buf_size) {
207 rc = EIO;
208 goto out;
209 }
210
211 parent = 1;
212 pp = (struct ptable_ent *)buf;
213 ent = 1;
214 bno = isonum_732(pp->block) + isonum_711(pp->extlen);
215
216 rc = ENOENT;
217 while (*path) {
218 if ((void *)pp >= buf + psize)
219 break;
220 if (isonum_722(pp->parent) != parent)
221 break;
222 if (!pnmatch(path, pp)) {
223 pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp));
224 ent++;
225 continue;
226 }
227 path += isonum_711(pp->namlen) + 1;
228 parent = ent;
229 bno = isonum_732(pp->block) + isonum_711(pp->extlen);
230 while ((void *)pp < buf + psize) {
231 if (isonum_722(pp->parent) == parent)
232 break;
233 pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp));
234 ent++;
235 }
236 }
237
238 /* Now bno has the start of the directory that supposedly contains the file */
239 bno--;
240 dsize = 1; /* Something stupid, but > 0 XXX */
241 for (psize = 0; psize < dsize;) {
242 if (!(psize % ISO_DEFAULT_BLOCK_SIZE)) {
243 bno++;
244 twiddle();
245 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ,
246 cdb2devb(bno),
247 ISO_DEFAULT_BLOCK_SIZE,
248 buf, &read);
249 if (rc)
250 goto out;
251 if (read != ISO_DEFAULT_BLOCK_SIZE) {
252 rc = EIO;
253 goto out;
254 }
255 dp = (struct iso_directory_record *)buf;
256 }
257 if (!isonum_711(dp->length)) {
258 if ((void *)dp == buf)
259 psize += ISO_DEFAULT_BLOCK_SIZE;
260 else
261 psize = roundup(psize, ISO_DEFAULT_BLOCK_SIZE);
262 continue;
263 }
264 if (dsize == 1)
265 dsize = isonum_733(dp->size);
266 if (dirmatch(path, dp))
267 break;
268 psize += isonum_711(dp->length);
269 dp = (struct iso_directory_record *)((void *)dp + isonum_711(dp->length));
270 }
271
272 if (psize >= dsize) {
273 rc = ENOENT;
274 goto out;
275 }
276
277 /* allocate file system specific data structure */
278 fp = alloc(sizeof(struct file));
279 bzero(fp, sizeof(struct file));
280 f->f_fsdata = (void *)fp;
281
282 fp->off = 0;
283 fp->bno = isonum_733(dp->extent);
284 fp->size = isonum_733(dp->size);
285 free(buf, buf_size);
286
287 return 0;
288
289 out:
290 if (fp)
291 free(fp, sizeof(struct file));
292 free(buf, buf_size);
293
294 return rc;
295 }
296
297 int
298 cd9660_close(f)
299 struct open_file *f;
300 {
301 struct file *fp = (struct file *)f->f_fsdata;
302
303 f->f_fsdata = 0;
304 free(fp, sizeof *fp);
305
306 return 0;
307 }
308
309 int
310 cd9660_read(f, start, size, resid)
311 struct open_file *f;
312 void *start;
313 size_t size;
314 size_t *resid;
315 {
316 struct file *fp = (struct file *)f->f_fsdata;
317 int rc = 0;
318 daddr_t bno;
319 char buf[ISO_DEFAULT_BLOCK_SIZE];
320 char *dp;
321 size_t read, off;
322
323 while (size) {
324 if (fp->off < 0 || fp->off >= fp->size)
325 break;
326 bno = fp->off / ISO_DEFAULT_BLOCK_SIZE + fp->bno;
327 if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1)
328 || size < ISO_DEFAULT_BLOCK_SIZE)
329 dp = buf;
330 else
331 dp = start;
332 twiddle();
333 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
334 ISO_DEFAULT_BLOCK_SIZE, dp, &read);
335 if (rc)
336 return rc;
337 if (read != ISO_DEFAULT_BLOCK_SIZE)
338 return EIO;
339 if (dp == buf) {
340 off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1);
341 if (read > off + size)
342 read = off + size;
343 read -= off;
344 bcopy(buf + off, start, read);
345 start += read;
346 fp->off += read;
347 size -= read;
348 } else {
349 start += ISO_DEFAULT_BLOCK_SIZE;
350 fp->off += ISO_DEFAULT_BLOCK_SIZE;
351 size -= ISO_DEFAULT_BLOCK_SIZE;
352 }
353 }
354 if (resid)
355 *resid = size;
356 return rc;
357 }
358
359 int
360 cd9660_write(f, start, size, resid)
361 struct open_file *f;
362 void *start;
363 size_t size;
364 size_t *resid;
365 {
366 return EROFS;
367 }
368
369 off_t
370 cd9660_seek(f, offset, where)
371 struct open_file *f;
372 off_t offset;
373 int where;
374 {
375 struct file *fp = (struct file *)f->f_fsdata;
376
377 switch (where) {
378 case SEEK_SET:
379 fp->off = offset;
380 break;
381 case SEEK_CUR:
382 fp->off += offset;
383 break;
384 case SEEK_END:
385 fp->off = fp->size - offset;
386 break;
387 default:
388 return -1;
389 }
390 return fp->off;
391 }
392
393 int
394 cd9660_stat(f, sb)
395 struct open_file *f;
396 struct stat *sb;
397 {
398 struct file *fp = (struct file *)f->f_fsdata;
399
400 /* only importatn stuff */
401 sb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
402 sb->st_uid = sb->st_gid = 0;
403 sb->st_size = fp->size;
404 return 0;
405 }
406