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