The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/libsa/cd9660.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1095cb054ee1f64b06da52eb098e40a1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.