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