2 /* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */
5 * Copyright (C) 1996 Wolfgang Solfrank.
6 * Copyright (C) 1996 TooLs GmbH.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
36 * Stand-alone ISO9660 file reading package.
38 * Note: This doesn't support Rock Ridge extensions, extended attributes,
39 * blocksizes other than 2048 bytes, multi-extent files, etc.
41 #include <sys/param.h>
43 #include <sys/dirent.h>
44 #include <isofs/cd9660/iso.h>
48 static int cd9660_open(const char *path, struct open_file *f);
49 static int cd9660_close(struct open_file *f);
50 static int cd9660_read(struct open_file *f, void *buf, size_t size, size_t *resid);
51 static int cd9660_write(struct open_file *f, void *buf, size_t size, size_t *resid);
52 static off_t cd9660_seek(struct open_file *f, off_t offset, int where);
53 static int cd9660_stat(struct open_file *f, struct stat *sb);
55 struct fs_ops cd9660_fsops = {
56 "cd9660", cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, cd9660_stat
60 int isdir; /* nonzero if file is directory */
61 off_t off; /* Current offset within file */
62 daddr_t bno; /* Starting block number */
63 off_t size; /* Size of file */
67 char namlen [ISODCL( 1, 1)]; /* 711 */
68 char extlen [ISODCL( 2, 2)]; /* 711 */
69 char block [ISODCL( 3, 6)]; /* 732 */
70 char parent [ISODCL( 7, 8)]; /* 722 */
74 #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
76 #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
78 /* XXX these should be in the system headers */
83 return (*p << 8)|p[1];
90 return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
96 struct iso_directory_record *dp;
102 for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) {
103 if (!*path || *path == '/')
105 if (toupper(*path) == *cp)
109 if (*path && *path != '/')
112 * Allow stripping of trailing dots and the version number.
113 * Note that this will find the first instead of the last version
116 if (i >= 0 && (*cp == ';' || *cp == '.')) {
117 /* This is to prevent matching of numeric extensions */
118 if (*cp == '.' && cp[1] != ';')
121 if (*++cp != ';' && (*cp < '0' || *cp > '9'))
134 struct iso_primary_descriptor *vd;
135 size_t buf_size, read, dsize, off;
137 struct iso_directory_record rec;
138 struct iso_directory_record *dp = 0;
141 /* First find the volume descriptor */
142 buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE);
144 for (bno = 16;; bno++) {
146 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
147 ISO_DEFAULT_BLOCK_SIZE, buf, &read);
150 if (read != ISO_DEFAULT_BLOCK_SIZE) {
155 if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
157 if (isonum_711(vd->type) == ISO_VD_END)
159 if (isonum_711(vd->type) == ISO_VD_PRIMARY)
162 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
165 rec = *(struct iso_directory_record *) vd->root_directory_record;
166 if (*path == '/') path++; /* eat leading '/' */
169 bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
170 dsize = isonum_733(rec.size);
174 while (off < dsize) {
175 if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
177 rc = f->f_dev->dv_strategy
178 (f->f_devdata, F_READ,
179 cdb2devb(bno + boff),
180 ISO_DEFAULT_BLOCK_SIZE,
184 if (read != ISO_DEFAULT_BLOCK_SIZE) {
189 dp = (struct iso_directory_record *) buf;
191 if (isonum_711(dp->length) == 0) {
192 /* skip to next block, if any */
193 off = boff * ISO_DEFAULT_BLOCK_SIZE;
197 if (dirmatch(path, dp))
200 dp = (struct iso_directory_record *)
201 ((char *) dp + isonum_711(dp->length));
202 off += isonum_711(dp->length);
210 while (*path && *path != '/') /* look for next component */
212 if (*path) path++; /* skip '/' */
215 /* allocate file system specific data structure */
216 fp = malloc(sizeof(struct file));
217 bzero(fp, sizeof(struct file));
218 f->f_fsdata = (void *)fp;
220 fp->isdir = (isonum_711(rec.flags) & 2) != 0;
222 fp->bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
223 fp->size = isonum_733(rec.size);
240 struct file *fp = (struct file *)f->f_fsdata;
249 cd9660_readfile(f, start, size, resid)
255 struct file *fp = (struct file *)f->f_fsdata;
258 char buf[ISO_DEFAULT_BLOCK_SIZE];
263 if (fp->off < 0 || fp->off >= fp->size)
265 bno = fp->off / ISO_DEFAULT_BLOCK_SIZE + fp->bno;
266 if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1)
267 || size < ISO_DEFAULT_BLOCK_SIZE)
272 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
273 ISO_DEFAULT_BLOCK_SIZE, dp, &read);
276 if (read != ISO_DEFAULT_BLOCK_SIZE)
279 off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1);
280 if (read > off + size)
283 bcopy(buf + off, start, read);
288 start += ISO_DEFAULT_BLOCK_SIZE;
289 fp->off += ISO_DEFAULT_BLOCK_SIZE;
290 size -= ISO_DEFAULT_BLOCK_SIZE;
299 cd9660_readdir(f, start, size, resid)
305 struct file *fp = (struct file *)f->f_fsdata;
308 char buf[ISO_DEFAULT_BLOCK_SIZE];
310 struct dirent *lastdp;
311 struct iso_directory_record *ep = 0;
312 size_t read, off, reclen, namelen;
314 if (fp->off < 0 || fp->off >= fp->size)
316 boff = fp->off / ISO_DEFAULT_BLOCK_SIZE;
320 if (off % ISO_DEFAULT_BLOCK_SIZE) {
322 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
323 ISO_DEFAULT_BLOCK_SIZE, buf, &read);
326 if (read != ISO_DEFAULT_BLOCK_SIZE)
329 ep = (struct iso_directory_record *)
330 (buf + (off % ISO_DEFAULT_BLOCK_SIZE));
333 lastdp = dp = (struct dirent *) start;
335 dp->d_type = DT_UNKNOWN;
337 while (size && off < fp->size) {
338 if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
340 rc = f->f_dev->dv_strategy
341 (f->f_devdata, F_READ,
342 cdb2devb(bno + boff),
343 ISO_DEFAULT_BLOCK_SIZE,
347 if (read != ISO_DEFAULT_BLOCK_SIZE) {
352 ep = (struct iso_directory_record *) buf;
355 if (isonum_711(ep->length) == 0) {
356 /* skip to next block, if any */
357 off = boff * ISO_DEFAULT_BLOCK_SIZE;
361 namelen = isonum_711(ep->name_len);
362 if (namelen == 1 && ep->name[0] == 1)
364 reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1;
365 reclen = (reclen + 3) & ~3;
369 dp->d_fileno = isonum_733(ep->extent);
370 dp->d_reclen = reclen;
371 if (isonum_711(ep->flags) & 2)
375 dp->d_namlen = namelen;
376 if (isonum_711(ep->name_len) == 1 && ep->name[0] == 0)
377 strcpy(dp->d_name, ".");
378 else if (isonum_711(ep->name_len) == 1 && ep->name[0] == 1)
379 strcpy(dp->d_name, "..");
381 bcopy(ep->name, dp->d_name, dp->d_namlen);
382 dp->d_name[dp->d_namlen] = 0;
385 dp = (struct dirent *) ((char *) dp + dp->d_reclen);
387 ep = (struct iso_directory_record *)
388 ((char *) ep + isonum_711(ep->length));
389 off += isonum_711(ep->length);
393 lastdp->d_reclen += size;
400 cd9660_read(f, start, size, resid)
406 struct file *fp = (struct file *)f->f_fsdata;
409 return cd9660_readdir(f, start, size, resid);
411 return cd9660_readfile(f, start, size, resid);
415 cd9660_write(f, start, size, resid)
425 cd9660_seek(f, offset, where)
430 struct file *fp = (struct file *)f->f_fsdata;
440 fp->off = fp->size - offset;
453 struct file *fp = (struct file *)f->f_fsdata;
455 /* only important stuff */
456 sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
458 sb->st_mode |= S_IFDIR;
460 sb->st_mode |= S_IFREG;
461 sb->st_uid = sb->st_gid = 0;
462 sb->st_size = fp->size;