1332084Sbenno/* 2332084Sbenno * Copyright (C) 1996 Wolfgang Solfrank. 3332084Sbenno * Copyright (C) 1996 TooLs GmbH. 4332084Sbenno * All rights reserved. 5332084Sbenno * 6332084Sbenno * Redistribution and use in source and binary forms, with or without 7332084Sbenno * modification, are permitted provided that the following conditions 8332084Sbenno * are met: 9332084Sbenno * 1. Redistributions of source code must retain the above copyright 10332084Sbenno * notice, this list of conditions and the following disclaimer. 11332084Sbenno * 2. Redistributions in binary form must reproduce the above copyright 12332084Sbenno * notice, this list of conditions and the following disclaimer in the 13332084Sbenno * documentation and/or other materials provided with the distribution. 14332084Sbenno * 3. All advertising materials mentioning features or use of this software 15332084Sbenno * must display the following acknowledgement: 16332084Sbenno * This product includes software developed by TooLs GmbH. 17332084Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products 18332084Sbenno * derived from this software without specific prior written permission. 19332084Sbenno * 20332084Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21332084Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22332084Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23332084Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24332084Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25332084Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26332084Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27332084Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28332084Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29332084Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30332084Sbenno */ 31332084Sbenno 32332084Sbenno/* Originally derived from libsa/cd9660.c: */ 33332084Sbenno/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ 34332084Sbenno 35332084Sbenno#include <sys/cdefs.h> 36332084Sbenno__FBSDID("$FreeBSD: stable/11/stand/libsa/cd9660read.c 344408 2019-02-21 02:43:48Z kevans $"); 37332084Sbenno 38332084Sbenno#include <fs/cd9660/iso.h> 39332084Sbenno#include <fs/cd9660/cd9660_rrip.h> 40332084Sbenno 41332084Sbennostatic uint64_t cd9660_lookup(const char *); 42332084Sbennostatic ssize_t cd9660_fsread(uint64_t, void *, size_t); 43332084Sbenno 44332084Sbenno#define SUSP_CONTINUATION "CE" 45332084Sbenno#define SUSP_PRESENT "SP" 46332084Sbenno#define SUSP_STOP "ST" 47332084Sbenno#define SUSP_EXTREF "ER" 48332084Sbenno#define RRIP_NAME "NM" 49332084Sbenno 50332084Sbennotypedef struct { 51332084Sbenno ISO_SUSP_HEADER h; 52332084Sbenno u_char signature [ISODCL ( 5, 6)]; 53332084Sbenno u_char len_skp [ISODCL ( 7, 7)]; /* 711 */ 54332084Sbenno} ISO_SUSP_PRESENT; 55332084Sbenno 56332084Sbennostatic int 57332084Sbennoread_iso_block(void *buffer, daddr_t blkno) 58332084Sbenno{ 59332084Sbenno 60332084Sbenno return (drvread(&dsk, buffer, blkno * 4, 4)); 61332084Sbenno} 62332084Sbenno 63332084Sbennostatic ISO_SUSP_HEADER * 64332084Sbennosusp_lookup_record(const char *identifier, struct iso_directory_record *dp, 65332084Sbenno int lenskip) 66332084Sbenno{ 67332084Sbenno static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; 68332084Sbenno ISO_SUSP_HEADER *sh; 69332084Sbenno ISO_RRIP_CONT *shc; 70332084Sbenno char *p, *end; 71332084Sbenno int error; 72332084Sbenno 73332084Sbenno p = dp->name + isonum_711(dp->name_len) + lenskip; 74332084Sbenno /* Names of even length have a padding byte after the name. */ 75332084Sbenno if ((isonum_711(dp->name_len) & 1) == 0) 76332084Sbenno p++; 77332084Sbenno end = (char *)dp + isonum_711(dp->length); 78332084Sbenno while (p + 3 < end) { 79332084Sbenno sh = (ISO_SUSP_HEADER *)p; 80332084Sbenno if (bcmp(sh->type, identifier, 2) == 0) 81332084Sbenno return (sh); 82332084Sbenno if (bcmp(sh->type, SUSP_STOP, 2) == 0) 83332084Sbenno return (NULL); 84332084Sbenno if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { 85332084Sbenno shc = (ISO_RRIP_CONT *)sh; 86332084Sbenno error = read_iso_block(susp_buffer, 87332084Sbenno isonum_733(shc->location)); 88332084Sbenno 89332084Sbenno /* Bail if it fails. */ 90332084Sbenno if (error != 0) 91332084Sbenno return (NULL); 92332084Sbenno p = susp_buffer + isonum_733(shc->offset); 93332084Sbenno end = p + isonum_733(shc->length); 94332084Sbenno } else { 95332084Sbenno /* Ignore this record and skip to the next. */ 96332084Sbenno p += isonum_711(sh->length); 97332084Sbenno 98332084Sbenno /* Avoid infinite loops with corrupted file systems */ 99332084Sbenno if (isonum_711(sh->length) == 0) 100332084Sbenno return (NULL); 101332084Sbenno } 102332084Sbenno } 103332084Sbenno return (NULL); 104332084Sbenno} 105332084Sbenno 106332084Sbennostatic const char * 107332084Sbennorrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len) 108332084Sbenno{ 109332084Sbenno ISO_RRIP_ALTNAME *p; 110332084Sbenno 111332084Sbenno if (len == NULL) 112332084Sbenno return (NULL); 113332084Sbenno 114332084Sbenno p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip); 115332084Sbenno if (p == NULL) 116332084Sbenno return (NULL); 117332084Sbenno switch (*p->flags) { 118332084Sbenno case ISO_SUSP_CFLAG_CURRENT: 119332084Sbenno *len = 1; 120332084Sbenno return ("."); 121332084Sbenno case ISO_SUSP_CFLAG_PARENT: 122332084Sbenno *len = 2; 123332084Sbenno return (".."); 124332084Sbenno case 0: 125332084Sbenno *len = isonum_711(p->h.length) - 5; 126332084Sbenno return ((char *)p + 5); 127332084Sbenno default: 128332084Sbenno /* 129332084Sbenno * We don't handle hostnames or continued names as they are 130332084Sbenno * too hard, so just bail and use the default name. 131332084Sbenno */ 132332084Sbenno return (NULL); 133332084Sbenno } 134332084Sbenno} 135332084Sbenno 136332084Sbennostatic int 137332084Sbennorrip_check(struct iso_directory_record *dp, int *lenskip) 138332084Sbenno{ 139332084Sbenno ISO_SUSP_PRESENT *sp; 140332084Sbenno ISO_RRIP_EXTREF *er; 141332084Sbenno char *p; 142332084Sbenno 143332084Sbenno /* First, see if we can find a SP field. */ 144332084Sbenno p = dp->name + isonum_711(dp->name_len); 145332084Sbenno if (p > (char *)dp + isonum_711(dp->length)) { 146332084Sbenno return (0); 147332084Sbenno } 148332084Sbenno sp = (ISO_SUSP_PRESENT *)p; 149332084Sbenno if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) { 150332084Sbenno return (0); 151332084Sbenno } 152332084Sbenno if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) { 153332084Sbenno return (0); 154332084Sbenno } 155332084Sbenno if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) { 156332084Sbenno return (0); 157332084Sbenno } 158332084Sbenno *lenskip = isonum_711(sp->len_skp); 159332084Sbenno 160332084Sbenno /* 161332084Sbenno * Now look for an ER field. If RRIP is present, then there must 162332084Sbenno * be at least one of these. It would be more pedantic to walk 163332084Sbenno * through the list of fields looking for a Rock Ridge ER field. 164332084Sbenno */ 165332084Sbenno er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0); 166332084Sbenno if (er == NULL) { 167332084Sbenno return (0); 168332084Sbenno } 169332084Sbenno return (1); 170332084Sbenno} 171332084Sbenno 172332084Sbennostatic int 173332084Sbennodirmatch(const char *path, struct iso_directory_record *dp, int use_rrip, 174332084Sbenno int lenskip) 175332084Sbenno{ 176332084Sbenno size_t len; 177344266Skevans const char *cp = NULL; 178332084Sbenno int i, icase; 179332084Sbenno 180332084Sbenno if (use_rrip) 181332084Sbenno cp = rrip_lookup_name(dp, lenskip, &len); 182332084Sbenno else 183332084Sbenno cp = NULL; 184332084Sbenno if (cp == NULL) { 185332084Sbenno len = isonum_711(dp->name_len); 186332084Sbenno cp = dp->name; 187332084Sbenno icase = 1; 188332084Sbenno } else 189332084Sbenno icase = 0; 190332084Sbenno for (i = len; --i >= 0; path++, cp++) { 191332084Sbenno if (!*path || *path == '/') 192332084Sbenno break; 193332084Sbenno if (*path == *cp) 194332084Sbenno continue; 195332084Sbenno if (!icase && toupper(*path) == *cp) 196332084Sbenno continue; 197332084Sbenno return 0; 198332084Sbenno } 199332084Sbenno if (*path && *path != '/') { 200332084Sbenno return 0; 201332084Sbenno } 202332084Sbenno /* 203332084Sbenno * Allow stripping of trailing dots and the version number. 204332084Sbenno * Note that this will find the first instead of the last version 205332084Sbenno * of a file. 206332084Sbenno */ 207332084Sbenno if (i >= 0 && (*cp == ';' || *cp == '.')) { 208332084Sbenno /* This is to prevent matching of numeric extensions */ 209332084Sbenno if (*cp == '.' && cp[1] != ';') { 210332084Sbenno return 0; 211332084Sbenno } 212332084Sbenno while (--i >= 0) 213332084Sbenno if (*++cp != ';' && (*cp < '0' || *cp > '9')) { 214332084Sbenno return 0; 215332084Sbenno } 216332084Sbenno } 217332084Sbenno return 1; 218332084Sbenno} 219332084Sbenno 220332084Sbennostatic uint64_t 221332084Sbennocd9660_lookup(const char *path) 222332084Sbenno{ 223332084Sbenno static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; 224332084Sbenno struct iso_primary_descriptor *vd; 225332084Sbenno struct iso_directory_record rec; 226332084Sbenno struct iso_directory_record *dp = NULL; 227332084Sbenno size_t dsize, off; 228332084Sbenno daddr_t bno, boff; 229332084Sbenno int rc, first, use_rrip, lenskip; 230332084Sbenno uint64_t cookie; 231332084Sbenno 232332084Sbenno for (bno = 16;; bno++) { 233332084Sbenno rc = read_iso_block(blkbuf, bno); 234332084Sbenno vd = (struct iso_primary_descriptor *)blkbuf; 235332084Sbenno 236332084Sbenno if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 237332084Sbenno return (0); 238332084Sbenno if (isonum_711(vd->type) == ISO_VD_END) 239332084Sbenno return (0); 240332084Sbenno if (isonum_711(vd->type) == ISO_VD_PRIMARY) 241332084Sbenno break; 242332084Sbenno } 243332084Sbenno 244344408Skevans bcopy(vd->root_directory_record, &rec, sizeof(rec)); 245332084Sbenno if (*path == '/') path++; /* eat leading '/' */ 246332084Sbenno 247332084Sbenno first = 1; 248332084Sbenno use_rrip = 0; 249344266Skevans lenskip = 0; 250332084Sbenno while (*path) { 251332084Sbenno bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 252332084Sbenno dsize = isonum_733(rec.size); 253332084Sbenno off = 0; 254332084Sbenno boff = 0; 255332084Sbenno 256332084Sbenno while (off < dsize) { 257332084Sbenno if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { 258332084Sbenno rc = read_iso_block(blkbuf, bno + boff); 259332084Sbenno if (rc) { 260332084Sbenno return (0); 261332084Sbenno } 262332084Sbenno boff++; 263332084Sbenno dp = (struct iso_directory_record *) blkbuf; 264332084Sbenno } 265332084Sbenno if (isonum_711(dp->length) == 0) { 266332084Sbenno /* skip to next block, if any */ 267332084Sbenno off = boff * ISO_DEFAULT_BLOCK_SIZE; 268332084Sbenno continue; 269332084Sbenno } 270332084Sbenno 271332084Sbenno /* See if RRIP is in use. */ 272332084Sbenno if (first) 273332084Sbenno use_rrip = rrip_check(dp, &lenskip); 274332084Sbenno 275332084Sbenno if (dirmatch(path, dp, use_rrip, 276332084Sbenno first ? 0 : lenskip)) { 277332084Sbenno first = 0; 278332084Sbenno break; 279332084Sbenno } else 280332084Sbenno first = 0; 281332084Sbenno 282332084Sbenno dp = (struct iso_directory_record *) 283332084Sbenno ((char *) dp + isonum_711(dp->length)); 284332084Sbenno /* If the new block has zero length, it is padding. */ 285332084Sbenno if (isonum_711(dp->length) == 0) { 286332084Sbenno /* Skip to next block, if any. */ 287332084Sbenno off = boff * ISO_DEFAULT_BLOCK_SIZE; 288332084Sbenno continue; 289332084Sbenno } 290332084Sbenno off += isonum_711(dp->length); 291332084Sbenno } 292332084Sbenno if (off >= dsize) { 293332084Sbenno return (0); 294332084Sbenno } 295332084Sbenno 296332084Sbenno rec = *dp; 297332084Sbenno while (*path && *path != '/') /* look for next component */ 298332084Sbenno path++; 299332084Sbenno if (*path) path++; /* skip '/' */ 300332084Sbenno } 301332084Sbenno 302332084Sbenno if ((isonum_711(rec.flags) & 2) != 0) { 303332084Sbenno return (0); 304332084Sbenno } 305332084Sbenno 306332084Sbenno cookie = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); 307332084Sbenno cookie = (cookie << 32) | isonum_733(rec.size); 308332084Sbenno 309332084Sbenno return (cookie); 310332084Sbenno} 311332084Sbenno 312332084Sbennostatic ssize_t 313332084Sbennocd9660_fsread(uint64_t cookie, void *buf, size_t nbytes) 314332084Sbenno{ 315332084Sbenno static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; 316332084Sbenno static daddr_t curstart = 0, curblk = 0; 317332084Sbenno daddr_t blk, blk_off; 318332084Sbenno off_t byte_off; 319332084Sbenno size_t size, remaining, n; 320332084Sbenno char *s; 321332084Sbenno 322332084Sbenno size = cookie & 0xffffffff; 323332084Sbenno blk = (cookie >> 32) & 0xffffffff; 324332084Sbenno 325332084Sbenno /* Make sure we're looking at the right file. */ 326332084Sbenno if (((blk << 32) | size) != cookie) { 327332084Sbenno return (-1); 328332084Sbenno } 329332084Sbenno 330332084Sbenno if (blk != curstart) { 331332084Sbenno curstart = blk; 332332084Sbenno fs_off = 0; 333332084Sbenno } 334332084Sbenno 335332084Sbenno size -= fs_off; 336332084Sbenno if (size < nbytes) { 337332084Sbenno nbytes = size; 338332084Sbenno } 339332084Sbenno remaining = nbytes; 340332084Sbenno s = buf; 341332084Sbenno 342332084Sbenno while (remaining > 0) { 343332084Sbenno blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT; 344332084Sbenno byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1); 345332084Sbenno 346332084Sbenno if (curblk != curstart + blk_off) { 347332084Sbenno curblk = curstart + blk_off; 348332084Sbenno read_iso_block(blkbuf, curblk); 349332084Sbenno } 350332084Sbenno 351332084Sbenno if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) { 352332084Sbenno n = remaining; 353332084Sbenno } else { 354332084Sbenno n = ISO_DEFAULT_BLOCK_SIZE - byte_off; 355332084Sbenno } 356332084Sbenno memcpy(s, blkbuf + byte_off, n); 357332084Sbenno remaining -= n; 358332084Sbenno s += n; 359332084Sbenno 360332084Sbenno fs_off += n; 361332084Sbenno } 362332084Sbenno 363332084Sbenno return (nbytes); 364332084Sbenno} 365