Annotation of sys/lib/libsa/cd9660.c, Revision 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