1*ca987d46SWarner Losh /* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ 2*ca987d46SWarner Losh 3*ca987d46SWarner Losh /* 4*ca987d46SWarner Losh * Copyright (C) 1996 Wolfgang Solfrank. 5*ca987d46SWarner Losh * Copyright (C) 1996 TooLs GmbH. 6*ca987d46SWarner Losh * All rights reserved. 7*ca987d46SWarner Losh * 8*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 9*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 10*ca987d46SWarner Losh * are met: 11*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 12*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 13*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 14*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 15*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 16*ca987d46SWarner Losh * 3. All advertising materials mentioning features or use of this software 17*ca987d46SWarner Losh * must display the following acknowledgement: 18*ca987d46SWarner Losh * This product includes software developed by TooLs GmbH. 19*ca987d46SWarner Losh * 4. The name of TooLs GmbH may not be used to endorse or promote products 20*ca987d46SWarner Losh * derived from this software without specific prior written permission. 21*ca987d46SWarner Losh * 22*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23*ca987d46SWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24*ca987d46SWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25*ca987d46SWarner Losh * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*ca987d46SWarner Losh * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27*ca987d46SWarner Losh * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28*ca987d46SWarner Losh * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29*ca987d46SWarner Losh * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30*ca987d46SWarner Losh * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31*ca987d46SWarner Losh * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*ca987d46SWarner Losh */ 33*ca987d46SWarner Losh 34*ca987d46SWarner Losh #include <sys/cdefs.h> 35*ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 36*ca987d46SWarner Losh 37*ca987d46SWarner Losh /* 38*ca987d46SWarner Losh * Stand-alone ISO9660 file reading package. 39*ca987d46SWarner Losh * 40*ca987d46SWarner Losh * Note: This doesn't support Rock Ridge extensions, extended attributes, 41*ca987d46SWarner Losh * blocksizes other than 2048 bytes, multi-extent files, etc. 42*ca987d46SWarner Losh */ 43*ca987d46SWarner Losh #include <sys/param.h> 44*ca987d46SWarner Losh #include <string.h> 45*ca987d46SWarner Losh #include <sys/dirent.h> 46*ca987d46SWarner Losh #include <isofs/cd9660/iso.h> 47*ca987d46SWarner Losh #include <isofs/cd9660/cd9660_rrip.h> 48*ca987d46SWarner Losh 49*ca987d46SWarner Losh #include "stand.h" 50*ca987d46SWarner Losh 51*ca987d46SWarner Losh #define SUSP_CONTINUATION "CE" 52*ca987d46SWarner Losh #define SUSP_PRESENT "SP" 53*ca987d46SWarner Losh #define SUSP_STOP "ST" 54*ca987d46SWarner Losh #define SUSP_EXTREF "ER" 55*ca987d46SWarner Losh #define RRIP_NAME "NM" 56*ca987d46SWarner Losh 57*ca987d46SWarner Losh typedef struct { 58*ca987d46SWarner Losh ISO_SUSP_HEADER h; 59*ca987d46SWarner Losh u_char signature [ISODCL ( 5, 6)]; 60*ca987d46SWarner Losh u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 61*ca987d46SWarner Losh } ISO_SUSP_PRESENT; 62*ca987d46SWarner Losh 63*ca987d46SWarner Losh static int buf_read_file(struct open_file *f, char **buf_p, 64*ca987d46SWarner Losh size_t *size_p); 65*ca987d46SWarner Losh static int cd9660_open(const char *path, struct open_file *f); 66*ca987d46SWarner Losh static int cd9660_close(struct open_file *f); 67*ca987d46SWarner Losh static int cd9660_read(struct open_file *f, void *buf, size_t size, 68*ca987d46SWarner Losh size_t *resid); 69*ca987d46SWarner Losh static int cd9660_write(struct open_file *f, void *buf, size_t size, 70*ca987d46SWarner Losh size_t *resid); 71*ca987d46SWarner Losh static off_t cd9660_seek(struct open_file *f, off_t offset, int where); 72*ca987d46SWarner Losh static int cd9660_stat(struct open_file *f, struct stat *sb); 73*ca987d46SWarner Losh static int cd9660_readdir(struct open_file *f, struct dirent *d); 74*ca987d46SWarner Losh static int dirmatch(struct open_file *f, const char *path, 75*ca987d46SWarner Losh struct iso_directory_record *dp, int use_rrip, int lenskip); 76*ca987d46SWarner Losh static int rrip_check(struct open_file *f, struct iso_directory_record *dp, 77*ca987d46SWarner Losh int *lenskip); 78*ca987d46SWarner Losh static char *rrip_lookup_name(struct open_file *f, 79*ca987d46SWarner Losh struct iso_directory_record *dp, int lenskip, size_t *len); 80*ca987d46SWarner Losh static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, 81*ca987d46SWarner Losh const char *identifier, struct iso_directory_record *dp, 82*ca987d46SWarner Losh int lenskip); 83*ca987d46SWarner Losh 84*ca987d46SWarner Losh struct fs_ops cd9660_fsops = { 85*ca987d46SWarner Losh "cd9660", 86*ca987d46SWarner Losh cd9660_open, 87*ca987d46SWarner Losh cd9660_close, 88*ca987d46SWarner Losh cd9660_read, 89*ca987d46SWarner Losh cd9660_write, 90*ca987d46SWarner Losh cd9660_seek, 91*ca987d46SWarner Losh cd9660_stat, 92*ca987d46SWarner Losh cd9660_readdir 93*ca987d46SWarner Losh }; 94*ca987d46SWarner Losh 95*ca987d46SWarner Losh #define F_ISDIR 0x0001 /* Directory */ 96*ca987d46SWarner Losh #define F_ROOTDIR 0x0002 /* Root directory */ 97*ca987d46SWarner Losh #define F_RR 0x0004 /* Rock Ridge on this volume */ 98*ca987d46SWarner Losh 99*ca987d46SWarner Losh struct file { 100*ca987d46SWarner Losh int f_flags; /* file flags */ 101*ca987d46SWarner Losh off_t f_off; /* Current offset within file */ 102*ca987d46SWarner Losh daddr_t f_bno; /* Starting block number */ 103*ca987d46SWarner Losh off_t f_size; /* Size of file */ 104*ca987d46SWarner Losh daddr_t f_buf_blkno; /* block number of data block */ 105*ca987d46SWarner Losh char *f_buf; /* buffer for data block */ 106*ca987d46SWarner Losh int f_susp_skip; /* len_skip for SUSP records */ 107*ca987d46SWarner Losh }; 108*ca987d46SWarner Losh 109*ca987d46SWarner Losh struct ptable_ent { 110*ca987d46SWarner Losh char namlen [ISODCL( 1, 1)]; /* 711 */ 111*ca987d46SWarner Losh char extlen [ISODCL( 2, 2)]; /* 711 */ 112*ca987d46SWarner Losh char block [ISODCL( 3, 6)]; /* 732 */ 113*ca987d46SWarner Losh char parent [ISODCL( 7, 8)]; /* 722 */ 114*ca987d46SWarner Losh char name [1]; 115*ca987d46SWarner Losh }; 116*ca987d46SWarner Losh #define PTFIXSZ 8 117*ca987d46SWarner Losh #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 118*ca987d46SWarner Losh 119*ca987d46SWarner Losh #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 120*ca987d46SWarner Losh 121*ca987d46SWarner Losh static ISO_SUSP_HEADER * 122*ca987d46SWarner Losh susp_lookup_record(struct open_file *f, const char *identifier, 123*ca987d46SWarner Losh struct iso_directory_record *dp, int lenskip) 124*ca987d46SWarner Losh { 125*ca987d46SWarner Losh static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 126*ca987d46SWarner Losh ISO_SUSP_HEADER *sh; 127*ca987d46SWarner Losh ISO_RRIP_CONT *shc; 128*ca987d46SWarner Losh char *p, *end; 129*ca987d46SWarner Losh int error; 130*ca987d46SWarner Losh size_t read; 131*ca987d46SWarner Losh 132*ca987d46SWarner Losh p = dp->name + isonum_711(dp->name_len) + lenskip; 133*ca987d46SWarner Losh /* Names of even length have a padding byte after the name. */ 134*ca987d46SWarner Losh if ((isonum_711(dp->name_len) & 1) == 0) 135*ca987d46SWarner Losh p++; 136*ca987d46SWarner Losh end = (char *)dp + isonum_711(dp->length); 137*ca987d46SWarner Losh while (p + 3 < end) { 138*ca987d46SWarner Losh sh = (ISO_SUSP_HEADER *)p; 139*ca987d46SWarner Losh if (bcmp(sh->type, identifier, 2) == 0) 140*ca987d46SWarner Losh return (sh); 141*ca987d46SWarner Losh if (bcmp(sh->type, SUSP_STOP, 2) == 0) 142*ca987d46SWarner Losh return (NULL); 143*ca987d46SWarner Losh if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 144*ca987d46SWarner Losh shc = (ISO_RRIP_CONT *)sh; 145*ca987d46SWarner Losh error = f->f_dev->dv_strategy(f->f_devdata, F_READ, 146*ca987d46SWarner Losh cdb2devb(isonum_733(shc->location)), 147*ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); 148*ca987d46SWarner Losh 149*ca987d46SWarner Losh /* Bail if it fails. */ 150*ca987d46SWarner Losh if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) 151*ca987d46SWarner Losh return (NULL); 152*ca987d46SWarner Losh p = susp_buffer + isonum_733(shc->offset); 153*ca987d46SWarner Losh end = p + isonum_733(shc->length); 154*ca987d46SWarner Losh } else { 155*ca987d46SWarner Losh /* Ignore this record and skip to the next. */ 156*ca987d46SWarner Losh p += isonum_711(sh->length); 157*ca987d46SWarner Losh 158*ca987d46SWarner Losh /* Avoid infinite loops with corrupted file systems */ 159*ca987d46SWarner Losh if (isonum_711(sh->length) == 0) 160*ca987d46SWarner Losh return (NULL); 161*ca987d46SWarner Losh } 162*ca987d46SWarner Losh } 163*ca987d46SWarner Losh return (NULL); 164*ca987d46SWarner Losh } 165*ca987d46SWarner Losh 166*ca987d46SWarner Losh static char * 167*ca987d46SWarner Losh rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, 168*ca987d46SWarner Losh int lenskip, size_t *len) 169*ca987d46SWarner Losh { 170*ca987d46SWarner Losh ISO_RRIP_ALTNAME *p; 171*ca987d46SWarner Losh 172*ca987d46SWarner Losh if (len == NULL) 173*ca987d46SWarner Losh return (NULL); 174*ca987d46SWarner Losh 175*ca987d46SWarner Losh p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); 176*ca987d46SWarner Losh if (p == NULL) 177*ca987d46SWarner Losh return (NULL); 178*ca987d46SWarner Losh switch (*p->flags) { 179*ca987d46SWarner Losh case ISO_SUSP_CFLAG_CURRENT: 180*ca987d46SWarner Losh *len = 1; 181*ca987d46SWarner Losh return ("."); 182*ca987d46SWarner Losh case ISO_SUSP_CFLAG_PARENT: 183*ca987d46SWarner Losh *len = 2; 184*ca987d46SWarner Losh return (".."); 185*ca987d46SWarner Losh case 0: 186*ca987d46SWarner Losh *len = isonum_711(p->h.length) - 5; 187*ca987d46SWarner Losh return ((char *)p + 5); 188*ca987d46SWarner Losh default: 189*ca987d46SWarner Losh /* 190*ca987d46SWarner Losh * We don't handle hostnames or continued names as they are 191*ca987d46SWarner Losh * too hard, so just bail and use the default name. 192*ca987d46SWarner Losh */ 193*ca987d46SWarner Losh return (NULL); 194*ca987d46SWarner Losh } 195*ca987d46SWarner Losh } 196*ca987d46SWarner Losh 197*ca987d46SWarner Losh static int 198*ca987d46SWarner Losh rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) 199*ca987d46SWarner Losh { 200*ca987d46SWarner Losh ISO_SUSP_PRESENT *sp; 201*ca987d46SWarner Losh ISO_RRIP_EXTREF *er; 202*ca987d46SWarner Losh char *p; 203*ca987d46SWarner Losh 204*ca987d46SWarner Losh /* First, see if we can find a SP field. */ 205*ca987d46SWarner Losh p = dp->name + isonum_711(dp->name_len); 206*ca987d46SWarner Losh if (p > (char *)dp + isonum_711(dp->length)) 207*ca987d46SWarner Losh return (0); 208*ca987d46SWarner Losh sp = (ISO_SUSP_PRESENT *)p; 209*ca987d46SWarner Losh if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) 210*ca987d46SWarner Losh return (0); 211*ca987d46SWarner Losh if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) 212*ca987d46SWarner Losh return (0); 213*ca987d46SWarner Losh if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) 214*ca987d46SWarner Losh return (0); 215*ca987d46SWarner Losh *lenskip = isonum_711(sp->len_skp); 216*ca987d46SWarner Losh 217*ca987d46SWarner Losh /* 218*ca987d46SWarner Losh * Now look for an ER field. If RRIP is present, then there must 219*ca987d46SWarner Losh * be at least one of these. It would be more pedantic to walk 220*ca987d46SWarner Losh * through the list of fields looking for a Rock Ridge ER field. 221*ca987d46SWarner Losh */ 222*ca987d46SWarner Losh er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); 223*ca987d46SWarner Losh if (er == NULL) 224*ca987d46SWarner Losh return (0); 225*ca987d46SWarner Losh return (1); 226*ca987d46SWarner Losh } 227*ca987d46SWarner Losh 228*ca987d46SWarner Losh static int 229*ca987d46SWarner Losh dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, 230*ca987d46SWarner Losh int use_rrip, int lenskip) 231*ca987d46SWarner Losh { 232*ca987d46SWarner Losh size_t len; 233*ca987d46SWarner Losh char *cp; 234*ca987d46SWarner Losh int i, icase; 235*ca987d46SWarner Losh 236*ca987d46SWarner Losh if (use_rrip) 237*ca987d46SWarner Losh cp = rrip_lookup_name(f, dp, lenskip, &len); 238*ca987d46SWarner Losh else 239*ca987d46SWarner Losh cp = NULL; 240*ca987d46SWarner Losh if (cp == NULL) { 241*ca987d46SWarner Losh len = isonum_711(dp->name_len); 242*ca987d46SWarner Losh cp = dp->name; 243*ca987d46SWarner Losh icase = 1; 244*ca987d46SWarner Losh } else 245*ca987d46SWarner Losh icase = 0; 246*ca987d46SWarner Losh for (i = len; --i >= 0; path++, cp++) { 247*ca987d46SWarner Losh if (!*path || *path == '/') 248*ca987d46SWarner Losh break; 249*ca987d46SWarner Losh if (*path == *cp) 250*ca987d46SWarner Losh continue; 251*ca987d46SWarner Losh if (!icase && toupper(*path) == *cp) 252*ca987d46SWarner Losh continue; 253*ca987d46SWarner Losh return 0; 254*ca987d46SWarner Losh } 255*ca987d46SWarner Losh if (*path && *path != '/') 256*ca987d46SWarner Losh return 0; 257*ca987d46SWarner Losh /* 258*ca987d46SWarner Losh * Allow stripping of trailing dots and the version number. 259*ca987d46SWarner Losh * Note that this will find the first instead of the last version 260*ca987d46SWarner Losh * of a file. 261*ca987d46SWarner Losh */ 262*ca987d46SWarner Losh if (i >= 0 && (*cp == ';' || *cp == '.')) { 263*ca987d46SWarner Losh /* This is to prevent matching of numeric extensions */ 264*ca987d46SWarner Losh if (*cp == '.' && cp[1] != ';') 265*ca987d46SWarner Losh return 0; 266*ca987d46SWarner Losh while (--i >= 0) 267*ca987d46SWarner Losh if (*++cp != ';' && (*cp < '0' || *cp > '9')) 268*ca987d46SWarner Losh return 0; 269*ca987d46SWarner Losh } 270*ca987d46SWarner Losh return 1; 271*ca987d46SWarner Losh } 272*ca987d46SWarner Losh 273*ca987d46SWarner Losh static int 274*ca987d46SWarner Losh cd9660_open(const char *path, struct open_file *f) 275*ca987d46SWarner Losh { 276*ca987d46SWarner Losh struct file *fp = NULL; 277*ca987d46SWarner Losh void *buf; 278*ca987d46SWarner Losh struct iso_primary_descriptor *vd; 279*ca987d46SWarner Losh size_t buf_size, read, dsize, off; 280*ca987d46SWarner Losh daddr_t bno, boff; 281*ca987d46SWarner Losh struct iso_directory_record rec; 282*ca987d46SWarner Losh struct iso_directory_record *dp = NULL; 283*ca987d46SWarner Losh int rc, first, use_rrip, lenskip; 284*ca987d46SWarner Losh 285*ca987d46SWarner Losh /* First find the volume descriptor */ 286*ca987d46SWarner Losh buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 287*ca987d46SWarner Losh vd = buf; 288*ca987d46SWarner Losh for (bno = 16;; bno++) { 289*ca987d46SWarner Losh twiddle(1); 290*ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 291*ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, buf, &read); 292*ca987d46SWarner Losh if (rc) 293*ca987d46SWarner Losh goto out; 294*ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 295*ca987d46SWarner Losh rc = EIO; 296*ca987d46SWarner Losh goto out; 297*ca987d46SWarner Losh } 298*ca987d46SWarner Losh rc = EINVAL; 299*ca987d46SWarner Losh if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 300*ca987d46SWarner Losh goto out; 301*ca987d46SWarner Losh if (isonum_711(vd->type) == ISO_VD_END) 302*ca987d46SWarner Losh goto out; 303*ca987d46SWarner Losh if (isonum_711(vd->type) == ISO_VD_PRIMARY) 304*ca987d46SWarner Losh break; 305*ca987d46SWarner Losh } 306*ca987d46SWarner Losh if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 307*ca987d46SWarner Losh goto out; 308*ca987d46SWarner Losh 309*ca987d46SWarner Losh rec = *(struct iso_directory_record *) vd->root_directory_record; 310*ca987d46SWarner Losh if (*path == '/') path++; /* eat leading '/' */ 311*ca987d46SWarner Losh 312*ca987d46SWarner Losh first = 1; 313*ca987d46SWarner Losh use_rrip = 0; 314*ca987d46SWarner Losh while (*path) { 315*ca987d46SWarner Losh bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 316*ca987d46SWarner Losh dsize = isonum_733(rec.size); 317*ca987d46SWarner Losh off = 0; 318*ca987d46SWarner Losh boff = 0; 319*ca987d46SWarner Losh 320*ca987d46SWarner Losh while (off < dsize) { 321*ca987d46SWarner Losh if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 322*ca987d46SWarner Losh twiddle(1); 323*ca987d46SWarner Losh rc = f->f_dev->dv_strategy 324*ca987d46SWarner Losh (f->f_devdata, F_READ, 325*ca987d46SWarner Losh cdb2devb(bno + boff), 326*ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, 327*ca987d46SWarner Losh buf, &read); 328*ca987d46SWarner Losh if (rc) 329*ca987d46SWarner Losh goto out; 330*ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 331*ca987d46SWarner Losh rc = EIO; 332*ca987d46SWarner Losh goto out; 333*ca987d46SWarner Losh } 334*ca987d46SWarner Losh boff++; 335*ca987d46SWarner Losh dp = (struct iso_directory_record *) buf; 336*ca987d46SWarner Losh } 337*ca987d46SWarner Losh if (isonum_711(dp->length) == 0) { 338*ca987d46SWarner Losh /* skip to next block, if any */ 339*ca987d46SWarner Losh off = boff * ISO_DEFAULT_BLOCK_SIZE; 340*ca987d46SWarner Losh continue; 341*ca987d46SWarner Losh } 342*ca987d46SWarner Losh 343*ca987d46SWarner Losh /* See if RRIP is in use. */ 344*ca987d46SWarner Losh if (first) 345*ca987d46SWarner Losh use_rrip = rrip_check(f, dp, &lenskip); 346*ca987d46SWarner Losh 347*ca987d46SWarner Losh if (dirmatch(f, path, dp, use_rrip, 348*ca987d46SWarner Losh first ? 0 : lenskip)) { 349*ca987d46SWarner Losh first = 0; 350*ca987d46SWarner Losh break; 351*ca987d46SWarner Losh } else 352*ca987d46SWarner Losh first = 0; 353*ca987d46SWarner Losh 354*ca987d46SWarner Losh dp = (struct iso_directory_record *) 355*ca987d46SWarner Losh ((char *) dp + isonum_711(dp->length)); 356*ca987d46SWarner Losh /* If the new block has zero length, it is padding. */ 357*ca987d46SWarner Losh if (isonum_711(dp->length) == 0) { 358*ca987d46SWarner Losh /* Skip to next block, if any. */ 359*ca987d46SWarner Losh off = boff * ISO_DEFAULT_BLOCK_SIZE; 360*ca987d46SWarner Losh continue; 361*ca987d46SWarner Losh } 362*ca987d46SWarner Losh off += isonum_711(dp->length); 363*ca987d46SWarner Losh } 364*ca987d46SWarner Losh if (off >= dsize) { 365*ca987d46SWarner Losh rc = ENOENT; 366*ca987d46SWarner Losh goto out; 367*ca987d46SWarner Losh } 368*ca987d46SWarner Losh 369*ca987d46SWarner Losh rec = *dp; 370*ca987d46SWarner Losh while (*path && *path != '/') /* look for next component */ 371*ca987d46SWarner Losh path++; 372*ca987d46SWarner Losh if (*path) path++; /* skip '/' */ 373*ca987d46SWarner Losh } 374*ca987d46SWarner Losh 375*ca987d46SWarner Losh /* allocate file system specific data structure */ 376*ca987d46SWarner Losh fp = malloc(sizeof(struct file)); 377*ca987d46SWarner Losh bzero(fp, sizeof(struct file)); 378*ca987d46SWarner Losh f->f_fsdata = (void *)fp; 379*ca987d46SWarner Losh 380*ca987d46SWarner Losh if ((isonum_711(rec.flags) & 2) != 0) { 381*ca987d46SWarner Losh fp->f_flags = F_ISDIR; 382*ca987d46SWarner Losh } 383*ca987d46SWarner Losh if (first) { 384*ca987d46SWarner Losh fp->f_flags |= F_ROOTDIR; 385*ca987d46SWarner Losh 386*ca987d46SWarner Losh /* Check for Rock Ridge since we didn't in the loop above. */ 387*ca987d46SWarner Losh bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 388*ca987d46SWarner Losh twiddle(1); 389*ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 390*ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, buf, &read); 391*ca987d46SWarner Losh if (rc) 392*ca987d46SWarner Losh goto out; 393*ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 394*ca987d46SWarner Losh rc = EIO; 395*ca987d46SWarner Losh goto out; 396*ca987d46SWarner Losh } 397*ca987d46SWarner Losh dp = (struct iso_directory_record *)buf; 398*ca987d46SWarner Losh use_rrip = rrip_check(f, dp, &lenskip); 399*ca987d46SWarner Losh } 400*ca987d46SWarner Losh if (use_rrip) { 401*ca987d46SWarner Losh fp->f_flags |= F_RR; 402*ca987d46SWarner Losh fp->f_susp_skip = lenskip; 403*ca987d46SWarner Losh } 404*ca987d46SWarner Losh fp->f_off = 0; 405*ca987d46SWarner Losh fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 406*ca987d46SWarner Losh fp->f_size = isonum_733(rec.size); 407*ca987d46SWarner Losh free(buf); 408*ca987d46SWarner Losh 409*ca987d46SWarner Losh return 0; 410*ca987d46SWarner Losh 411*ca987d46SWarner Losh out: 412*ca987d46SWarner Losh if (fp) 413*ca987d46SWarner Losh free(fp); 414*ca987d46SWarner Losh free(buf); 415*ca987d46SWarner Losh 416*ca987d46SWarner Losh return rc; 417*ca987d46SWarner Losh } 418*ca987d46SWarner Losh 419*ca987d46SWarner Losh static int 420*ca987d46SWarner Losh cd9660_close(struct open_file *f) 421*ca987d46SWarner Losh { 422*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 423*ca987d46SWarner Losh 424*ca987d46SWarner Losh f->f_fsdata = NULL; 425*ca987d46SWarner Losh free(fp); 426*ca987d46SWarner Losh 427*ca987d46SWarner Losh return 0; 428*ca987d46SWarner Losh } 429*ca987d46SWarner Losh 430*ca987d46SWarner Losh static int 431*ca987d46SWarner Losh buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 432*ca987d46SWarner Losh { 433*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 434*ca987d46SWarner Losh daddr_t blkno, blkoff; 435*ca987d46SWarner Losh int rc = 0; 436*ca987d46SWarner Losh size_t read; 437*ca987d46SWarner Losh 438*ca987d46SWarner Losh blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; 439*ca987d46SWarner Losh blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; 440*ca987d46SWarner Losh 441*ca987d46SWarner Losh if (blkno != fp->f_buf_blkno) { 442*ca987d46SWarner Losh if (fp->f_buf == (char *)0) 443*ca987d46SWarner Losh fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); 444*ca987d46SWarner Losh 445*ca987d46SWarner Losh twiddle(16); 446*ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 447*ca987d46SWarner Losh cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, 448*ca987d46SWarner Losh fp->f_buf, &read); 449*ca987d46SWarner Losh if (rc) 450*ca987d46SWarner Losh return (rc); 451*ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) 452*ca987d46SWarner Losh return (EIO); 453*ca987d46SWarner Losh 454*ca987d46SWarner Losh fp->f_buf_blkno = blkno; 455*ca987d46SWarner Losh } 456*ca987d46SWarner Losh 457*ca987d46SWarner Losh *buf_p = fp->f_buf + blkoff; 458*ca987d46SWarner Losh *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; 459*ca987d46SWarner Losh 460*ca987d46SWarner Losh if (*size_p > fp->f_size - fp->f_off) 461*ca987d46SWarner Losh *size_p = fp->f_size - fp->f_off; 462*ca987d46SWarner Losh return (rc); 463*ca987d46SWarner Losh } 464*ca987d46SWarner Losh 465*ca987d46SWarner Losh static int 466*ca987d46SWarner Losh cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) 467*ca987d46SWarner Losh { 468*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 469*ca987d46SWarner Losh char *buf, *addr; 470*ca987d46SWarner Losh size_t buf_size, csize; 471*ca987d46SWarner Losh int rc = 0; 472*ca987d46SWarner Losh 473*ca987d46SWarner Losh addr = start; 474*ca987d46SWarner Losh while (size) { 475*ca987d46SWarner Losh if (fp->f_off < 0 || fp->f_off >= fp->f_size) 476*ca987d46SWarner Losh break; 477*ca987d46SWarner Losh 478*ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 479*ca987d46SWarner Losh if (rc) 480*ca987d46SWarner Losh break; 481*ca987d46SWarner Losh 482*ca987d46SWarner Losh csize = size > buf_size ? buf_size : size; 483*ca987d46SWarner Losh bcopy(buf, addr, csize); 484*ca987d46SWarner Losh 485*ca987d46SWarner Losh fp->f_off += csize; 486*ca987d46SWarner Losh addr += csize; 487*ca987d46SWarner Losh size -= csize; 488*ca987d46SWarner Losh } 489*ca987d46SWarner Losh if (resid) 490*ca987d46SWarner Losh *resid = size; 491*ca987d46SWarner Losh return (rc); 492*ca987d46SWarner Losh } 493*ca987d46SWarner Losh 494*ca987d46SWarner Losh static int 495*ca987d46SWarner Losh cd9660_readdir(struct open_file *f, struct dirent *d) 496*ca987d46SWarner Losh { 497*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 498*ca987d46SWarner Losh struct iso_directory_record *ep; 499*ca987d46SWarner Losh size_t buf_size, reclen, namelen; 500*ca987d46SWarner Losh int error = 0; 501*ca987d46SWarner Losh int lenskip; 502*ca987d46SWarner Losh char *buf, *name; 503*ca987d46SWarner Losh 504*ca987d46SWarner Losh again: 505*ca987d46SWarner Losh if (fp->f_off >= fp->f_size) 506*ca987d46SWarner Losh return (ENOENT); 507*ca987d46SWarner Losh error = buf_read_file(f, &buf, &buf_size); 508*ca987d46SWarner Losh if (error) 509*ca987d46SWarner Losh return (error); 510*ca987d46SWarner Losh ep = (struct iso_directory_record *)buf; 511*ca987d46SWarner Losh 512*ca987d46SWarner Losh if (isonum_711(ep->length) == 0) { 513*ca987d46SWarner Losh daddr_t blkno; 514*ca987d46SWarner Losh 515*ca987d46SWarner Losh /* skip to next block, if any */ 516*ca987d46SWarner Losh blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; 517*ca987d46SWarner Losh fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; 518*ca987d46SWarner Losh goto again; 519*ca987d46SWarner Losh } 520*ca987d46SWarner Losh 521*ca987d46SWarner Losh if (fp->f_flags & F_RR) { 522*ca987d46SWarner Losh if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) 523*ca987d46SWarner Losh lenskip = 0; 524*ca987d46SWarner Losh else 525*ca987d46SWarner Losh lenskip = fp->f_susp_skip; 526*ca987d46SWarner Losh name = rrip_lookup_name(f, ep, lenskip, &namelen); 527*ca987d46SWarner Losh } else 528*ca987d46SWarner Losh name = NULL; 529*ca987d46SWarner Losh if (name == NULL) { 530*ca987d46SWarner Losh namelen = isonum_711(ep->name_len); 531*ca987d46SWarner Losh name = ep->name; 532*ca987d46SWarner Losh if (namelen == 1) { 533*ca987d46SWarner Losh if (ep->name[0] == 0) 534*ca987d46SWarner Losh name = "."; 535*ca987d46SWarner Losh else if (ep->name[0] == 1) { 536*ca987d46SWarner Losh namelen = 2; 537*ca987d46SWarner Losh name = ".."; 538*ca987d46SWarner Losh } 539*ca987d46SWarner Losh } 540*ca987d46SWarner Losh } 541*ca987d46SWarner Losh reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; 542*ca987d46SWarner Losh reclen = (reclen + 3) & ~3; 543*ca987d46SWarner Losh 544*ca987d46SWarner Losh d->d_fileno = isonum_733(ep->extent); 545*ca987d46SWarner Losh d->d_reclen = reclen; 546*ca987d46SWarner Losh if (isonum_711(ep->flags) & 2) 547*ca987d46SWarner Losh d->d_type = DT_DIR; 548*ca987d46SWarner Losh else 549*ca987d46SWarner Losh d->d_type = DT_REG; 550*ca987d46SWarner Losh d->d_namlen = namelen; 551*ca987d46SWarner Losh 552*ca987d46SWarner Losh bcopy(name, d->d_name, d->d_namlen); 553*ca987d46SWarner Losh d->d_name[d->d_namlen] = 0; 554*ca987d46SWarner Losh 555*ca987d46SWarner Losh fp->f_off += isonum_711(ep->length); 556*ca987d46SWarner Losh return (0); 557*ca987d46SWarner Losh } 558*ca987d46SWarner Losh 559*ca987d46SWarner Losh static int 560*ca987d46SWarner Losh cd9660_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused) 561*ca987d46SWarner Losh { 562*ca987d46SWarner Losh return EROFS; 563*ca987d46SWarner Losh } 564*ca987d46SWarner Losh 565*ca987d46SWarner Losh static off_t 566*ca987d46SWarner Losh cd9660_seek(struct open_file *f, off_t offset, int where) 567*ca987d46SWarner Losh { 568*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 569*ca987d46SWarner Losh 570*ca987d46SWarner Losh switch (where) { 571*ca987d46SWarner Losh case SEEK_SET: 572*ca987d46SWarner Losh fp->f_off = offset; 573*ca987d46SWarner Losh break; 574*ca987d46SWarner Losh case SEEK_CUR: 575*ca987d46SWarner Losh fp->f_off += offset; 576*ca987d46SWarner Losh break; 577*ca987d46SWarner Losh case SEEK_END: 578*ca987d46SWarner Losh fp->f_off = fp->f_size - offset; 579*ca987d46SWarner Losh break; 580*ca987d46SWarner Losh default: 581*ca987d46SWarner Losh return -1; 582*ca987d46SWarner Losh } 583*ca987d46SWarner Losh return fp->f_off; 584*ca987d46SWarner Losh } 585*ca987d46SWarner Losh 586*ca987d46SWarner Losh static int 587*ca987d46SWarner Losh cd9660_stat(struct open_file *f, struct stat *sb) 588*ca987d46SWarner Losh { 589*ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 590*ca987d46SWarner Losh 591*ca987d46SWarner Losh /* only important stuff */ 592*ca987d46SWarner Losh sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; 593*ca987d46SWarner Losh if (fp->f_flags & F_ISDIR) 594*ca987d46SWarner Losh sb->st_mode |= S_IFDIR; 595*ca987d46SWarner Losh else 596*ca987d46SWarner Losh sb->st_mode |= S_IFREG; 597*ca987d46SWarner Losh sb->st_uid = sb->st_gid = 0; 598*ca987d46SWarner Losh sb->st_size = fp->f_size; 599*ca987d46SWarner Losh return 0; 600*ca987d46SWarner Losh } 601