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> 456cea60aeSToomas Soome #include <stdbool.h> 46ca987d46SWarner Losh #include <sys/dirent.h> 47b3e16b02SWarner Losh #include <fs/cd9660/iso.h> 48b3e16b02SWarner Losh #include <fs/cd9660/cd9660_rrip.h> 49ca987d46SWarner Losh 50ca987d46SWarner Losh #include "stand.h" 51ca987d46SWarner Losh 52ca987d46SWarner Losh #define SUSP_CONTINUATION "CE" 53ca987d46SWarner Losh #define SUSP_PRESENT "SP" 54ca987d46SWarner Losh #define SUSP_STOP "ST" 55ca987d46SWarner Losh #define SUSP_EXTREF "ER" 56ca987d46SWarner Losh #define RRIP_NAME "NM" 57ca987d46SWarner Losh 58ca987d46SWarner Losh typedef struct { 59ca987d46SWarner Losh ISO_SUSP_HEADER h; 60ca987d46SWarner Losh u_char signature [ISODCL ( 5, 6)]; 61ca987d46SWarner Losh u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 62ca987d46SWarner Losh } ISO_SUSP_PRESENT; 63ca987d46SWarner Losh 64ca987d46SWarner Losh static int buf_read_file(struct open_file *f, char **buf_p, 65ca987d46SWarner Losh size_t *size_p); 66ca987d46SWarner Losh static int cd9660_open(const char *path, struct open_file *f); 67ca987d46SWarner Losh static int cd9660_close(struct open_file *f); 68ca987d46SWarner Losh static int cd9660_read(struct open_file *f, void *buf, size_t size, 69ca987d46SWarner Losh size_t *resid); 70ca987d46SWarner Losh static off_t cd9660_seek(struct open_file *f, off_t offset, int where); 71ca987d46SWarner Losh static int cd9660_stat(struct open_file *f, struct stat *sb); 72ca987d46SWarner Losh static int cd9660_readdir(struct open_file *f, struct dirent *d); 73ca987d46SWarner Losh static int dirmatch(struct open_file *f, const char *path, 74ca987d46SWarner Losh struct iso_directory_record *dp, int use_rrip, int lenskip); 75ca987d46SWarner Losh static int rrip_check(struct open_file *f, struct iso_directory_record *dp, 76ca987d46SWarner Losh int *lenskip); 77ca987d46SWarner Losh static char *rrip_lookup_name(struct open_file *f, 78ca987d46SWarner Losh struct iso_directory_record *dp, int lenskip, size_t *len); 79ca987d46SWarner Losh static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, 80ca987d46SWarner Losh const char *identifier, struct iso_directory_record *dp, 81ca987d46SWarner Losh int lenskip); 82ca987d46SWarner Losh 83ca987d46SWarner Losh struct fs_ops cd9660_fsops = { 84ca987d46SWarner Losh "cd9660", 85ca987d46SWarner Losh cd9660_open, 86ca987d46SWarner Losh cd9660_close, 87ca987d46SWarner Losh cd9660_read, 88468b6c53SToomas Soome null_write, 89ca987d46SWarner Losh cd9660_seek, 90ca987d46SWarner Losh cd9660_stat, 91ca987d46SWarner Losh cd9660_readdir 92ca987d46SWarner Losh }; 93ca987d46SWarner Losh 94ca987d46SWarner Losh #define F_ISDIR 0x0001 /* Directory */ 95ca987d46SWarner Losh #define F_ROOTDIR 0x0002 /* Root directory */ 96ca987d46SWarner Losh #define F_RR 0x0004 /* Rock Ridge on this volume */ 97ca987d46SWarner Losh 98ca987d46SWarner Losh struct file { 99ca987d46SWarner Losh int f_flags; /* file flags */ 100ca987d46SWarner Losh off_t f_off; /* Current offset within file */ 101ca987d46SWarner Losh daddr_t f_bno; /* Starting block number */ 102ca987d46SWarner Losh off_t f_size; /* Size of file */ 103ca987d46SWarner Losh daddr_t f_buf_blkno; /* block number of data block */ 104ca987d46SWarner Losh char *f_buf; /* buffer for data block */ 105ca987d46SWarner Losh int f_susp_skip; /* len_skip for SUSP records */ 106ca987d46SWarner Losh }; 107ca987d46SWarner Losh 108ca987d46SWarner Losh struct ptable_ent { 109ca987d46SWarner Losh char namlen [ISODCL( 1, 1)]; /* 711 */ 110ca987d46SWarner Losh char extlen [ISODCL( 2, 2)]; /* 711 */ 111ca987d46SWarner Losh char block [ISODCL( 3, 6)]; /* 732 */ 112ca987d46SWarner Losh char parent [ISODCL( 7, 8)]; /* 722 */ 113ca987d46SWarner Losh char name [1]; 114ca987d46SWarner Losh }; 115ca987d46SWarner Losh #define PTFIXSZ 8 116ca987d46SWarner Losh #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 117ca987d46SWarner Losh 118ca987d46SWarner Losh #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 119ca987d46SWarner Losh 120ca987d46SWarner Losh static ISO_SUSP_HEADER * 121ca987d46SWarner Losh susp_lookup_record(struct open_file *f, const char *identifier, 122ca987d46SWarner Losh struct iso_directory_record *dp, int lenskip) 123ca987d46SWarner Losh { 124ca987d46SWarner Losh static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 125ca987d46SWarner Losh ISO_SUSP_HEADER *sh; 126ca987d46SWarner Losh ISO_RRIP_CONT *shc; 127ca987d46SWarner Losh char *p, *end; 128ca987d46SWarner Losh int error; 129ca987d46SWarner Losh size_t read; 130ca987d46SWarner Losh 131ca987d46SWarner Losh p = dp->name + isonum_711(dp->name_len) + lenskip; 132ca987d46SWarner Losh /* Names of even length have a padding byte after the name. */ 133ca987d46SWarner Losh if ((isonum_711(dp->name_len) & 1) == 0) 134ca987d46SWarner Losh p++; 135ca987d46SWarner Losh end = (char *)dp + isonum_711(dp->length); 136ca987d46SWarner Losh while (p + 3 < end) { 137ca987d46SWarner Losh sh = (ISO_SUSP_HEADER *)p; 138ca987d46SWarner Losh if (bcmp(sh->type, identifier, 2) == 0) 139ca987d46SWarner Losh return (sh); 140ca987d46SWarner Losh if (bcmp(sh->type, SUSP_STOP, 2) == 0) 141ca987d46SWarner Losh return (NULL); 142ca987d46SWarner Losh if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 143ca987d46SWarner Losh shc = (ISO_RRIP_CONT *)sh; 144ca987d46SWarner Losh error = f->f_dev->dv_strategy(f->f_devdata, F_READ, 145ca987d46SWarner Losh cdb2devb(isonum_733(shc->location)), 146ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); 147ca987d46SWarner Losh 148ca987d46SWarner Losh /* Bail if it fails. */ 149ca987d46SWarner Losh if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) 150ca987d46SWarner Losh return (NULL); 151ca987d46SWarner Losh p = susp_buffer + isonum_733(shc->offset); 152ca987d46SWarner Losh end = p + isonum_733(shc->length); 153ca987d46SWarner Losh } else { 154ca987d46SWarner Losh /* Ignore this record and skip to the next. */ 155ca987d46SWarner Losh p += isonum_711(sh->length); 156ca987d46SWarner Losh 157ca987d46SWarner Losh /* Avoid infinite loops with corrupted file systems */ 158ca987d46SWarner Losh if (isonum_711(sh->length) == 0) 159ca987d46SWarner Losh return (NULL); 160ca987d46SWarner Losh } 161ca987d46SWarner Losh } 162ca987d46SWarner Losh return (NULL); 163ca987d46SWarner Losh } 164ca987d46SWarner Losh 165ca987d46SWarner Losh static char * 166ca987d46SWarner Losh rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, 167ca987d46SWarner Losh int lenskip, size_t *len) 168ca987d46SWarner Losh { 169ca987d46SWarner Losh ISO_RRIP_ALTNAME *p; 170ca987d46SWarner Losh 171ca987d46SWarner Losh if (len == NULL) 172ca987d46SWarner Losh return (NULL); 173ca987d46SWarner Losh 174ca987d46SWarner Losh p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); 175ca987d46SWarner Losh if (p == NULL) 176ca987d46SWarner Losh return (NULL); 177ca987d46SWarner Losh switch (*p->flags) { 178ca987d46SWarner Losh case ISO_SUSP_CFLAG_CURRENT: 179ca987d46SWarner Losh *len = 1; 180ca987d46SWarner Losh return ("."); 181ca987d46SWarner Losh case ISO_SUSP_CFLAG_PARENT: 182ca987d46SWarner Losh *len = 2; 183ca987d46SWarner Losh return (".."); 184ca987d46SWarner Losh case 0: 185ca987d46SWarner Losh *len = isonum_711(p->h.length) - 5; 186ca987d46SWarner Losh return ((char *)p + 5); 187ca987d46SWarner Losh default: 188ca987d46SWarner Losh /* 189ca987d46SWarner Losh * We don't handle hostnames or continued names as they are 190ca987d46SWarner Losh * too hard, so just bail and use the default name. 191ca987d46SWarner Losh */ 192ca987d46SWarner Losh return (NULL); 193ca987d46SWarner Losh } 194ca987d46SWarner Losh } 195ca987d46SWarner Losh 196ca987d46SWarner Losh static int 197ca987d46SWarner Losh rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) 198ca987d46SWarner Losh { 199ca987d46SWarner Losh ISO_SUSP_PRESENT *sp; 200ca987d46SWarner Losh ISO_RRIP_EXTREF *er; 201ca987d46SWarner Losh char *p; 202ca987d46SWarner Losh 203ca987d46SWarner Losh /* First, see if we can find a SP field. */ 204ca987d46SWarner Losh p = dp->name + isonum_711(dp->name_len); 205ca987d46SWarner Losh if (p > (char *)dp + isonum_711(dp->length)) 206ca987d46SWarner Losh return (0); 207ca987d46SWarner Losh sp = (ISO_SUSP_PRESENT *)p; 208ca987d46SWarner Losh if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) 209ca987d46SWarner Losh return (0); 210ca987d46SWarner Losh if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) 211ca987d46SWarner Losh return (0); 212ca987d46SWarner Losh if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) 213ca987d46SWarner Losh return (0); 214ca987d46SWarner Losh *lenskip = isonum_711(sp->len_skp); 215ca987d46SWarner Losh 216ca987d46SWarner Losh /* 217ca987d46SWarner Losh * Now look for an ER field. If RRIP is present, then there must 218ca987d46SWarner Losh * be at least one of these. It would be more pedantic to walk 219ca987d46SWarner Losh * through the list of fields looking for a Rock Ridge ER field. 220ca987d46SWarner Losh */ 221ca987d46SWarner Losh er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); 222ca987d46SWarner Losh if (er == NULL) 223ca987d46SWarner Losh return (0); 224ca987d46SWarner Losh return (1); 225ca987d46SWarner Losh } 226ca987d46SWarner Losh 227ca987d46SWarner Losh static int 228ca987d46SWarner Losh dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, 229ca987d46SWarner Losh int use_rrip, int lenskip) 230ca987d46SWarner Losh { 2316cea60aeSToomas Soome size_t len, plen; 2326cea60aeSToomas Soome char *cp, *sep; 233ca987d46SWarner Losh int i, icase; 234ca987d46SWarner Losh 235ca987d46SWarner Losh if (use_rrip) 236ca987d46SWarner Losh cp = rrip_lookup_name(f, dp, lenskip, &len); 237ca987d46SWarner Losh else 238ca987d46SWarner Losh cp = NULL; 239ca987d46SWarner Losh if (cp == NULL) { 240ca987d46SWarner Losh len = isonum_711(dp->name_len); 241ca987d46SWarner Losh cp = dp->name; 242ca987d46SWarner Losh icase = 1; 243ca987d46SWarner Losh } else 244ca987d46SWarner Losh icase = 0; 24561250f78SToomas Soome 2466cea60aeSToomas Soome sep = strchr(path, '/'); 2476cea60aeSToomas Soome if (sep != NULL) { 2486cea60aeSToomas Soome plen = sep - path; 2496cea60aeSToomas Soome } else { 2506cea60aeSToomas Soome plen = strlen(path); 2516cea60aeSToomas Soome } 2526cea60aeSToomas Soome 2536cea60aeSToomas Soome if (plen != len) 25461250f78SToomas Soome return (0); 25561250f78SToomas Soome 256ca987d46SWarner Losh for (i = len; --i >= 0; path++, cp++) { 257ca987d46SWarner Losh if (!*path || *path == '/') 258ca987d46SWarner Losh break; 259ca987d46SWarner Losh if (*path == *cp) 260ca987d46SWarner Losh continue; 261ca987d46SWarner Losh if (!icase && toupper(*path) == *cp) 262ca987d46SWarner Losh continue; 263ca987d46SWarner Losh return 0; 264ca987d46SWarner Losh } 265ca987d46SWarner Losh if (*path && *path != '/') 266ca987d46SWarner Losh return 0; 267ca987d46SWarner Losh /* 268ca987d46SWarner Losh * Allow stripping of trailing dots and the version number. 269ca987d46SWarner Losh * Note that this will find the first instead of the last version 270ca987d46SWarner Losh * of a file. 271ca987d46SWarner Losh */ 272ca987d46SWarner Losh if (i >= 0 && (*cp == ';' || *cp == '.')) { 273ca987d46SWarner Losh /* This is to prevent matching of numeric extensions */ 274ca987d46SWarner Losh if (*cp == '.' && cp[1] != ';') 275ca987d46SWarner Losh return 0; 276ca987d46SWarner Losh while (--i >= 0) 277ca987d46SWarner Losh if (*++cp != ';' && (*cp < '0' || *cp > '9')) 278ca987d46SWarner Losh return 0; 279ca987d46SWarner Losh } 280ca987d46SWarner Losh return 1; 281ca987d46SWarner Losh } 282ca987d46SWarner Losh 283ca987d46SWarner Losh static int 284ca987d46SWarner Losh cd9660_open(const char *path, struct open_file *f) 285ca987d46SWarner Losh { 286ca987d46SWarner Losh struct file *fp = NULL; 287ca987d46SWarner Losh void *buf; 288ca987d46SWarner Losh struct iso_primary_descriptor *vd; 289ca987d46SWarner Losh size_t buf_size, read, dsize, off; 290ca987d46SWarner Losh daddr_t bno, boff; 291ca987d46SWarner Losh struct iso_directory_record rec; 292ca987d46SWarner Losh struct iso_directory_record *dp = NULL; 293ca987d46SWarner Losh int rc, first, use_rrip, lenskip; 2946cea60aeSToomas Soome bool isdir = false; 295ca987d46SWarner Losh 296ca987d46SWarner Losh /* First find the volume descriptor */ 297ca987d46SWarner Losh buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 298ca987d46SWarner Losh vd = buf; 299ca987d46SWarner Losh for (bno = 16;; bno++) { 300ca987d46SWarner Losh twiddle(1); 301ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 302ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, buf, &read); 303ca987d46SWarner Losh if (rc) 304ca987d46SWarner Losh goto out; 305ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 306ca987d46SWarner Losh rc = EIO; 307ca987d46SWarner Losh goto out; 308ca987d46SWarner Losh } 309ca987d46SWarner Losh rc = EINVAL; 310ca987d46SWarner Losh if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 311ca987d46SWarner Losh goto out; 312ca987d46SWarner Losh if (isonum_711(vd->type) == ISO_VD_END) 313ca987d46SWarner Losh goto out; 314ca987d46SWarner Losh if (isonum_711(vd->type) == ISO_VD_PRIMARY) 315ca987d46SWarner Losh break; 316ca987d46SWarner Losh } 317ca987d46SWarner Losh if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 318ca987d46SWarner Losh goto out; 319ca987d46SWarner Losh 32017e2c266SToomas Soome bcopy(vd->root_directory_record, &rec, sizeof(rec)); 321ca987d46SWarner Losh if (*path == '/') path++; /* eat leading '/' */ 322ca987d46SWarner Losh 323ca987d46SWarner Losh first = 1; 324ca987d46SWarner Losh use_rrip = 0; 325213f235fSToomas Soome lenskip = 0; 326ca987d46SWarner Losh while (*path) { 327ca987d46SWarner Losh bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 328ca987d46SWarner Losh dsize = isonum_733(rec.size); 329ca987d46SWarner Losh off = 0; 330ca987d46SWarner Losh boff = 0; 331ca987d46SWarner Losh 332ca987d46SWarner Losh while (off < dsize) { 333ca987d46SWarner Losh if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 334ca987d46SWarner Losh twiddle(1); 335ca987d46SWarner Losh rc = f->f_dev->dv_strategy 336ca987d46SWarner Losh (f->f_devdata, F_READ, 337ca987d46SWarner Losh cdb2devb(bno + boff), 338ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, 339ca987d46SWarner Losh buf, &read); 340ca987d46SWarner Losh if (rc) 341ca987d46SWarner Losh goto out; 342ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 343ca987d46SWarner Losh rc = EIO; 344ca987d46SWarner Losh goto out; 345ca987d46SWarner Losh } 346ca987d46SWarner Losh boff++; 347ca987d46SWarner Losh dp = (struct iso_directory_record *) buf; 348ca987d46SWarner Losh } 349ca987d46SWarner Losh if (isonum_711(dp->length) == 0) { 350ca987d46SWarner Losh /* skip to next block, if any */ 351ca987d46SWarner Losh off = boff * ISO_DEFAULT_BLOCK_SIZE; 352ca987d46SWarner Losh continue; 353ca987d46SWarner Losh } 354ca987d46SWarner Losh 355ca987d46SWarner Losh /* See if RRIP is in use. */ 356ca987d46SWarner Losh if (first) 357ca987d46SWarner Losh use_rrip = rrip_check(f, dp, &lenskip); 358ca987d46SWarner Losh 359ca987d46SWarner Losh if (dirmatch(f, path, dp, use_rrip, 360ca987d46SWarner Losh first ? 0 : lenskip)) { 361ca987d46SWarner Losh first = 0; 362ca987d46SWarner Losh break; 363ca987d46SWarner Losh } else 364ca987d46SWarner Losh first = 0; 365ca987d46SWarner Losh 366ca987d46SWarner Losh dp = (struct iso_directory_record *) 367ca987d46SWarner Losh ((char *) dp + isonum_711(dp->length)); 368ca987d46SWarner Losh /* If the new block has zero length, it is padding. */ 369ca987d46SWarner Losh if (isonum_711(dp->length) == 0) { 370ca987d46SWarner Losh /* Skip to next block, if any. */ 371ca987d46SWarner Losh off = boff * ISO_DEFAULT_BLOCK_SIZE; 372ca987d46SWarner Losh continue; 373ca987d46SWarner Losh } 374ca987d46SWarner Losh off += isonum_711(dp->length); 375ca987d46SWarner Losh } 376ca987d46SWarner Losh if (off >= dsize) { 377ca987d46SWarner Losh rc = ENOENT; 378ca987d46SWarner Losh goto out; 379ca987d46SWarner Losh } 380ca987d46SWarner Losh 381ca987d46SWarner Losh rec = *dp; 382ca987d46SWarner Losh while (*path && *path != '/') /* look for next component */ 383ca987d46SWarner Losh path++; 3846cea60aeSToomas Soome 3856cea60aeSToomas Soome if (*path) /* this component was directory */ 3866cea60aeSToomas Soome isdir = true; 3876cea60aeSToomas Soome 3886cea60aeSToomas Soome while (*path == '/') 3896cea60aeSToomas Soome path++; /* skip '/' */ 3906cea60aeSToomas Soome 3916cea60aeSToomas Soome if (*path) /* We do have next component. */ 3926cea60aeSToomas Soome isdir = false; 3936cea60aeSToomas Soome } 3946cea60aeSToomas Soome 3956cea60aeSToomas Soome /* 3966cea60aeSToomas Soome * if the path had trailing / but the path does point to file, 3976cea60aeSToomas Soome * report the error ENOTDIR. 3986cea60aeSToomas Soome */ 3996cea60aeSToomas Soome if (isdir == true && (isonum_711(rec.flags) & 2) == 0) { 4006cea60aeSToomas Soome rc = ENOTDIR; 4016cea60aeSToomas Soome goto out; 402ca987d46SWarner Losh } 403ca987d46SWarner Losh 404ca987d46SWarner Losh /* allocate file system specific data structure */ 405ca987d46SWarner Losh fp = malloc(sizeof(struct file)); 406ca987d46SWarner Losh bzero(fp, sizeof(struct file)); 407ca987d46SWarner Losh f->f_fsdata = (void *)fp; 408ca987d46SWarner Losh 409ca987d46SWarner Losh if ((isonum_711(rec.flags) & 2) != 0) { 410ca987d46SWarner Losh fp->f_flags = F_ISDIR; 411ca987d46SWarner Losh } 412ca987d46SWarner Losh if (first) { 413ca987d46SWarner Losh fp->f_flags |= F_ROOTDIR; 414ca987d46SWarner Losh 415ca987d46SWarner Losh /* Check for Rock Ridge since we didn't in the loop above. */ 416ca987d46SWarner Losh bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 417ca987d46SWarner Losh twiddle(1); 418ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 419ca987d46SWarner Losh ISO_DEFAULT_BLOCK_SIZE, buf, &read); 420ca987d46SWarner Losh if (rc) 421ca987d46SWarner Losh goto out; 422ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) { 423ca987d46SWarner Losh rc = EIO; 424ca987d46SWarner Losh goto out; 425ca987d46SWarner Losh } 426ca987d46SWarner Losh dp = (struct iso_directory_record *)buf; 427ca987d46SWarner Losh use_rrip = rrip_check(f, dp, &lenskip); 428ca987d46SWarner Losh } 429ca987d46SWarner Losh if (use_rrip) { 430ca987d46SWarner Losh fp->f_flags |= F_RR; 431ca987d46SWarner Losh fp->f_susp_skip = lenskip; 432ca987d46SWarner Losh } 433ca987d46SWarner Losh fp->f_off = 0; 434ca987d46SWarner Losh fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 435ca987d46SWarner Losh fp->f_size = isonum_733(rec.size); 436ca987d46SWarner Losh free(buf); 437ca987d46SWarner Losh 438ca987d46SWarner Losh return 0; 439ca987d46SWarner Losh 440ca987d46SWarner Losh out: 441ca987d46SWarner Losh if (fp) 442ca987d46SWarner Losh free(fp); 443ca987d46SWarner Losh free(buf); 444ca987d46SWarner Losh 445ca987d46SWarner Losh return rc; 446ca987d46SWarner Losh } 447ca987d46SWarner Losh 448ca987d46SWarner Losh static int 449ca987d46SWarner Losh cd9660_close(struct open_file *f) 450ca987d46SWarner Losh { 451ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 452ca987d46SWarner Losh 453ca987d46SWarner Losh f->f_fsdata = NULL; 454ca987d46SWarner Losh free(fp); 455ca987d46SWarner Losh 456ca987d46SWarner Losh return 0; 457ca987d46SWarner Losh } 458ca987d46SWarner Losh 459ca987d46SWarner Losh static int 460ca987d46SWarner Losh buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 461ca987d46SWarner Losh { 462ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 463ca987d46SWarner Losh daddr_t blkno, blkoff; 464ca987d46SWarner Losh int rc = 0; 465ca987d46SWarner Losh size_t read; 466ca987d46SWarner Losh 467ca987d46SWarner Losh blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; 468ca987d46SWarner Losh blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; 469ca987d46SWarner Losh 470ca987d46SWarner Losh if (blkno != fp->f_buf_blkno) { 471ca987d46SWarner Losh if (fp->f_buf == (char *)0) 472ca987d46SWarner Losh fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); 473ca987d46SWarner Losh 474ca987d46SWarner Losh twiddle(16); 475ca987d46SWarner Losh rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 476ca987d46SWarner Losh cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, 477ca987d46SWarner Losh fp->f_buf, &read); 478ca987d46SWarner Losh if (rc) 479ca987d46SWarner Losh return (rc); 480ca987d46SWarner Losh if (read != ISO_DEFAULT_BLOCK_SIZE) 481ca987d46SWarner Losh return (EIO); 482ca987d46SWarner Losh 483ca987d46SWarner Losh fp->f_buf_blkno = blkno; 484ca987d46SWarner Losh } 485ca987d46SWarner Losh 486ca987d46SWarner Losh *buf_p = fp->f_buf + blkoff; 487ca987d46SWarner Losh *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; 488ca987d46SWarner Losh 489ca987d46SWarner Losh if (*size_p > fp->f_size - fp->f_off) 490ca987d46SWarner Losh *size_p = fp->f_size - fp->f_off; 491ca987d46SWarner Losh return (rc); 492ca987d46SWarner Losh } 493ca987d46SWarner Losh 494ca987d46SWarner Losh static int 495ca987d46SWarner Losh cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) 496ca987d46SWarner Losh { 497ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 498ca987d46SWarner Losh char *buf, *addr; 499ca987d46SWarner Losh size_t buf_size, csize; 500ca987d46SWarner Losh int rc = 0; 501ca987d46SWarner Losh 502ca987d46SWarner Losh addr = start; 503ca987d46SWarner Losh while (size) { 504ca987d46SWarner Losh if (fp->f_off < 0 || fp->f_off >= fp->f_size) 505ca987d46SWarner Losh break; 506ca987d46SWarner Losh 507ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 508ca987d46SWarner Losh if (rc) 509ca987d46SWarner Losh break; 510ca987d46SWarner Losh 511ca987d46SWarner Losh csize = size > buf_size ? buf_size : size; 512ca987d46SWarner Losh bcopy(buf, addr, csize); 513ca987d46SWarner Losh 514ca987d46SWarner Losh fp->f_off += csize; 515ca987d46SWarner Losh addr += csize; 516ca987d46SWarner Losh size -= csize; 517ca987d46SWarner Losh } 518ca987d46SWarner Losh if (resid) 519ca987d46SWarner Losh *resid = size; 520ca987d46SWarner Losh return (rc); 521ca987d46SWarner Losh } 522ca987d46SWarner Losh 523ca987d46SWarner Losh static int 524ca987d46SWarner Losh cd9660_readdir(struct open_file *f, struct dirent *d) 525ca987d46SWarner Losh { 526ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 527ca987d46SWarner Losh struct iso_directory_record *ep; 528ca987d46SWarner Losh size_t buf_size, reclen, namelen; 529ca987d46SWarner Losh int error = 0; 530ca987d46SWarner Losh int lenskip; 531ca987d46SWarner Losh char *buf, *name; 532ca987d46SWarner Losh 533ca987d46SWarner Losh again: 534ca987d46SWarner Losh if (fp->f_off >= fp->f_size) 535ca987d46SWarner Losh return (ENOENT); 536ca987d46SWarner Losh error = buf_read_file(f, &buf, &buf_size); 537ca987d46SWarner Losh if (error) 538ca987d46SWarner Losh return (error); 539ca987d46SWarner Losh ep = (struct iso_directory_record *)buf; 540ca987d46SWarner Losh 541ca987d46SWarner Losh if (isonum_711(ep->length) == 0) { 542ca987d46SWarner Losh daddr_t blkno; 543ca987d46SWarner Losh 544ca987d46SWarner Losh /* skip to next block, if any */ 545ca987d46SWarner Losh blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; 546ca987d46SWarner Losh fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; 547ca987d46SWarner Losh goto again; 548ca987d46SWarner Losh } 549ca987d46SWarner Losh 550ca987d46SWarner Losh if (fp->f_flags & F_RR) { 551ca987d46SWarner Losh if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) 552ca987d46SWarner Losh lenskip = 0; 553ca987d46SWarner Losh else 554ca987d46SWarner Losh lenskip = fp->f_susp_skip; 555ca987d46SWarner Losh name = rrip_lookup_name(f, ep, lenskip, &namelen); 556ca987d46SWarner Losh } else 557ca987d46SWarner Losh name = NULL; 558ca987d46SWarner Losh if (name == NULL) { 559ca987d46SWarner Losh namelen = isonum_711(ep->name_len); 560ca987d46SWarner Losh name = ep->name; 561ca987d46SWarner Losh if (namelen == 1) { 562ca987d46SWarner Losh if (ep->name[0] == 0) 563ca987d46SWarner Losh name = "."; 564ca987d46SWarner Losh else if (ep->name[0] == 1) { 565ca987d46SWarner Losh namelen = 2; 566ca987d46SWarner Losh name = ".."; 567ca987d46SWarner Losh } 568ca987d46SWarner Losh } 569ca987d46SWarner Losh } 570ca987d46SWarner Losh reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; 571ca987d46SWarner Losh reclen = (reclen + 3) & ~3; 572ca987d46SWarner Losh 573ca987d46SWarner Losh d->d_fileno = isonum_733(ep->extent); 574ca987d46SWarner Losh d->d_reclen = reclen; 575ca987d46SWarner Losh if (isonum_711(ep->flags) & 2) 576ca987d46SWarner Losh d->d_type = DT_DIR; 577ca987d46SWarner Losh else 578ca987d46SWarner Losh d->d_type = DT_REG; 579ca987d46SWarner Losh d->d_namlen = namelen; 580ca987d46SWarner Losh 581ca987d46SWarner Losh bcopy(name, d->d_name, d->d_namlen); 582ca987d46SWarner Losh d->d_name[d->d_namlen] = 0; 583ca987d46SWarner Losh 584ca987d46SWarner Losh fp->f_off += isonum_711(ep->length); 585ca987d46SWarner Losh return (0); 586ca987d46SWarner Losh } 587ca987d46SWarner Losh 588ca987d46SWarner Losh static off_t 589ca987d46SWarner Losh cd9660_seek(struct open_file *f, off_t offset, int where) 590ca987d46SWarner Losh { 591ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 592ca987d46SWarner Losh 593ca987d46SWarner Losh switch (where) { 594ca987d46SWarner Losh case SEEK_SET: 595ca987d46SWarner Losh fp->f_off = offset; 596ca987d46SWarner Losh break; 597ca987d46SWarner Losh case SEEK_CUR: 598ca987d46SWarner Losh fp->f_off += offset; 599ca987d46SWarner Losh break; 600ca987d46SWarner Losh case SEEK_END: 601ca987d46SWarner Losh fp->f_off = fp->f_size - offset; 602ca987d46SWarner Losh break; 603ca987d46SWarner Losh default: 604ca987d46SWarner Losh return -1; 605ca987d46SWarner Losh } 606ca987d46SWarner Losh return fp->f_off; 607ca987d46SWarner Losh } 608ca987d46SWarner Losh 609ca987d46SWarner Losh static int 610ca987d46SWarner Losh cd9660_stat(struct open_file *f, struct stat *sb) 611ca987d46SWarner Losh { 612ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 613ca987d46SWarner Losh 614ca987d46SWarner Losh /* only important stuff */ 615ca987d46SWarner Losh sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; 616ca987d46SWarner Losh if (fp->f_flags & F_ISDIR) 617ca987d46SWarner Losh sb->st_mode |= S_IFDIR; 618ca987d46SWarner Losh else 619ca987d46SWarner Losh sb->st_mode |= S_IFREG; 620ca987d46SWarner Losh sb->st_uid = sb->st_gid = 0; 621ca987d46SWarner Losh sb->st_size = fp->f_size; 622ca987d46SWarner Losh return 0; 623ca987d46SWarner Losh } 624