[BACK]Return to cd9660.c CVS log [TXT][DIR] Up to [local] / sys / lib / libsa

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