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$"); 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> 4556222Sobrien#include <sys/dirent.h> 4638451Smsmith#include <isofs/cd9660/iso.h> 4786142Sjhb#include <isofs/cd9660/cd9660_rrip.h> 4838451Smsmith 4938451Smsmith#include "stand.h" 5038451Smsmith 5186142Sjhb#define SUSP_CONTINUATION "CE" 5286142Sjhb#define SUSP_PRESENT "SP" 5386142Sjhb#define SUSP_STOP "ST" 5486142Sjhb#define SUSP_EXTREF "ER" 5586142Sjhb#define RRIP_NAME "NM" 5686142Sjhb 5786142Sjhbtypedef struct { 5886142Sjhb ISO_SUSP_HEADER h; 5986142Sjhb u_char signature [ISODCL ( 5, 6)]; 6086142Sjhb u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 6186142Sjhb} ISO_SUSP_PRESENT; 6286142Sjhb 6386137Sjhbstatic int buf_read_file(struct open_file *f, char **buf_p, 6486137Sjhb size_t *size_p); 6539468Smsmithstatic int cd9660_open(const char *path, struct open_file *f); 6638451Smsmithstatic int cd9660_close(struct open_file *f); 6786137Sjhbstatic int cd9660_read(struct open_file *f, void *buf, size_t size, 6886137Sjhb size_t *resid); 6986137Sjhbstatic int cd9660_write(struct open_file *f, void *buf, size_t size, 7086137Sjhb size_t *resid); 7138451Smsmithstatic off_t cd9660_seek(struct open_file *f, off_t offset, int where); 7238451Smsmithstatic int cd9660_stat(struct open_file *f, struct stat *sb); 7359766Sjlemonstatic int cd9660_readdir(struct open_file *f, struct dirent *d); 7486142Sjhbstatic int dirmatch(struct open_file *f, const char *path, 7586142Sjhb struct iso_directory_record *dp, int use_rrip, int lenskip); 7686142Sjhbstatic int rrip_check(struct open_file *f, struct iso_directory_record *dp, 7786142Sjhb int *lenskip); 7886142Sjhbstatic char *rrip_lookup_name(struct open_file *f, 7986142Sjhb struct iso_directory_record *dp, int lenskip, size_t *len); 8086142Sjhbstatic ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, 8186142Sjhb const char *identifier, struct iso_directory_record *dp, 8286142Sjhb int lenskip); 8338451Smsmith 8438451Smsmithstruct fs_ops cd9660_fsops = { 8559766Sjlemon "cd9660", 8659766Sjlemon cd9660_open, 8759766Sjlemon cd9660_close, 8859766Sjlemon cd9660_read, 8959766Sjlemon cd9660_write, 9059766Sjlemon cd9660_seek, 9159766Sjlemon cd9660_stat, 9259766Sjlemon cd9660_readdir 9338451Smsmith}; 9438451Smsmith 9586158Sjhb#define F_ISDIR 0x0001 /* Directory */ 9686158Sjhb#define F_ROOTDIR 0x0002 /* Root directory */ 9786158Sjhb#define F_RR 0x0004 /* Rock Ridge on this volume */ 9886158Sjhb 9938451Smsmithstruct file { 10086158Sjhb int f_flags; /* file flags */ 10159766Sjlemon off_t f_off; /* Current offset within file */ 10259766Sjlemon daddr_t f_bno; /* Starting block number */ 10359766Sjlemon off_t f_size; /* Size of file */ 10459766Sjlemon daddr_t f_buf_blkno; /* block number of data block */ 10559766Sjlemon char *f_buf; /* buffer for data block */ 10686158Sjhb int f_susp_skip; /* len_skip for SUSP records */ 10738451Smsmith}; 10838451Smsmith 10938451Smsmithstruct ptable_ent { 11038451Smsmith char namlen [ISODCL( 1, 1)]; /* 711 */ 11138451Smsmith char extlen [ISODCL( 2, 2)]; /* 711 */ 11238451Smsmith char block [ISODCL( 3, 6)]; /* 732 */ 11338451Smsmith char parent [ISODCL( 7, 8)]; /* 722 */ 11438451Smsmith char name [1]; 11538451Smsmith}; 11638451Smsmith#define PTFIXSZ 8 11738451Smsmith#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 11838451Smsmith 11938451Smsmith#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 12038451Smsmith 12186142Sjhbstatic ISO_SUSP_HEADER * 12286142Sjhbsusp_lookup_record(struct open_file *f, const char *identifier, 12386142Sjhb struct iso_directory_record *dp, int lenskip) 12486142Sjhb{ 12586142Sjhb static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 12686142Sjhb ISO_SUSP_HEADER *sh; 12786142Sjhb ISO_RRIP_CONT *shc; 12886142Sjhb char *p, *end; 12986142Sjhb int error; 13086142Sjhb size_t read; 13186142Sjhb 13286142Sjhb p = dp->name + isonum_711(dp->name_len) + lenskip; 13386142Sjhb /* Names of even length have a padding byte after the name. */ 13486142Sjhb if ((isonum_711(dp->name_len) & 1) == 0) 13586142Sjhb p++; 13686142Sjhb end = (char *)dp + isonum_711(dp->length); 13786142Sjhb while (p + 3 < end) { 13886142Sjhb sh = (ISO_SUSP_HEADER *)p; 13986142Sjhb if (bcmp(sh->type, identifier, 2) == 0) 14086142Sjhb return (sh); 14186142Sjhb if (bcmp(sh->type, SUSP_STOP, 2) == 0) 14286142Sjhb return (NULL); 14386142Sjhb if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 14486142Sjhb shc = (ISO_RRIP_CONT *)sh; 14586142Sjhb error = f->f_dev->dv_strategy(f->f_devdata, F_READ, 14686142Sjhb cdb2devb(isonum_733(shc->location)), 14786142Sjhb ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); 14886142Sjhb 14986142Sjhb /* Bail if it fails. */ 15086142Sjhb if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) 15186142Sjhb return (NULL); 15286142Sjhb p = susp_buffer + isonum_733(shc->offset); 15386142Sjhb end = p + isonum_733(shc->length); 15486142Sjhb } else 15586142Sjhb /* Ignore this record and skip to the next. */ 15686142Sjhb p += isonum_711(sh->length); 15786142Sjhb } 15886142Sjhb return (NULL); 15986142Sjhb} 16086142Sjhb 16186142Sjhbstatic char * 16286142Sjhbrrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, 16386142Sjhb int lenskip, size_t *len) 16486142Sjhb{ 16586142Sjhb ISO_RRIP_ALTNAME *p; 16686142Sjhb 16786142Sjhb if (len == NULL) 16886142Sjhb return (NULL); 16986142Sjhb 17086142Sjhb p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); 17186142Sjhb if (p == NULL) 17286142Sjhb return (NULL); 17386142Sjhb switch (*p->flags) { 17486142Sjhb case ISO_SUSP_CFLAG_CURRENT: 17586142Sjhb *len = 1; 17686142Sjhb return ("."); 17786142Sjhb case ISO_SUSP_CFLAG_PARENT: 17886142Sjhb *len = 2; 17986142Sjhb return (".."); 18086142Sjhb case 0: 18186142Sjhb *len = isonum_711(p->h.length) - 5; 18286142Sjhb return ((char *)p + 5); 18386142Sjhb default: 18486142Sjhb /* 18586142Sjhb * We don't handle hostnames or continued names as they are 18686142Sjhb * too hard, so just bail and use the default name. 18786142Sjhb */ 18886142Sjhb return (NULL); 18986142Sjhb } 19086142Sjhb} 19186142Sjhb 19238451Smsmithstatic int 19386142Sjhbrrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) 19438451Smsmith{ 19586142Sjhb ISO_SUSP_PRESENT *sp; 19686142Sjhb ISO_RRIP_EXTREF *er; 19786142Sjhb char *p; 19886142Sjhb 19986142Sjhb /* First, see if we can find a SP field. */ 20086142Sjhb p = dp->name + isonum_711(dp->name_len); 20186142Sjhb if (p > (char *)dp + isonum_711(dp->length)) 20286142Sjhb return (0); 20386142Sjhb sp = (ISO_SUSP_PRESENT *)p; 20486142Sjhb if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) 20586142Sjhb return (0); 20686142Sjhb if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) 20786142Sjhb return (0); 20886142Sjhb if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) 20986142Sjhb return (0); 21086142Sjhb *lenskip = isonum_711(sp->len_skp); 21186142Sjhb 21286142Sjhb /* 21386142Sjhb * Now look for an ER field. If RRIP is present, then there must 21486142Sjhb * be at least one of these. It would be more pedantic to walk 21586142Sjhb * through the list of fields looking for a Rock Ridge ER field. 21686142Sjhb */ 21786142Sjhb er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); 21886142Sjhb if (er == NULL) 21986142Sjhb return (0); 22086142Sjhb return (1); 22186142Sjhb} 22286142Sjhb 22386142Sjhbstatic int 22486142Sjhbdirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, 22586142Sjhb int use_rrip, int lenskip) 22686142Sjhb{ 22786142Sjhb size_t len; 22838451Smsmith char *cp; 22986142Sjhb int i, icase; 23038451Smsmith 23186142Sjhb if (use_rrip) 23286142Sjhb cp = rrip_lookup_name(f, dp, lenskip, &len); 23386142Sjhb else 23486142Sjhb cp = NULL; 23586142Sjhb if (cp == NULL) { 23686142Sjhb len = isonum_711(dp->name_len); 23786142Sjhb cp = dp->name; 23886142Sjhb icase = 1; 23986142Sjhb } else 24086142Sjhb icase = 0; 24186142Sjhb for (i = len; --i >= 0; path++, cp++) { 24256222Sobrien if (!*path || *path == '/') 24338451Smsmith break; 24486142Sjhb if (*path == *cp) 24538451Smsmith continue; 24686142Sjhb if (!icase && toupper(*path) == *cp) 24786142Sjhb continue; 24838451Smsmith return 0; 24938451Smsmith } 25056222Sobrien if (*path && *path != '/') 25138451Smsmith return 0; 25238451Smsmith /* 25338451Smsmith * Allow stripping of trailing dots and the version number. 25438451Smsmith * Note that this will find the first instead of the last version 25538451Smsmith * of a file. 25638451Smsmith */ 25738451Smsmith if (i >= 0 && (*cp == ';' || *cp == '.')) { 25838451Smsmith /* This is to prevent matching of numeric extensions */ 25938451Smsmith if (*cp == '.' && cp[1] != ';') 26038451Smsmith return 0; 26138451Smsmith while (--i >= 0) 26238451Smsmith if (*++cp != ';' && (*cp < '0' || *cp > '9')) 26338451Smsmith return 0; 26438451Smsmith } 26538451Smsmith return 1; 26638451Smsmith} 26738451Smsmith 26838451Smsmithstatic int 26986137Sjhbcd9660_open(const char *path, struct open_file *f) 27038451Smsmith{ 27138451Smsmith struct file *fp = 0; 27238451Smsmith void *buf; 27338451Smsmith struct iso_primary_descriptor *vd; 27456222Sobrien size_t buf_size, read, dsize, off; 27556222Sobrien daddr_t bno, boff; 27656222Sobrien struct iso_directory_record rec; 27738451Smsmith struct iso_directory_record *dp = 0; 27886142Sjhb int rc, first, use_rrip, lenskip; 27956223Sobrien 28038451Smsmith /* First find the volume descriptor */ 28138451Smsmith buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 28238451Smsmith vd = buf; 28338451Smsmith for (bno = 16;; bno++) { 28438451Smsmith twiddle(); 28538451Smsmith rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 28638451Smsmith ISO_DEFAULT_BLOCK_SIZE, buf, &read); 28738451Smsmith if (rc) 28838451Smsmith goto out; 28938451Smsmith if (read != ISO_DEFAULT_BLOCK_SIZE) { 29038451Smsmith rc = EIO; 29138451Smsmith goto out; 29238451Smsmith } 29338451Smsmith rc = EINVAL; 29438451Smsmith if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 29538451Smsmith goto out; 29638451Smsmith if (isonum_711(vd->type) == ISO_VD_END) 29738451Smsmith goto out; 29838451Smsmith if (isonum_711(vd->type) == ISO_VD_PRIMARY) 29938451Smsmith break; 30038451Smsmith } 30138451Smsmith if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 30238451Smsmith goto out; 30356223Sobrien 30456222Sobrien rec = *(struct iso_directory_record *) vd->root_directory_record; 30556222Sobrien if (*path == '/') path++; /* eat leading '/' */ 30638451Smsmith 30786142Sjhb first = 1; 30886142Sjhb use_rrip = 0; 30938451Smsmith while (*path) { 31056222Sobrien bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 31156222Sobrien dsize = isonum_733(rec.size); 31256222Sobrien off = 0; 31356222Sobrien boff = 0; 31456222Sobrien 31556222Sobrien while (off < dsize) { 31656222Sobrien if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 31756222Sobrien twiddle(); 31856222Sobrien rc = f->f_dev->dv_strategy 31956222Sobrien (f->f_devdata, F_READ, 32056222Sobrien cdb2devb(bno + boff), 32156222Sobrien ISO_DEFAULT_BLOCK_SIZE, 32256222Sobrien buf, &read); 32356222Sobrien if (rc) 32456222Sobrien goto out; 32556222Sobrien if (read != ISO_DEFAULT_BLOCK_SIZE) { 32656222Sobrien rc = EIO; 32756222Sobrien goto out; 32856222Sobrien } 32956222Sobrien boff++; 33056222Sobrien dp = (struct iso_directory_record *) buf; 33156222Sobrien } 33256222Sobrien if (isonum_711(dp->length) == 0) { 33356222Sobrien /* skip to next block, if any */ 33456222Sobrien off = boff * ISO_DEFAULT_BLOCK_SIZE; 33556222Sobrien continue; 33656222Sobrien } 33756222Sobrien 33886142Sjhb /* See if RRIP is in use. */ 33986142Sjhb if (first) 34086142Sjhb use_rrip = rrip_check(f, dp, &lenskip); 34186142Sjhb 34286142Sjhb if (dirmatch(f, path, dp, use_rrip, 34386142Sjhb first ? 0 : lenskip)) { 34486142Sjhb first = 0; 34538451Smsmith break; 34686142Sjhb } else 34786142Sjhb first = 0; 34838451Smsmith 34956222Sobrien dp = (struct iso_directory_record *) 35056222Sobrien ((char *) dp + isonum_711(dp->length)); 35156222Sobrien off += isonum_711(dp->length); 35238451Smsmith } 35382208Sgallatin if (off >= dsize) { 35456222Sobrien rc = ENOENT; 35556222Sobrien goto out; 35638451Smsmith } 35738451Smsmith 35856222Sobrien rec = *dp; 35956222Sobrien while (*path && *path != '/') /* look for next component */ 36056222Sobrien path++; 36156222Sobrien if (*path) path++; /* skip '/' */ 36238451Smsmith } 36356223Sobrien 36438451Smsmith /* allocate file system specific data structure */ 36538451Smsmith fp = malloc(sizeof(struct file)); 36638451Smsmith bzero(fp, sizeof(struct file)); 36738451Smsmith f->f_fsdata = (void *)fp; 36838451Smsmith 36986158Sjhb if ((isonum_711(rec.flags) & 2) != 0) { 37086158Sjhb fp->f_flags = F_ISDIR; 37186158Sjhb } 37286158Sjhb if (first) { 37386158Sjhb fp->f_flags |= F_ROOTDIR; 37486158Sjhb 37586158Sjhb /* Check for Rock Ridge since we didn't in the loop above. */ 37686158Sjhb bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 37786158Sjhb twiddle(); 37886158Sjhb rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 37986158Sjhb ISO_DEFAULT_BLOCK_SIZE, buf, &read); 38086158Sjhb if (rc) 38186158Sjhb goto out; 38286158Sjhb if (read != ISO_DEFAULT_BLOCK_SIZE) { 38386158Sjhb rc = EIO; 38486158Sjhb goto out; 38586158Sjhb } 38686158Sjhb dp = (struct iso_directory_record *)buf; 38786158Sjhb use_rrip = rrip_check(f, dp, &lenskip); 38886158Sjhb } 38986158Sjhb if (use_rrip) { 39086158Sjhb fp->f_flags |= F_RR; 39186158Sjhb fp->f_susp_skip = lenskip; 39286158Sjhb } 39359766Sjlemon fp->f_off = 0; 39459766Sjlemon fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 39559766Sjlemon fp->f_size = isonum_733(rec.size); 39638451Smsmith free(buf); 39756223Sobrien 39838451Smsmith return 0; 39956223Sobrien 40038451Smsmithout: 40138451Smsmith if (fp) 40238451Smsmith free(fp); 40338451Smsmith free(buf); 40456223Sobrien 40538451Smsmith return rc; 40638451Smsmith} 40738451Smsmith 40838451Smsmithstatic int 40986137Sjhbcd9660_close(struct open_file *f) 41038451Smsmith{ 41138451Smsmith struct file *fp = (struct file *)f->f_fsdata; 41256223Sobrien 41338451Smsmith f->f_fsdata = 0; 41438451Smsmith free(fp); 41556223Sobrien 41638451Smsmith return 0; 41738451Smsmith} 41838451Smsmith 41938451Smsmithstatic int 42086137Sjhbbuf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 42138451Smsmith{ 42238451Smsmith struct file *fp = (struct file *)f->f_fsdata; 42375298Sgallatin daddr_t blkno, blkoff; 42438451Smsmith int rc = 0; 42559766Sjlemon size_t read; 42656223Sobrien 42759766Sjlemon blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; 42875298Sgallatin blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; 42959766Sjlemon 43059766Sjlemon if (blkno != fp->f_buf_blkno) { 43159766Sjlemon if (fp->f_buf == (char *)0) 43259766Sjlemon fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); 43359766Sjlemon 43456223Sobrien twiddle(); 43559766Sjlemon rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 43659766Sjlemon cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, fp->f_buf, &read); 43738451Smsmith if (rc) 43859766Sjlemon return (rc); 43938451Smsmith if (read != ISO_DEFAULT_BLOCK_SIZE) 44059766Sjlemon return (EIO); 44159766Sjlemon 44259766Sjlemon fp->f_buf_blkno = blkno; 44338451Smsmith } 44459766Sjlemon 44575298Sgallatin *buf_p = fp->f_buf + blkoff; 44675298Sgallatin *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; 44759766Sjlemon 44859766Sjlemon if (*size_p > fp->f_size - fp->f_off) 44959766Sjlemon *size_p = fp->f_size - fp->f_off; 45059766Sjlemon return (rc); 45138451Smsmith} 45238451Smsmith 45338451Smsmithstatic int 45486137Sjhbcd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) 45556222Sobrien{ 45656222Sobrien struct file *fp = (struct file *)f->f_fsdata; 45759766Sjlemon char *buf, *addr; 45859766Sjlemon size_t buf_size, csize; 45956222Sobrien int rc = 0; 46056223Sobrien 46159766Sjlemon addr = start; 46259766Sjlemon while (size) { 46359766Sjlemon if (fp->f_off < 0 || fp->f_off >= fp->f_size) 46459766Sjlemon break; 46556222Sobrien 46659766Sjlemon rc = buf_read_file(f, &buf, &buf_size); 46756222Sobrien if (rc) 46856222Sobrien break; 46956222Sobrien 47059766Sjlemon csize = size > buf_size ? buf_size : size; 47159766Sjlemon bcopy(buf, addr, csize); 47256222Sobrien 47359766Sjlemon fp->f_off += csize; 47459766Sjlemon addr += csize; 47559766Sjlemon size -= csize; 47656222Sobrien } 47756222Sobrien if (resid) 47859766Sjlemon *resid = size; 47959766Sjlemon return (rc); 48056222Sobrien} 48156222Sobrien 48256222Sobrienstatic int 48359766Sjlemoncd9660_readdir(struct open_file *f, struct dirent *d) 48456222Sobrien{ 48556222Sobrien struct file *fp = (struct file *)f->f_fsdata; 48659766Sjlemon struct iso_directory_record *ep; 48759766Sjlemon size_t buf_size, reclen, namelen; 48859766Sjlemon int error = 0; 48986158Sjhb int lenskip; 49086158Sjhb char *buf, *name; 49156222Sobrien 49259766Sjlemonagain: 49359766Sjlemon if (fp->f_off >= fp->f_size) 49459766Sjlemon return (ENOENT); 49559766Sjlemon error = buf_read_file(f, &buf, &buf_size); 49659766Sjlemon if (error) 49759766Sjlemon return (error); 49859766Sjlemon ep = (struct iso_directory_record *)buf; 49959766Sjlemon 50059766Sjlemon if (isonum_711(ep->length) == 0) { 50159766Sjlemon daddr_t blkno; 50259766Sjlemon 50359766Sjlemon /* skip to next block, if any */ 50459766Sjlemon blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; 50559766Sjlemon fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; 50659766Sjlemon goto again; 50759766Sjlemon } 50859766Sjlemon 50986158Sjhb if (fp->f_flags & F_RR) { 51086158Sjhb if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) 51186158Sjhb lenskip = 0; 51286158Sjhb else 51386158Sjhb lenskip = fp->f_susp_skip; 51486158Sjhb name = rrip_lookup_name(f, ep, lenskip, &namelen); 51586158Sjhb } else 51686158Sjhb name = NULL; 51786158Sjhb if (name == NULL) { 51886158Sjhb namelen = isonum_711(ep->name_len); 51986158Sjhb name = ep->name; 52086158Sjhb if (namelen == 1) { 52186158Sjhb if (ep->name[0] == 0) 52286158Sjhb name = "."; 52386158Sjhb else if (ep->name[0] == 1) { 52486158Sjhb namelen = 2; 52586158Sjhb name = ".."; 52686158Sjhb } 52786158Sjhb } 52886158Sjhb } 52959766Sjlemon reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; 53059766Sjlemon reclen = (reclen + 3) & ~3; 53159766Sjlemon 53259766Sjlemon d->d_fileno = isonum_733(ep->extent); 53359766Sjlemon d->d_reclen = reclen; 53459766Sjlemon if (isonum_711(ep->flags) & 2) 53559766Sjlemon d->d_type = DT_DIR; 53656222Sobrien else 53759766Sjlemon d->d_type = DT_REG; 53859766Sjlemon d->d_namlen = namelen; 53959766Sjlemon 54086158Sjhb bcopy(name, d->d_name, d->d_namlen); 54159766Sjlemon d->d_name[d->d_namlen] = 0; 54259766Sjlemon 54359766Sjlemon fp->f_off += isonum_711(ep->length); 54459766Sjlemon return (0); 54556222Sobrien} 54656222Sobrien 54756222Sobrienstatic int 548221358Srodrigccd9660_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused) 54938451Smsmith{ 55038451Smsmith return EROFS; 55138451Smsmith} 55238451Smsmith 55338451Smsmithstatic off_t 55486137Sjhbcd9660_seek(struct open_file *f, off_t offset, int where) 55538451Smsmith{ 55638451Smsmith struct file *fp = (struct file *)f->f_fsdata; 55756223Sobrien 55838451Smsmith switch (where) { 55938451Smsmith case SEEK_SET: 56059766Sjlemon fp->f_off = offset; 56138451Smsmith break; 56238451Smsmith case SEEK_CUR: 56359766Sjlemon fp->f_off += offset; 56438451Smsmith break; 56538451Smsmith case SEEK_END: 56659766Sjlemon fp->f_off = fp->f_size - offset; 56738451Smsmith break; 56838451Smsmith default: 56938451Smsmith return -1; 57038451Smsmith } 57159766Sjlemon return fp->f_off; 57238451Smsmith} 57338451Smsmith 57438451Smsmithstatic int 57586137Sjhbcd9660_stat(struct open_file *f, struct stat *sb) 57638451Smsmith{ 57738451Smsmith struct file *fp = (struct file *)f->f_fsdata; 57856223Sobrien 57956222Sobrien /* only important stuff */ 58056222Sobrien sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; 58186158Sjhb if (fp->f_flags & F_ISDIR) 58256222Sobrien sb->st_mode |= S_IFDIR; 58356222Sobrien else 58456222Sobrien sb->st_mode |= S_IFREG; 58538451Smsmith sb->st_uid = sb->st_gid = 0; 58659766Sjlemon sb->st_size = fp->f_size; 58738451Smsmith return 0; 58838451Smsmith} 589