14a5d661aSToomas Soome /* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ 24a5d661aSToomas Soome 34a5d661aSToomas Soome /* 44a5d661aSToomas Soome * Copyright (C) 1996 Wolfgang Solfrank. 54a5d661aSToomas Soome * Copyright (C) 1996 TooLs GmbH. 64a5d661aSToomas Soome * All rights reserved. 74a5d661aSToomas Soome * 84a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 94a5d661aSToomas Soome * modification, are permitted provided that the following conditions 104a5d661aSToomas Soome * are met: 114a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 124a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 134a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 144a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 154a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 164a5d661aSToomas Soome * 3. All advertising materials mentioning features or use of this software 174a5d661aSToomas Soome * must display the following acknowledgement: 184a5d661aSToomas Soome * This product includes software developed by TooLs GmbH. 194a5d661aSToomas Soome * 4. The name of TooLs GmbH may not be used to endorse or promote products 204a5d661aSToomas Soome * derived from this software without specific prior written permission. 214a5d661aSToomas Soome * 224a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 234a5d661aSToomas Soome * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 244a5d661aSToomas Soome * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 254a5d661aSToomas Soome * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 264a5d661aSToomas Soome * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 274a5d661aSToomas Soome * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 284a5d661aSToomas Soome * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 294a5d661aSToomas Soome * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 304a5d661aSToomas Soome * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 314a5d661aSToomas Soome * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 324a5d661aSToomas Soome */ 334a5d661aSToomas Soome 344a5d661aSToomas Soome #include <sys/cdefs.h> 354a5d661aSToomas Soome __FBSDID("$FreeBSD$"); 364a5d661aSToomas Soome 374a5d661aSToomas Soome /* 384a5d661aSToomas Soome * Stand-alone ISO9660 file reading package. 394a5d661aSToomas Soome * 404a5d661aSToomas Soome * Note: This doesn't support Rock Ridge extensions, extended attributes, 414a5d661aSToomas Soome * blocksizes other than 2048 bytes, multi-extent files, etc. 424a5d661aSToomas Soome */ 434a5d661aSToomas Soome #include <sys/param.h> 444a5d661aSToomas Soome #include <string.h> 454a5d661aSToomas Soome #include <sys/dirent.h> 464a5d661aSToomas Soome #include <isofs/cd9660/iso.h> 474a5d661aSToomas Soome #include <isofs/cd9660/cd9660_rrip.h> 484a5d661aSToomas Soome 494a5d661aSToomas Soome #include "stand.h" 504a5d661aSToomas Soome 514a5d661aSToomas Soome #define SUSP_CONTINUATION "CE" 524a5d661aSToomas Soome #define SUSP_PRESENT "SP" 534a5d661aSToomas Soome #define SUSP_STOP "ST" 544a5d661aSToomas Soome #define SUSP_EXTREF "ER" 554a5d661aSToomas Soome #define RRIP_NAME "NM" 564a5d661aSToomas Soome 574a5d661aSToomas Soome typedef struct { 584a5d661aSToomas Soome ISO_SUSP_HEADER h; 594a5d661aSToomas Soome u_char signature [ISODCL ( 5, 6)]; 604a5d661aSToomas Soome u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 614a5d661aSToomas Soome } ISO_SUSP_PRESENT; 624a5d661aSToomas Soome 634a5d661aSToomas Soome static int buf_read_file(struct open_file *f, char **buf_p, 644a5d661aSToomas Soome size_t *size_p); 654a5d661aSToomas Soome static int cd9660_open(const char *path, struct open_file *f); 664a5d661aSToomas Soome static int cd9660_close(struct open_file *f); 674a5d661aSToomas Soome static int cd9660_read(struct open_file *f, void *buf, size_t size, 684a5d661aSToomas Soome size_t *resid); 694a5d661aSToomas Soome static int cd9660_write(struct open_file *f, void *buf, size_t size, 704a5d661aSToomas Soome size_t *resid); 714a5d661aSToomas Soome static off_t cd9660_seek(struct open_file *f, off_t offset, int where); 724a5d661aSToomas Soome static int cd9660_stat(struct open_file *f, struct stat *sb); 734a5d661aSToomas Soome static int cd9660_readdir(struct open_file *f, struct dirent *d); 744a5d661aSToomas Soome static int dirmatch(struct open_file *f, const char *path, 754a5d661aSToomas Soome struct iso_directory_record *dp, int use_rrip, int lenskip); 764a5d661aSToomas Soome static int rrip_check(struct open_file *f, struct iso_directory_record *dp, 774a5d661aSToomas Soome int *lenskip); 784a5d661aSToomas Soome static char *rrip_lookup_name(struct open_file *f, 794a5d661aSToomas Soome struct iso_directory_record *dp, int lenskip, size_t *len); 804a5d661aSToomas Soome static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, 814a5d661aSToomas Soome const char *identifier, struct iso_directory_record *dp, 824a5d661aSToomas Soome int lenskip); 834a5d661aSToomas Soome 844a5d661aSToomas Soome struct fs_ops cd9660_fsops = { 854a5d661aSToomas Soome "cd9660", 864a5d661aSToomas Soome cd9660_open, 874a5d661aSToomas Soome cd9660_close, 884a5d661aSToomas Soome cd9660_read, 894a5d661aSToomas Soome cd9660_write, 904a5d661aSToomas Soome cd9660_seek, 914a5d661aSToomas Soome cd9660_stat, 924a5d661aSToomas Soome cd9660_readdir 934a5d661aSToomas Soome }; 944a5d661aSToomas Soome 954a5d661aSToomas Soome #define F_ISDIR 0x0001 /* Directory */ 964a5d661aSToomas Soome #define F_ROOTDIR 0x0002 /* Root directory */ 974a5d661aSToomas Soome #define F_RR 0x0004 /* Rock Ridge on this volume */ 984a5d661aSToomas Soome 994a5d661aSToomas Soome struct file { 1004a5d661aSToomas Soome int f_flags; /* file flags */ 1014a5d661aSToomas Soome off_t f_off; /* Current offset within file */ 1024a5d661aSToomas Soome daddr_t f_bno; /* Starting block number */ 1034a5d661aSToomas Soome off_t f_size; /* Size of file */ 1044a5d661aSToomas Soome daddr_t f_buf_blkno; /* block number of data block */ 1054a5d661aSToomas Soome char *f_buf; /* buffer for data block */ 1064a5d661aSToomas Soome int f_susp_skip; /* len_skip for SUSP records */ 1074a5d661aSToomas Soome }; 1084a5d661aSToomas Soome 1094a5d661aSToomas Soome struct ptable_ent { 1104a5d661aSToomas Soome char namlen [ISODCL( 1, 1)]; /* 711 */ 1114a5d661aSToomas Soome char extlen [ISODCL( 2, 2)]; /* 711 */ 1124a5d661aSToomas Soome char block [ISODCL( 3, 6)]; /* 732 */ 1134a5d661aSToomas Soome char parent [ISODCL( 7, 8)]; /* 722 */ 1144a5d661aSToomas Soome char name [1]; 1154a5d661aSToomas Soome }; 1164a5d661aSToomas Soome #define PTFIXSZ 8 1174a5d661aSToomas Soome #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 1184a5d661aSToomas Soome 1194a5d661aSToomas Soome #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 1204a5d661aSToomas Soome 1214a5d661aSToomas Soome static ISO_SUSP_HEADER * 1224a5d661aSToomas Soome susp_lookup_record(struct open_file *f, const char *identifier, 1234a5d661aSToomas Soome struct iso_directory_record *dp, int lenskip) 1244a5d661aSToomas Soome { 1254a5d661aSToomas Soome static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 1264a5d661aSToomas Soome ISO_SUSP_HEADER *sh; 1274a5d661aSToomas Soome ISO_RRIP_CONT *shc; 1284a5d661aSToomas Soome char *p, *end; 1294a5d661aSToomas Soome int error; 1304a5d661aSToomas Soome size_t read; 1314a5d661aSToomas Soome 1324a5d661aSToomas Soome p = dp->name + isonum_711(dp->name_len) + lenskip; 1334a5d661aSToomas Soome /* Names of even length have a padding byte after the name. */ 1344a5d661aSToomas Soome if ((isonum_711(dp->name_len) & 1) == 0) 1354a5d661aSToomas Soome p++; 1364a5d661aSToomas Soome end = (char *)dp + isonum_711(dp->length); 1374a5d661aSToomas Soome while (p + 3 < end) { 1384a5d661aSToomas Soome sh = (ISO_SUSP_HEADER *)p; 1394a5d661aSToomas Soome if (bcmp(sh->type, identifier, 2) == 0) 1404a5d661aSToomas Soome return (sh); 1414a5d661aSToomas Soome if (bcmp(sh->type, SUSP_STOP, 2) == 0) 1424a5d661aSToomas Soome return (NULL); 1434a5d661aSToomas Soome if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 1444a5d661aSToomas Soome shc = (ISO_RRIP_CONT *)sh; 1454a5d661aSToomas Soome error = f->f_dev->dv_strategy(f->f_devdata, F_READ, 146*976852c7SToomas Soome cdb2devb(isonum_733(shc->location)), 1474a5d661aSToomas Soome ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); 1484a5d661aSToomas Soome 1494a5d661aSToomas Soome /* Bail if it fails. */ 1504a5d661aSToomas Soome if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) 1514a5d661aSToomas Soome return (NULL); 1524a5d661aSToomas Soome p = susp_buffer + isonum_733(shc->offset); 1534a5d661aSToomas Soome end = p + isonum_733(shc->length); 1544a5d661aSToomas Soome } else { 1554a5d661aSToomas Soome /* Ignore this record and skip to the next. */ 1564a5d661aSToomas Soome p += isonum_711(sh->length); 1574a5d661aSToomas Soome 1584a5d661aSToomas Soome /* Avoid infinite loops with corrupted file systems */ 1594a5d661aSToomas Soome if (isonum_711(sh->length) == 0) 1604a5d661aSToomas Soome return (NULL); 1614a5d661aSToomas Soome } 1624a5d661aSToomas Soome } 1634a5d661aSToomas Soome return (NULL); 1644a5d661aSToomas Soome } 1654a5d661aSToomas Soome 1664a5d661aSToomas Soome static char * 1674a5d661aSToomas Soome rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, 1684a5d661aSToomas Soome int lenskip, size_t *len) 1694a5d661aSToomas Soome { 1704a5d661aSToomas Soome ISO_RRIP_ALTNAME *p; 1714a5d661aSToomas Soome 1724a5d661aSToomas Soome if (len == NULL) 1734a5d661aSToomas Soome return (NULL); 1744a5d661aSToomas Soome 1754a5d661aSToomas Soome p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); 1764a5d661aSToomas Soome if (p == NULL) 1774a5d661aSToomas Soome return (NULL); 1784a5d661aSToomas Soome switch (*p->flags) { 1794a5d661aSToomas Soome case ISO_SUSP_CFLAG_CURRENT: 1804a5d661aSToomas Soome *len = 1; 1814a5d661aSToomas Soome return ("."); 1824a5d661aSToomas Soome case ISO_SUSP_CFLAG_PARENT: 1834a5d661aSToomas Soome *len = 2; 1844a5d661aSToomas Soome return (".."); 1854a5d661aSToomas Soome case 0: 1864a5d661aSToomas Soome *len = isonum_711(p->h.length) - 5; 1874a5d661aSToomas Soome return ((char *)p + 5); 1884a5d661aSToomas Soome default: 1894a5d661aSToomas Soome /* 1904a5d661aSToomas Soome * We don't handle hostnames or continued names as they are 1914a5d661aSToomas Soome * too hard, so just bail and use the default name. 1924a5d661aSToomas Soome */ 1934a5d661aSToomas Soome return (NULL); 1944a5d661aSToomas Soome } 1954a5d661aSToomas Soome } 1964a5d661aSToomas Soome 1974a5d661aSToomas Soome static int 1984a5d661aSToomas Soome rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) 1994a5d661aSToomas Soome { 2004a5d661aSToomas Soome ISO_SUSP_PRESENT *sp; 2014a5d661aSToomas Soome ISO_RRIP_EXTREF *er; 2024a5d661aSToomas Soome char *p; 2034a5d661aSToomas Soome 2044a5d661aSToomas Soome /* First, see if we can find a SP field. */ 2054a5d661aSToomas Soome p = dp->name + isonum_711(dp->name_len); 2064a5d661aSToomas Soome if (p > (char *)dp + isonum_711(dp->length)) 2074a5d661aSToomas Soome return (0); 2084a5d661aSToomas Soome sp = (ISO_SUSP_PRESENT *)p; 2094a5d661aSToomas Soome if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) 2104a5d661aSToomas Soome return (0); 2114a5d661aSToomas Soome if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) 2124a5d661aSToomas Soome return (0); 2134a5d661aSToomas Soome if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) 2144a5d661aSToomas Soome return (0); 2154a5d661aSToomas Soome *lenskip = isonum_711(sp->len_skp); 2164a5d661aSToomas Soome 2174a5d661aSToomas Soome /* 2184a5d661aSToomas Soome * Now look for an ER field. If RRIP is present, then there must 2194a5d661aSToomas Soome * be at least one of these. It would be more pedantic to walk 2204a5d661aSToomas Soome * through the list of fields looking for a Rock Ridge ER field. 2214a5d661aSToomas Soome */ 2224a5d661aSToomas Soome er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); 2234a5d661aSToomas Soome if (er == NULL) 2244a5d661aSToomas Soome return (0); 2254a5d661aSToomas Soome return (1); 2264a5d661aSToomas Soome } 2274a5d661aSToomas Soome 2284a5d661aSToomas Soome static int 2294a5d661aSToomas Soome dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, 2304a5d661aSToomas Soome int use_rrip, int lenskip) 2314a5d661aSToomas Soome { 2324a5d661aSToomas Soome size_t len; 2334a5d661aSToomas Soome char *cp; 2344a5d661aSToomas Soome int i, icase; 2354a5d661aSToomas Soome 2364a5d661aSToomas Soome if (use_rrip) 2374a5d661aSToomas Soome cp = rrip_lookup_name(f, dp, lenskip, &len); 2384a5d661aSToomas Soome else 2394a5d661aSToomas Soome cp = NULL; 2404a5d661aSToomas Soome if (cp == NULL) { 2414a5d661aSToomas Soome len = isonum_711(dp->name_len); 2424a5d661aSToomas Soome cp = dp->name; 2434a5d661aSToomas Soome icase = 1; 2444a5d661aSToomas Soome } else 2454a5d661aSToomas Soome icase = 0; 2464a5d661aSToomas Soome for (i = len; --i >= 0; path++, cp++) { 2474a5d661aSToomas Soome if (!*path || *path == '/') 2484a5d661aSToomas Soome break; 2494a5d661aSToomas Soome if (*path == *cp) 2504a5d661aSToomas Soome continue; 2514a5d661aSToomas Soome if (!icase && toupper(*path) == *cp) 2524a5d661aSToomas Soome continue; 2534a5d661aSToomas Soome return 0; 2544a5d661aSToomas Soome } 2554a5d661aSToomas Soome if (*path && *path != '/') 2564a5d661aSToomas Soome return 0; 2574a5d661aSToomas Soome /* 2584a5d661aSToomas Soome * Allow stripping of trailing dots and the version number. 2594a5d661aSToomas Soome * Note that this will find the first instead of the last version 2604a5d661aSToomas Soome * of a file. 2614a5d661aSToomas Soome */ 2624a5d661aSToomas Soome if (i >= 0 && (*cp == ';' || *cp == '.')) { 2634a5d661aSToomas Soome /* This is to prevent matching of numeric extensions */ 2644a5d661aSToomas Soome if (*cp == '.' && cp[1] != ';') 2654a5d661aSToomas Soome return 0; 2664a5d661aSToomas Soome while (--i >= 0) 2674a5d661aSToomas Soome if (*++cp != ';' && (*cp < '0' || *cp > '9')) 2684a5d661aSToomas Soome return 0; 2694a5d661aSToomas Soome } 2704a5d661aSToomas Soome return 1; 2714a5d661aSToomas Soome } 2724a5d661aSToomas Soome 2734a5d661aSToomas Soome static int 2744a5d661aSToomas Soome cd9660_open(const char *path, struct open_file *f) 2754a5d661aSToomas Soome { 276830d404aSToomas Soome struct file *fp = NULL; 2774a5d661aSToomas Soome void *buf; 2784a5d661aSToomas Soome struct iso_primary_descriptor *vd; 2794a5d661aSToomas Soome size_t buf_size, read, dsize, off; 2804a5d661aSToomas Soome daddr_t bno, boff; 2814a5d661aSToomas Soome struct iso_directory_record rec; 282830d404aSToomas Soome struct iso_directory_record *dp = NULL; 2834a5d661aSToomas Soome int rc, first, use_rrip, lenskip; 2844a5d661aSToomas Soome 2854a5d661aSToomas Soome /* First find the volume descriptor */ 2864a5d661aSToomas Soome buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 2874a5d661aSToomas Soome vd = buf; 2884a5d661aSToomas Soome for (bno = 16;; bno++) { 2894a5d661aSToomas Soome twiddle(1); 2904a5d661aSToomas Soome rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 291*976852c7SToomas Soome ISO_DEFAULT_BLOCK_SIZE, buf, &read); 2924a5d661aSToomas Soome if (rc) 2934a5d661aSToomas Soome goto out; 2944a5d661aSToomas Soome if (read != ISO_DEFAULT_BLOCK_SIZE) { 2954a5d661aSToomas Soome rc = EIO; 2964a5d661aSToomas Soome goto out; 2974a5d661aSToomas Soome } 2984a5d661aSToomas Soome rc = EINVAL; 2994a5d661aSToomas Soome if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 3004a5d661aSToomas Soome goto out; 3014a5d661aSToomas Soome if (isonum_711(vd->type) == ISO_VD_END) 3024a5d661aSToomas Soome goto out; 3034a5d661aSToomas Soome if (isonum_711(vd->type) == ISO_VD_PRIMARY) 3044a5d661aSToomas Soome break; 3054a5d661aSToomas Soome } 3064a5d661aSToomas Soome if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 3074a5d661aSToomas Soome goto out; 3084a5d661aSToomas Soome 3094a5d661aSToomas Soome rec = *(struct iso_directory_record *) vd->root_directory_record; 3104a5d661aSToomas Soome if (*path == '/') path++; /* eat leading '/' */ 3114a5d661aSToomas Soome 3124a5d661aSToomas Soome first = 1; 3134a5d661aSToomas Soome use_rrip = 0; 3144a5d661aSToomas Soome while (*path) { 3154a5d661aSToomas Soome bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 3164a5d661aSToomas Soome dsize = isonum_733(rec.size); 3174a5d661aSToomas Soome off = 0; 3184a5d661aSToomas Soome boff = 0; 3194a5d661aSToomas Soome 3204a5d661aSToomas Soome while (off < dsize) { 3214a5d661aSToomas Soome if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 3224a5d661aSToomas Soome twiddle(1); 3234a5d661aSToomas Soome rc = f->f_dev->dv_strategy 3244a5d661aSToomas Soome (f->f_devdata, F_READ, 3254a5d661aSToomas Soome cdb2devb(bno + boff), 326*976852c7SToomas Soome ISO_DEFAULT_BLOCK_SIZE, 3274a5d661aSToomas Soome buf, &read); 3284a5d661aSToomas Soome if (rc) 3294a5d661aSToomas Soome goto out; 3304a5d661aSToomas Soome if (read != ISO_DEFAULT_BLOCK_SIZE) { 3314a5d661aSToomas Soome rc = EIO; 3324a5d661aSToomas Soome goto out; 3334a5d661aSToomas Soome } 3344a5d661aSToomas Soome boff++; 3354a5d661aSToomas Soome dp = (struct iso_directory_record *) buf; 3364a5d661aSToomas Soome } 3374a5d661aSToomas Soome if (isonum_711(dp->length) == 0) { 3384a5d661aSToomas Soome /* skip to next block, if any */ 3394a5d661aSToomas Soome off = boff * ISO_DEFAULT_BLOCK_SIZE; 3404a5d661aSToomas Soome continue; 3414a5d661aSToomas Soome } 3424a5d661aSToomas Soome 3434a5d661aSToomas Soome /* See if RRIP is in use. */ 3444a5d661aSToomas Soome if (first) 3454a5d661aSToomas Soome use_rrip = rrip_check(f, dp, &lenskip); 3464a5d661aSToomas Soome 3474a5d661aSToomas Soome if (dirmatch(f, path, dp, use_rrip, 3484a5d661aSToomas Soome first ? 0 : lenskip)) { 3494a5d661aSToomas Soome first = 0; 3504a5d661aSToomas Soome break; 3514a5d661aSToomas Soome } else 3524a5d661aSToomas Soome first = 0; 3534a5d661aSToomas Soome 3544a5d661aSToomas Soome dp = (struct iso_directory_record *) 3554a5d661aSToomas Soome ((char *) dp + isonum_711(dp->length)); 356dc3bcc54SToomas Soome /* If the new block has zero length, it is padding. */ 357dc3bcc54SToomas Soome if (isonum_711(dp->length) == 0) { 358dc3bcc54SToomas Soome /* Skip to next block, if any. */ 359dc3bcc54SToomas Soome off = boff * ISO_DEFAULT_BLOCK_SIZE; 360dc3bcc54SToomas Soome continue; 361dc3bcc54SToomas Soome } 3624a5d661aSToomas Soome off += isonum_711(dp->length); 3634a5d661aSToomas Soome } 3644a5d661aSToomas Soome if (off >= dsize) { 3654a5d661aSToomas Soome rc = ENOENT; 3664a5d661aSToomas Soome goto out; 3674a5d661aSToomas Soome } 3684a5d661aSToomas Soome 3694a5d661aSToomas Soome rec = *dp; 3704a5d661aSToomas Soome while (*path && *path != '/') /* look for next component */ 3714a5d661aSToomas Soome path++; 3724a5d661aSToomas Soome if (*path) path++; /* skip '/' */ 3734a5d661aSToomas Soome } 3744a5d661aSToomas Soome 3754a5d661aSToomas Soome /* allocate file system specific data structure */ 3764a5d661aSToomas Soome fp = malloc(sizeof(struct file)); 3774a5d661aSToomas Soome bzero(fp, sizeof(struct file)); 3784a5d661aSToomas Soome f->f_fsdata = (void *)fp; 3794a5d661aSToomas Soome 3804a5d661aSToomas Soome if ((isonum_711(rec.flags) & 2) != 0) { 3814a5d661aSToomas Soome fp->f_flags = F_ISDIR; 3824a5d661aSToomas Soome } 3834a5d661aSToomas Soome if (first) { 3844a5d661aSToomas Soome fp->f_flags |= F_ROOTDIR; 3854a5d661aSToomas Soome 3864a5d661aSToomas Soome /* Check for Rock Ridge since we didn't in the loop above. */ 3874a5d661aSToomas Soome bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 3884a5d661aSToomas Soome twiddle(1); 3894a5d661aSToomas Soome rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 390*976852c7SToomas Soome ISO_DEFAULT_BLOCK_SIZE, buf, &read); 3914a5d661aSToomas Soome if (rc) 3924a5d661aSToomas Soome goto out; 3934a5d661aSToomas Soome if (read != ISO_DEFAULT_BLOCK_SIZE) { 3944a5d661aSToomas Soome rc = EIO; 3954a5d661aSToomas Soome goto out; 3964a5d661aSToomas Soome } 3974a5d661aSToomas Soome dp = (struct iso_directory_record *)buf; 3984a5d661aSToomas Soome use_rrip = rrip_check(f, dp, &lenskip); 3994a5d661aSToomas Soome } 4004a5d661aSToomas Soome if (use_rrip) { 4014a5d661aSToomas Soome fp->f_flags |= F_RR; 4024a5d661aSToomas Soome fp->f_susp_skip = lenskip; 4034a5d661aSToomas Soome } 4044a5d661aSToomas Soome fp->f_off = 0; 4054a5d661aSToomas Soome fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 4064a5d661aSToomas Soome fp->f_size = isonum_733(rec.size); 4074a5d661aSToomas Soome free(buf); 4084a5d661aSToomas Soome 4094a5d661aSToomas Soome return 0; 4104a5d661aSToomas Soome 4114a5d661aSToomas Soome out: 4124a5d661aSToomas Soome if (fp) 4134a5d661aSToomas Soome free(fp); 4144a5d661aSToomas Soome free(buf); 4154a5d661aSToomas Soome 4164a5d661aSToomas Soome return rc; 4174a5d661aSToomas Soome } 4184a5d661aSToomas Soome 4194a5d661aSToomas Soome static int 4204a5d661aSToomas Soome cd9660_close(struct open_file *f) 4214a5d661aSToomas Soome { 4224a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 4234a5d661aSToomas Soome 424830d404aSToomas Soome f->f_fsdata = NULL; 4254a5d661aSToomas Soome free(fp); 4264a5d661aSToomas Soome 4274a5d661aSToomas Soome return 0; 4284a5d661aSToomas Soome } 4294a5d661aSToomas Soome 4304a5d661aSToomas Soome static int 4314a5d661aSToomas Soome buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 4324a5d661aSToomas Soome { 4334a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 4344a5d661aSToomas Soome daddr_t blkno, blkoff; 4354a5d661aSToomas Soome int rc = 0; 4364a5d661aSToomas Soome size_t read; 4374a5d661aSToomas Soome 4384a5d661aSToomas Soome blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; 4394a5d661aSToomas Soome blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; 4404a5d661aSToomas Soome 4414a5d661aSToomas Soome if (blkno != fp->f_buf_blkno) { 4424a5d661aSToomas Soome if (fp->f_buf == (char *)0) 4434a5d661aSToomas Soome fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); 4444a5d661aSToomas Soome 4454a5d661aSToomas Soome twiddle(16); 4464a5d661aSToomas Soome rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 447*976852c7SToomas Soome cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, 4484a5d661aSToomas Soome fp->f_buf, &read); 4494a5d661aSToomas Soome if (rc) 4504a5d661aSToomas Soome return (rc); 4514a5d661aSToomas Soome if (read != ISO_DEFAULT_BLOCK_SIZE) 4524a5d661aSToomas Soome return (EIO); 4534a5d661aSToomas Soome 4544a5d661aSToomas Soome fp->f_buf_blkno = blkno; 4554a5d661aSToomas Soome } 4564a5d661aSToomas Soome 4574a5d661aSToomas Soome *buf_p = fp->f_buf + blkoff; 4584a5d661aSToomas Soome *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; 4594a5d661aSToomas Soome 4604a5d661aSToomas Soome if (*size_p > fp->f_size - fp->f_off) 4614a5d661aSToomas Soome *size_p = fp->f_size - fp->f_off; 4624a5d661aSToomas Soome return (rc); 4634a5d661aSToomas Soome } 4644a5d661aSToomas Soome 4654a5d661aSToomas Soome static int 4664a5d661aSToomas Soome cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) 4674a5d661aSToomas Soome { 4684a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 4694a5d661aSToomas Soome char *buf, *addr; 4704a5d661aSToomas Soome size_t buf_size, csize; 4714a5d661aSToomas Soome int rc = 0; 4724a5d661aSToomas Soome 4734a5d661aSToomas Soome addr = start; 4744a5d661aSToomas Soome while (size) { 4754a5d661aSToomas Soome if (fp->f_off < 0 || fp->f_off >= fp->f_size) 4764a5d661aSToomas Soome break; 4774a5d661aSToomas Soome 4784a5d661aSToomas Soome rc = buf_read_file(f, &buf, &buf_size); 4794a5d661aSToomas Soome if (rc) 4804a5d661aSToomas Soome break; 4814a5d661aSToomas Soome 4824a5d661aSToomas Soome csize = size > buf_size ? buf_size : size; 4834a5d661aSToomas Soome bcopy(buf, addr, csize); 4844a5d661aSToomas Soome 4854a5d661aSToomas Soome fp->f_off += csize; 4864a5d661aSToomas Soome addr += csize; 4874a5d661aSToomas Soome size -= csize; 4884a5d661aSToomas Soome } 4894a5d661aSToomas Soome if (resid) 4904a5d661aSToomas Soome *resid = size; 4914a5d661aSToomas Soome return (rc); 4924a5d661aSToomas Soome } 4934a5d661aSToomas Soome 4944a5d661aSToomas Soome static int 4954a5d661aSToomas Soome cd9660_readdir(struct open_file *f, struct dirent *d) 4964a5d661aSToomas Soome { 4974a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 4984a5d661aSToomas Soome struct iso_directory_record *ep; 4994a5d661aSToomas Soome size_t buf_size, reclen, namelen; 5004a5d661aSToomas Soome int error = 0; 5014a5d661aSToomas Soome int lenskip; 5024a5d661aSToomas Soome char *buf, *name; 5034a5d661aSToomas Soome 5044a5d661aSToomas Soome again: 5054a5d661aSToomas Soome if (fp->f_off >= fp->f_size) 5064a5d661aSToomas Soome return (ENOENT); 5074a5d661aSToomas Soome error = buf_read_file(f, &buf, &buf_size); 5084a5d661aSToomas Soome if (error) 5094a5d661aSToomas Soome return (error); 5104a5d661aSToomas Soome ep = (struct iso_directory_record *)buf; 5114a5d661aSToomas Soome 5124a5d661aSToomas Soome if (isonum_711(ep->length) == 0) { 5134a5d661aSToomas Soome daddr_t blkno; 5144a5d661aSToomas Soome 5154a5d661aSToomas Soome /* skip to next block, if any */ 5164a5d661aSToomas Soome blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; 5174a5d661aSToomas Soome fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; 5184a5d661aSToomas Soome goto again; 5194a5d661aSToomas Soome } 5204a5d661aSToomas Soome 5214a5d661aSToomas Soome if (fp->f_flags & F_RR) { 5224a5d661aSToomas Soome if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) 5234a5d661aSToomas Soome lenskip = 0; 5244a5d661aSToomas Soome else 5254a5d661aSToomas Soome lenskip = fp->f_susp_skip; 5264a5d661aSToomas Soome name = rrip_lookup_name(f, ep, lenskip, &namelen); 5274a5d661aSToomas Soome } else 5284a5d661aSToomas Soome name = NULL; 5294a5d661aSToomas Soome if (name == NULL) { 5304a5d661aSToomas Soome namelen = isonum_711(ep->name_len); 5314a5d661aSToomas Soome name = ep->name; 5324a5d661aSToomas Soome if (namelen == 1) { 5334a5d661aSToomas Soome if (ep->name[0] == 0) 5344a5d661aSToomas Soome name = "."; 5354a5d661aSToomas Soome else if (ep->name[0] == 1) { 5364a5d661aSToomas Soome namelen = 2; 5374a5d661aSToomas Soome name = ".."; 5384a5d661aSToomas Soome } 5394a5d661aSToomas Soome } 5404a5d661aSToomas Soome } 5414a5d661aSToomas Soome reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; 5424a5d661aSToomas Soome reclen = (reclen + 3) & ~3; 5434a5d661aSToomas Soome 5444a5d661aSToomas Soome d->d_fileno = isonum_733(ep->extent); 5454a5d661aSToomas Soome d->d_reclen = reclen; 5464a5d661aSToomas Soome if (isonum_711(ep->flags) & 2) 5474a5d661aSToomas Soome d->d_type = DT_DIR; 5484a5d661aSToomas Soome else 5494a5d661aSToomas Soome d->d_type = DT_REG; 5504a5d661aSToomas Soome d->d_namlen = namelen; 5514a5d661aSToomas Soome 5524a5d661aSToomas Soome bcopy(name, d->d_name, d->d_namlen); 5534a5d661aSToomas Soome d->d_name[d->d_namlen] = 0; 5544a5d661aSToomas Soome 5554a5d661aSToomas Soome fp->f_off += isonum_711(ep->length); 5564a5d661aSToomas Soome return (0); 5574a5d661aSToomas Soome } 5584a5d661aSToomas Soome 5594a5d661aSToomas Soome static int 5604a5d661aSToomas Soome cd9660_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused) 5614a5d661aSToomas Soome { 5624a5d661aSToomas Soome return EROFS; 5634a5d661aSToomas Soome } 5644a5d661aSToomas Soome 5654a5d661aSToomas Soome static off_t 5664a5d661aSToomas Soome cd9660_seek(struct open_file *f, off_t offset, int where) 5674a5d661aSToomas Soome { 5684a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 5694a5d661aSToomas Soome 5704a5d661aSToomas Soome switch (where) { 5714a5d661aSToomas Soome case SEEK_SET: 5724a5d661aSToomas Soome fp->f_off = offset; 5734a5d661aSToomas Soome break; 5744a5d661aSToomas Soome case SEEK_CUR: 5754a5d661aSToomas Soome fp->f_off += offset; 5764a5d661aSToomas Soome break; 5774a5d661aSToomas Soome case SEEK_END: 5784a5d661aSToomas Soome fp->f_off = fp->f_size - offset; 5794a5d661aSToomas Soome break; 5804a5d661aSToomas Soome default: 5814a5d661aSToomas Soome return -1; 5824a5d661aSToomas Soome } 5834a5d661aSToomas Soome return fp->f_off; 5844a5d661aSToomas Soome } 5854a5d661aSToomas Soome 5864a5d661aSToomas Soome static int 5874a5d661aSToomas Soome cd9660_stat(struct open_file *f, struct stat *sb) 5884a5d661aSToomas Soome { 5894a5d661aSToomas Soome struct file *fp = (struct file *)f->f_fsdata; 5904a5d661aSToomas Soome 5914a5d661aSToomas Soome /* only important stuff */ 5924a5d661aSToomas Soome sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; 5934a5d661aSToomas Soome if (fp->f_flags & F_ISDIR) 5944a5d661aSToomas Soome sb->st_mode |= S_IFDIR; 5954a5d661aSToomas Soome else 5964a5d661aSToomas Soome sb->st_mode |= S_IFREG; 5974a5d661aSToomas Soome sb->st_uid = sb->st_gid = 0; 5984a5d661aSToomas Soome sb->st_size = fp->f_size; 5994a5d661aSToomas Soome return 0; 6004a5d661aSToomas Soome } 601