root/lib/libsa/cd9660.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pnmatch
  2. dirmatch
  3. cd9660_open
  4. cd9660_close
  5. cd9660_read
  6. cd9660_write
  7. cd9660_seek
  8. cd9660_stat
  9. cd9660_readdir

    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

/* [<][>][^][v][top][bottom][index][help] */