138451Smsmith/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ 238451Smsmith 338451Smsmith/* 438451Smsmith * Copyright (C) 1996 Wolfgang Solfrank. 538451Smsmith * Copyright (C) 1996 TooLs GmbH. 638451Smsmith * All rights reserved. 738451Smsmith * 838451Smsmith * Redistribution and use in source and binary forms, with or without 938451Smsmith * modification, are permitted provided that the following conditions 1038451Smsmith * are met: 1138451Smsmith * 1. Redistributions of source code must retain the above copyright 1238451Smsmith * notice, this list of conditions and the following disclaimer. 1338451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1438451Smsmith * notice, this list of conditions and the following disclaimer in the 1538451Smsmith * documentation and/or other materials provided with the distribution. 1638451Smsmith * 3. All advertising materials mentioning features or use of this software 1738451Smsmith * must display the following acknowledgement: 1838451Smsmith * This product includes software developed by TooLs GmbH. 1938451Smsmith * 4. The name of TooLs GmbH may not be used to endorse or promote products 2038451Smsmith * derived from this software without specific prior written permission. 2138451Smsmith * 2238451Smsmith * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2338451Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2438451Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2538451Smsmith * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2638451Smsmith * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2738451Smsmith * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2838451Smsmith * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2938451Smsmith * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3038451Smsmith * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3138451Smsmith * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3238451Smsmith */ 3338451Smsmith 3484221Sdillon#include <sys/cdefs.h> 3584221Sdillon__FBSDID("$FreeBSD: stable/11/stand/libsa/cd9660.c 346477 2019-04-21 03:43:27Z kevans $"); 3684221Sdillon 3738451Smsmith/* 3838451Smsmith * Stand-alone ISO9660 file reading package. 3938451Smsmith * 4038451Smsmith * Note: This doesn't support Rock Ridge extensions, extended attributes, 4138451Smsmith * blocksizes other than 2048 bytes, multi-extent files, etc. 4238451Smsmith */ 4338451Smsmith#include <sys/param.h> 4438451Smsmith#include <string.h> 45346477Skevans#include <stdbool.h> 4656222Sobrien#include <sys/dirent.h> 47329175Skevans#include <fs/cd9660/iso.h> 48329175Skevans#include <fs/cd9660/cd9660_rrip.h> 4938451Smsmith 5038451Smsmith#include "stand.h" 5138451Smsmith 5286142Sjhb#define SUSP_CONTINUATION "CE" 5386142Sjhb#define SUSP_PRESENT "SP" 5486142Sjhb#define SUSP_STOP "ST" 5586142Sjhb#define SUSP_EXTREF "ER" 5686142Sjhb#define RRIP_NAME "NM" 5786142Sjhb 5886142Sjhbtypedef struct { 5986142Sjhb ISO_SUSP_HEADER h; 6086142Sjhb u_char signature [ISODCL ( 5, 6)]; 6186142Sjhb u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 6286142Sjhb} ISO_SUSP_PRESENT; 6386142Sjhb 6486137Sjhbstatic int buf_read_file(struct open_file *f, char **buf_p, 6586137Sjhb size_t *size_p); 6639468Smsmithstatic int cd9660_open(const char *path, struct open_file *f); 6738451Smsmithstatic int cd9660_close(struct open_file *f); 6886137Sjhbstatic int cd9660_read(struct open_file *f, void *buf, size_t size, 6986137Sjhb size_t *resid); 7038451Smsmithstatic off_t cd9660_seek(struct open_file *f, off_t offset, int where); 7138451Smsmithstatic int cd9660_stat(struct open_file *f, struct stat *sb); 7259766Sjlemonstatic int cd9660_readdir(struct open_file *f, struct dirent *d); 7386142Sjhbstatic int dirmatch(struct open_file *f, const char *path, 7486142Sjhb struct iso_directory_record *dp, int use_rrip, int lenskip); 7586142Sjhbstatic int rrip_check(struct open_file *f, struct iso_directory_record *dp, 7686142Sjhb int *lenskip); 7786142Sjhbstatic char *rrip_lookup_name(struct open_file *f, 7886142Sjhb struct iso_directory_record *dp, int lenskip, size_t *len); 7986142Sjhbstatic ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, 8086142Sjhb const char *identifier, struct iso_directory_record *dp, 8186142Sjhb int lenskip); 8238451Smsmith 8338451Smsmithstruct fs_ops cd9660_fsops = { 8459766Sjlemon "cd9660", 8559766Sjlemon cd9660_open, 8659766Sjlemon cd9660_close, 8759766Sjlemon cd9660_read, 88332141Skevans null_write, 8959766Sjlemon cd9660_seek, 9059766Sjlemon cd9660_stat, 9159766Sjlemon cd9660_readdir 9238451Smsmith}; 9338451Smsmith 9486158Sjhb#define F_ISDIR 0x0001 /* Directory */ 9586158Sjhb#define F_ROOTDIR 0x0002 /* Root directory */ 9686158Sjhb#define F_RR 0x0004 /* Rock Ridge on this volume */ 9786158Sjhb 9838451Smsmithstruct file { 9986158Sjhb int f_flags; /* file flags */ 10059766Sjlemon off_t f_off; /* Current offset within file */ 10159766Sjlemon daddr_t f_bno; /* Starting block number */ 10259766Sjlemon off_t f_size; /* Size of file */ 10359766Sjlemon daddr_t f_buf_blkno; /* block number of data block */ 10459766Sjlemon char *f_buf; /* buffer for data block */ 10586158Sjhb int f_susp_skip; /* len_skip for SUSP records */ 10638451Smsmith}; 10738451Smsmith 10838451Smsmithstruct ptable_ent { 10938451Smsmith char namlen [ISODCL( 1, 1)]; /* 711 */ 11038451Smsmith char extlen [ISODCL( 2, 2)]; /* 711 */ 11138451Smsmith char block [ISODCL( 3, 6)]; /* 732 */ 11238451Smsmith char parent [ISODCL( 7, 8)]; /* 722 */ 11338451Smsmith char name [1]; 11438451Smsmith}; 11538451Smsmith#define PTFIXSZ 8 11638451Smsmith#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 11738451Smsmith 11838451Smsmith#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 11938451Smsmith 12086142Sjhbstatic ISO_SUSP_HEADER * 12186142Sjhbsusp_lookup_record(struct open_file *f, const char *identifier, 12286142Sjhb struct iso_directory_record *dp, int lenskip) 12386142Sjhb{ 12486142Sjhb static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 12586142Sjhb ISO_SUSP_HEADER *sh; 12686142Sjhb ISO_RRIP_CONT *shc; 12786142Sjhb char *p, *end; 12886142Sjhb int error; 12986142Sjhb size_t read; 13086142Sjhb 13186142Sjhb p = dp->name + isonum_711(dp->name_len) + lenskip; 13286142Sjhb /* Names of even length have a padding byte after the name. */ 13386142Sjhb if ((isonum_711(dp->name_len) & 1) == 0) 13486142Sjhb p++; 13586142Sjhb end = (char *)dp + isonum_711(dp->length); 13686142Sjhb while (p + 3 < end) { 13786142Sjhb sh = (ISO_SUSP_HEADER *)p; 13886142Sjhb if (bcmp(sh->type, identifier, 2) == 0) 13986142Sjhb return (sh); 14086142Sjhb if (bcmp(sh->type, SUSP_STOP, 2) == 0) 14186142Sjhb return (NULL); 14286142Sjhb if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 14386142Sjhb shc = (ISO_RRIP_CONT *)sh; 14486142Sjhb error = f->f_dev->dv_strategy(f->f_devdata, F_READ, 145313355Stsoome cdb2devb(isonum_733(shc->location)), 14686142Sjhb ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); 14786142Sjhb 14886142Sjhb /* Bail if it fails. */ 14986142Sjhb if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) 15086142Sjhb return (NULL); 15186142Sjhb p = susp_buffer + isonum_733(shc->offset); 15286142Sjhb end = p + isonum_733(shc->length); 153276412Snwhitehorn } else { 15486142Sjhb /* Ignore this record and skip to the next. */ 15586142Sjhb p += isonum_711(sh->length); 156276412Snwhitehorn 157276412Snwhitehorn /* Avoid infinite loops with corrupted file systems */ 158276412Snwhitehorn if (isonum_711(sh->length) == 0) 159276412Snwhitehorn return (NULL); 160276412Snwhitehorn } 16186142Sjhb } 16286142Sjhb return (NULL); 16386142Sjhb} 16486142Sjhb 16586142Sjhbstatic char * 16686142Sjhbrrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, 16786142Sjhb int lenskip, size_t *len) 16886142Sjhb{ 16986142Sjhb ISO_RRIP_ALTNAME *p; 17086142Sjhb 17186142Sjhb if (len == NULL) 17286142Sjhb return (NULL); 17386142Sjhb 17486142Sjhb p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); 17586142Sjhb if (p == NULL) 17686142Sjhb return (NULL); 17786142Sjhb switch (*p->flags) { 17886142Sjhb case ISO_SUSP_CFLAG_CURRENT: 17986142Sjhb *len = 1; 18086142Sjhb return ("."); 18186142Sjhb case ISO_SUSP_CFLAG_PARENT: 18286142Sjhb *len = 2; 18386142Sjhb return (".."); 18486142Sjhb case 0: 18586142Sjhb *len = isonum_711(p->h.length) - 5; 18686142Sjhb return ((char *)p + 5); 18786142Sjhb default: 18886142Sjhb /* 18986142Sjhb * We don't handle hostnames or continued names as they are 19086142Sjhb * too hard, so just bail and use the default name. 19186142Sjhb */ 19286142Sjhb return (NULL); 19386142Sjhb } 19486142Sjhb} 19586142Sjhb 19638451Smsmithstatic int 19786142Sjhbrrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) 19838451Smsmith{ 19986142Sjhb ISO_SUSP_PRESENT *sp; 20086142Sjhb ISO_RRIP_EXTREF *er; 20186142Sjhb char *p; 20286142Sjhb 20386142Sjhb /* First, see if we can find a SP field. */ 20486142Sjhb p = dp->name + isonum_711(dp->name_len); 20586142Sjhb if (p > (char *)dp + isonum_711(dp->length)) 20686142Sjhb return (0); 20786142Sjhb sp = (ISO_SUSP_PRESENT *)p; 20886142Sjhb if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) 20986142Sjhb return (0); 21086142Sjhb if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) 21186142Sjhb return (0); 21286142Sjhb if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) 21386142Sjhb return (0); 21486142Sjhb *lenskip = isonum_711(sp->len_skp); 21586142Sjhb 21686142Sjhb /* 21786142Sjhb * Now look for an ER field. If RRIP is present, then there must 21886142Sjhb * be at least one of these. It would be more pedantic to walk 21986142Sjhb * through the list of fields looking for a Rock Ridge ER field. 22086142Sjhb */ 22186142Sjhb er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); 22286142Sjhb if (er == NULL) 22386142Sjhb return (0); 22486142Sjhb return (1); 22586142Sjhb} 22686142Sjhb 22786142Sjhbstatic int 22886142Sjhbdirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, 22986142Sjhb int use_rrip, int lenskip) 23086142Sjhb{ 231346477Skevans size_t len, plen; 232346477Skevans char *cp, *sep; 23386142Sjhb int i, icase; 23438451Smsmith 23586142Sjhb if (use_rrip) 23686142Sjhb cp = rrip_lookup_name(f, dp, lenskip, &len); 23786142Sjhb else 23886142Sjhb cp = NULL; 23986142Sjhb if (cp == NULL) { 24086142Sjhb len = isonum_711(dp->name_len); 24186142Sjhb cp = dp->name; 24286142Sjhb icase = 1; 24386142Sjhb } else 24486142Sjhb icase = 0; 245346477Skevans 246346477Skevans sep = strchr(path, '/'); 247346477Skevans if (sep != NULL) { 248346477Skevans plen = sep - path; 249346477Skevans } else { 250346477Skevans plen = strlen(path); 251346477Skevans } 252346477Skevans 253346477Skevans if (plen != len) 254346477Skevans return (0); 255346477Skevans 25686142Sjhb for (i = len; --i >= 0; path++, cp++) { 25756222Sobrien if (!*path || *path == '/') 25838451Smsmith break; 25986142Sjhb if (*path == *cp) 26038451Smsmith continue; 26186142Sjhb if (!icase && toupper(*path) == *cp) 26286142Sjhb continue; 26338451Smsmith return 0; 26438451Smsmith } 26556222Sobrien if (*path && *path != '/') 26638451Smsmith return 0; 26738451Smsmith /* 26838451Smsmith * Allow stripping of trailing dots and the version number. 26938451Smsmith * Note that this will find the first instead of the last version 27038451Smsmith * of a file. 27138451Smsmith */ 27238451Smsmith if (i >= 0 && (*cp == ';' || *cp == '.')) { 27338451Smsmith /* This is to prevent matching of numeric extensions */ 27438451Smsmith if (*cp == '.' && cp[1] != ';') 27538451Smsmith return 0; 27638451Smsmith while (--i >= 0) 27738451Smsmith if (*++cp != ';' && (*cp < '0' || *cp > '9')) 27838451Smsmith return 0; 27938451Smsmith } 28038451Smsmith return 1; 28138451Smsmith} 28238451Smsmith 28338451Smsmithstatic int 28486137Sjhbcd9660_open(const char *path, struct open_file *f) 28538451Smsmith{ 286298210Spfg struct file *fp = NULL; 28738451Smsmith void *buf; 28838451Smsmith struct iso_primary_descriptor *vd; 28956222Sobrien size_t buf_size, read, dsize, off; 29056222Sobrien daddr_t bno, boff; 29156222Sobrien struct iso_directory_record rec; 292298210Spfg struct iso_directory_record *dp = NULL; 29386142Sjhb int rc, first, use_rrip, lenskip; 294346477Skevans bool isdir = false; 29556223Sobrien 29638451Smsmith /* First find the volume descriptor */ 29738451Smsmith buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 29838451Smsmith vd = buf; 29938451Smsmith for (bno = 16;; bno++) { 300276079Sian twiddle(1); 30138451Smsmith rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 302313355Stsoome ISO_DEFAULT_BLOCK_SIZE, buf, &read); 30338451Smsmith if (rc) 30438451Smsmith goto out; 30538451Smsmith if (read != ISO_DEFAULT_BLOCK_SIZE) { 30638451Smsmith rc = EIO; 30738451Smsmith goto out; 30838451Smsmith } 30938451Smsmith rc = EINVAL; 31038451Smsmith if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 31138451Smsmith goto out; 31238451Smsmith if (isonum_711(vd->type) == ISO_VD_END) 31338451Smsmith goto out; 31438451Smsmith if (isonum_711(vd->type) == ISO_VD_PRIMARY) 31538451Smsmith break; 31638451Smsmith } 31738451Smsmith if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 31838451Smsmith goto out; 31956223Sobrien 320344408Skevans bcopy(vd->root_directory_record, &rec, sizeof(rec)); 32156222Sobrien if (*path == '/') path++; /* eat leading '/' */ 32238451Smsmith 32386142Sjhb first = 1; 32486142Sjhb use_rrip = 0; 325344266Skevans lenskip = 0; 32638451Smsmith while (*path) { 32756222Sobrien bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 32856222Sobrien dsize = isonum_733(rec.size); 32956222Sobrien off = 0; 33056222Sobrien boff = 0; 33156222Sobrien 33256222Sobrien while (off < dsize) { 33356222Sobrien if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 334276079Sian twiddle(1); 33556222Sobrien rc = f->f_dev->dv_strategy 33656222Sobrien (f->f_devdata, F_READ, 337313355Stsoome cdb2devb(bno + boff), 33856222Sobrien ISO_DEFAULT_BLOCK_SIZE, 33956222Sobrien buf, &read); 34056222Sobrien if (rc) 34156222Sobrien goto out; 34256222Sobrien if (read != ISO_DEFAULT_BLOCK_SIZE) { 34356222Sobrien rc = EIO; 34456222Sobrien goto out; 34556222Sobrien } 34656222Sobrien boff++; 34756222Sobrien dp = (struct iso_directory_record *) buf; 34856222Sobrien } 34956222Sobrien if (isonum_711(dp->length) == 0) { 35056222Sobrien /* skip to next block, if any */ 35156222Sobrien off = boff * ISO_DEFAULT_BLOCK_SIZE; 35256222Sobrien continue; 35356222Sobrien } 35456222Sobrien 35586142Sjhb /* See if RRIP is in use. */ 35686142Sjhb if (first) 35786142Sjhb use_rrip = rrip_check(f, dp, &lenskip); 35886142Sjhb 35986142Sjhb if (dirmatch(f, path, dp, use_rrip, 360344266Skevans first ? 0 : lenskip)) { 36186142Sjhb first = 0; 36238451Smsmith break; 36386142Sjhb } else 36486142Sjhb first = 0; 36538451Smsmith 36656222Sobrien dp = (struct iso_directory_record *) 36756222Sobrien ((char *) dp + isonum_711(dp->length)); 368329098Skevans /* If the new block has zero length, it is padding. */ 369329098Skevans if (isonum_711(dp->length) == 0) { 370329098Skevans /* Skip to next block, if any. */ 371329098Skevans off = boff * ISO_DEFAULT_BLOCK_SIZE; 372329098Skevans continue; 373329098Skevans } 37456222Sobrien off += isonum_711(dp->length); 37538451Smsmith } 37682208Sgallatin if (off >= dsize) { 37756222Sobrien rc = ENOENT; 37856222Sobrien goto out; 37938451Smsmith } 38038451Smsmith 38156222Sobrien rec = *dp; 38256222Sobrien while (*path && *path != '/') /* look for next component */ 38356222Sobrien path++; 384346477Skevans 385346477Skevans if (*path) /* this component was directory */ 386346477Skevans isdir = true; 387346477Skevans 388346477Skevans while (*path == '/') 389346477Skevans path++; /* skip '/' */ 390346477Skevans 391346477Skevans if (*path) /* We do have next component. */ 392346477Skevans isdir = false; 39338451Smsmith } 39456223Sobrien 395346477Skevans /* 396346477Skevans * if the path had trailing / but the path does point to file, 397346477Skevans * report the error ENOTDIR. 398346477Skevans */ 399346477Skevans if (isdir == true && (isonum_711(rec.flags) & 2) == 0) { 400346477Skevans rc = ENOTDIR; 401346477Skevans goto out; 402346477Skevans } 403346477Skevans 40438451Smsmith /* allocate file system specific data structure */ 40538451Smsmith fp = malloc(sizeof(struct file)); 40638451Smsmith bzero(fp, sizeof(struct file)); 40738451Smsmith f->f_fsdata = (void *)fp; 40838451Smsmith 40986158Sjhb if ((isonum_711(rec.flags) & 2) != 0) { 41086158Sjhb fp->f_flags = F_ISDIR; 41186158Sjhb } 41286158Sjhb if (first) { 41386158Sjhb fp->f_flags |= F_ROOTDIR; 41486158Sjhb 41586158Sjhb /* Check for Rock Ridge since we didn't in the loop above. */ 41686158Sjhb bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 417276079Sian twiddle(1); 41886158Sjhb rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 419313355Stsoome ISO_DEFAULT_BLOCK_SIZE, buf, &read); 42086158Sjhb if (rc) 42186158Sjhb goto out; 42286158Sjhb if (read != ISO_DEFAULT_BLOCK_SIZE) { 42386158Sjhb rc = EIO; 42486158Sjhb goto out; 42586158Sjhb } 42686158Sjhb dp = (struct iso_directory_record *)buf; 42786158Sjhb use_rrip = rrip_check(f, dp, &lenskip); 42886158Sjhb } 42986158Sjhb if (use_rrip) { 43086158Sjhb fp->f_flags |= F_RR; 43186158Sjhb fp->f_susp_skip = lenskip; 43286158Sjhb } 43359766Sjlemon fp->f_off = 0; 43459766Sjlemon fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 43559766Sjlemon fp->f_size = isonum_733(rec.size); 43638451Smsmith free(buf); 43756223Sobrien 43838451Smsmith return 0; 43956223Sobrien 44038451Smsmithout: 44138451Smsmith if (fp) 44238451Smsmith free(fp); 44338451Smsmith free(buf); 44456223Sobrien 44538451Smsmith return rc; 44638451Smsmith} 44738451Smsmith 44838451Smsmithstatic int 44986137Sjhbcd9660_close(struct open_file *f) 45038451Smsmith{ 45138451Smsmith struct file *fp = (struct file *)f->f_fsdata; 45256223Sobrien 453298210Spfg f->f_fsdata = NULL; 45438451Smsmith free(fp); 45556223Sobrien 45638451Smsmith return 0; 45738451Smsmith} 45838451Smsmith 45938451Smsmithstatic int 46086137Sjhbbuf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 46138451Smsmith{ 46238451Smsmith struct file *fp = (struct file *)f->f_fsdata; 46375298Sgallatin daddr_t blkno, blkoff; 46438451Smsmith int rc = 0; 46559766Sjlemon size_t read; 46656223Sobrien 46759766Sjlemon blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; 46875298Sgallatin blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; 46959766Sjlemon 47059766Sjlemon if (blkno != fp->f_buf_blkno) { 47159766Sjlemon if (fp->f_buf == (char *)0) 47259766Sjlemon fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); 47359766Sjlemon 474276079Sian twiddle(16); 47559766Sjlemon rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 476313355Stsoome cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, 477298230Sallanjude fp->f_buf, &read); 47838451Smsmith if (rc) 47959766Sjlemon return (rc); 48038451Smsmith if (read != ISO_DEFAULT_BLOCK_SIZE) 48159766Sjlemon return (EIO); 48259766Sjlemon 48359766Sjlemon fp->f_buf_blkno = blkno; 48438451Smsmith } 48559766Sjlemon 48675298Sgallatin *buf_p = fp->f_buf + blkoff; 48775298Sgallatin *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; 48859766Sjlemon 48959766Sjlemon if (*size_p > fp->f_size - fp->f_off) 49059766Sjlemon *size_p = fp->f_size - fp->f_off; 49159766Sjlemon return (rc); 49238451Smsmith} 49338451Smsmith 49438451Smsmithstatic int 49586137Sjhbcd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) 49656222Sobrien{ 49756222Sobrien struct file *fp = (struct file *)f->f_fsdata; 49859766Sjlemon char *buf, *addr; 49959766Sjlemon size_t buf_size, csize; 50056222Sobrien int rc = 0; 50156223Sobrien 50259766Sjlemon addr = start; 50359766Sjlemon while (size) { 50459766Sjlemon if (fp->f_off < 0 || fp->f_off >= fp->f_size) 50559766Sjlemon break; 50656222Sobrien 50759766Sjlemon rc = buf_read_file(f, &buf, &buf_size); 50856222Sobrien if (rc) 50956222Sobrien break; 51056222Sobrien 51159766Sjlemon csize = size > buf_size ? buf_size : size; 51259766Sjlemon bcopy(buf, addr, csize); 51356222Sobrien 51459766Sjlemon fp->f_off += csize; 51559766Sjlemon addr += csize; 51659766Sjlemon size -= csize; 51756222Sobrien } 51856222Sobrien if (resid) 51959766Sjlemon *resid = size; 52059766Sjlemon return (rc); 52156222Sobrien} 52256222Sobrien 52356222Sobrienstatic int 52459766Sjlemoncd9660_readdir(struct open_file *f, struct dirent *d) 52556222Sobrien{ 52656222Sobrien struct file *fp = (struct file *)f->f_fsdata; 52759766Sjlemon struct iso_directory_record *ep; 52859766Sjlemon size_t buf_size, reclen, namelen; 52959766Sjlemon int error = 0; 53086158Sjhb int lenskip; 53186158Sjhb char *buf, *name; 53256222Sobrien 53359766Sjlemonagain: 53459766Sjlemon if (fp->f_off >= fp->f_size) 53559766Sjlemon return (ENOENT); 53659766Sjlemon error = buf_read_file(f, &buf, &buf_size); 53759766Sjlemon if (error) 53859766Sjlemon return (error); 53959766Sjlemon ep = (struct iso_directory_record *)buf; 54059766Sjlemon 54159766Sjlemon if (isonum_711(ep->length) == 0) { 54259766Sjlemon daddr_t blkno; 54359766Sjlemon 54459766Sjlemon /* skip to next block, if any */ 54559766Sjlemon blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; 54659766Sjlemon fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; 54759766Sjlemon goto again; 54859766Sjlemon } 54959766Sjlemon 55086158Sjhb if (fp->f_flags & F_RR) { 55186158Sjhb if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) 55286158Sjhb lenskip = 0; 55386158Sjhb else 55486158Sjhb lenskip = fp->f_susp_skip; 55586158Sjhb name = rrip_lookup_name(f, ep, lenskip, &namelen); 55686158Sjhb } else 55786158Sjhb name = NULL; 55886158Sjhb if (name == NULL) { 55986158Sjhb namelen = isonum_711(ep->name_len); 56086158Sjhb name = ep->name; 56186158Sjhb if (namelen == 1) { 56286158Sjhb if (ep->name[0] == 0) 56386158Sjhb name = "."; 56486158Sjhb else if (ep->name[0] == 1) { 56586158Sjhb namelen = 2; 56686158Sjhb name = ".."; 56786158Sjhb } 56886158Sjhb } 56986158Sjhb } 57059766Sjlemon reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; 57159766Sjlemon reclen = (reclen + 3) & ~3; 57259766Sjlemon 57359766Sjlemon d->d_fileno = isonum_733(ep->extent); 57459766Sjlemon d->d_reclen = reclen; 57559766Sjlemon if (isonum_711(ep->flags) & 2) 57659766Sjlemon d->d_type = DT_DIR; 57756222Sobrien else 57859766Sjlemon d->d_type = DT_REG; 57959766Sjlemon d->d_namlen = namelen; 58059766Sjlemon 58186158Sjhb bcopy(name, d->d_name, d->d_namlen); 58259766Sjlemon d->d_name[d->d_namlen] = 0; 58359766Sjlemon 58459766Sjlemon fp->f_off += isonum_711(ep->length); 58559766Sjlemon return (0); 58656222Sobrien} 58756222Sobrien 58838451Smsmithstatic off_t 58986137Sjhbcd9660_seek(struct open_file *f, off_t offset, int where) 59038451Smsmith{ 59138451Smsmith struct file *fp = (struct file *)f->f_fsdata; 59256223Sobrien 59338451Smsmith switch (where) { 59438451Smsmith case SEEK_SET: 59559766Sjlemon fp->f_off = offset; 59638451Smsmith break; 59738451Smsmith case SEEK_CUR: 59859766Sjlemon fp->f_off += offset; 59938451Smsmith break; 60038451Smsmith case SEEK_END: 60159766Sjlemon fp->f_off = fp->f_size - offset; 60238451Smsmith break; 60338451Smsmith default: 60438451Smsmith return -1; 60538451Smsmith } 60659766Sjlemon return fp->f_off; 60738451Smsmith} 60838451Smsmith 60938451Smsmithstatic int 61086137Sjhbcd9660_stat(struct open_file *f, struct stat *sb) 61138451Smsmith{ 61238451Smsmith struct file *fp = (struct file *)f->f_fsdata; 61356223Sobrien 61456222Sobrien /* only important stuff */ 61556222Sobrien sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; 61686158Sjhb if (fp->f_flags & F_ISDIR) 61756222Sobrien sb->st_mode |= S_IFDIR; 61856222Sobrien else 61956222Sobrien sb->st_mode |= S_IFREG; 62038451Smsmith sb->st_uid = sb->st_gid = 0; 62159766Sjlemon sb->st_size = fp->f_size; 62238451Smsmith return 0; 62338451Smsmith} 624