1 /* $OpenBSD: cd9660.c,v 1.9 2003/06/01 17:00:32 deraadt Exp $ */ 2 /* $NetBSD: cd9660.c,v 1.1 1996/09/30 16:01:19 ws Exp $ */ 3 4 /* 5 * Copyright (C) 1996 Wolfgang Solfrank. 6 * Copyright (C) 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Stand-alone ISO9660 file reading package. 37 * 38 * Note: This doesn't support Rock Ridge extensions, extended attributes, 39 * blocksizes other than 2048 bytes, multi-extent files, etc. 40 */ 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 44 #include <lib/libkern/libkern.h> 45 46 /* THIS IS AN UGLY HACK!!! XXX */ 47 struct fid; 48 struct mbuf; 49 struct nameidata; 50 struct netexport { int x; }; 51 struct proc; 52 struct statfs; 53 struct ucred; 54 #include <isofs/cd9660/iso.h> 55 56 #include "stand.h" 57 #include "cd9660.h" 58 59 struct file { 60 off_t off; /* Current offset within file */ 61 daddr_t bno; /* Starting block number */ 62 off_t size; /* Size of file */ 63 }; 64 65 struct ptable_ent { 66 char namlen [ISODCL( 1, 1)]; /* 711 */ 67 char extlen [ISODCL( 2, 2)]; /* 711 */ 68 char block [ISODCL( 3, 6)]; /* 732 */ 69 char parent [ISODCL( 7, 8)]; /* 722 */ 70 char name [1]; 71 }; 72 #define PTFIXSZ 8 73 #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) 74 75 #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) 76 77 static int 78 pnmatch(path, pp) 79 char *path; 80 struct ptable_ent *pp; 81 { 82 char *cp; 83 int i; 84 85 cp = pp->name; 86 for (i = isonum_711(pp->namlen); --i >= 0; path++, cp++) { 87 if (toupper(*path) == *cp) 88 continue; 89 return 0; 90 } 91 if (*path != '/') 92 return 0; 93 return 1; 94 } 95 96 static int 97 dirmatch(path, dp) 98 char *path; 99 struct iso_directory_record *dp; 100 { 101 char *cp; 102 int i; 103 104 /* This needs to be a regular file */ 105 if (dp->flags[0] & 6) 106 return 0; 107 108 cp = dp->name; 109 for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) { 110 if (!*path) 111 break; 112 if (toupper(*path) == *cp) 113 continue; 114 return 0; 115 } 116 if (*path) 117 return 0; 118 /* 119 * Allow stripping of trailing dots and the version number. 120 * Note that this will find the first instead of the last version 121 * of a file. 122 */ 123 if (i >= 0 && (*cp == ';' || *cp == '.')) { 124 /* This is to prevent matching of numeric extensions */ 125 if (*cp == '.' && cp[1] != ';') 126 return 0; 127 while (--i >= 0) 128 if (*++cp != ';' && (*cp < '0' || *cp > '9')) 129 return 0; 130 } 131 return 1; 132 } 133 134 int 135 cd9660_open(path, f) 136 char *path; 137 struct open_file *f; 138 { 139 struct file *fp = 0; 140 void *buf; 141 struct iso_primary_descriptor *vd; 142 size_t buf_size, read, psize, dsize; 143 daddr_t bno; 144 int parent, ent; 145 struct ptable_ent *pp; 146 struct iso_directory_record *dp; 147 int rc; 148 149 /* First find the volume descriptor */ 150 buf = alloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); 151 dp = (struct iso_directory_record *)buf; 152 vd = buf; 153 for (bno = 16;; bno++) { 154 twiddle(); 155 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 156 ISO_DEFAULT_BLOCK_SIZE, buf, &read); 157 if (rc) 158 goto out; 159 if (read != ISO_DEFAULT_BLOCK_SIZE) { 160 rc = EIO; 161 goto out; 162 } 163 rc = EINVAL; 164 if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) 165 goto out; 166 if (isonum_711(vd->type) == ISO_VD_END) 167 goto out; 168 if (isonum_711(vd->type) == ISO_VD_PRIMARY) 169 break; 170 } 171 if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) 172 goto out; 173 174 /* Now get the path table and lookup the directory of the file */ 175 bno = isonum_732(vd->type_m_path_table); 176 psize = isonum_733(vd->path_table_size); 177 178 if (psize > ISO_DEFAULT_BLOCK_SIZE) { 179 free(buf, ISO_DEFAULT_BLOCK_SIZE); 180 buf = alloc(buf_size = roundup(psize, ISO_DEFAULT_BLOCK_SIZE)); 181 } 182 183 twiddle(); 184 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 185 buf_size, buf, &read); 186 if (rc) 187 goto out; 188 if (read != buf_size) { 189 rc = EIO; 190 goto out; 191 } 192 193 parent = 1; 194 pp = (struct ptable_ent *)buf; 195 ent = 1; 196 bno = isonum_732(pp->block) + isonum_711(pp->extlen); 197 198 rc = ENOENT; 199 /* 200 * Remove extra separators 201 */ 202 while (*path == '/') 203 path++; 204 205 while (*path) { 206 if ((void *)pp >= buf + psize) 207 break; 208 if (isonum_722(pp->parent) != parent) 209 break; 210 if (!pnmatch(path, pp)) { 211 pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp)); 212 ent++; 213 continue; 214 } 215 path += isonum_711(pp->namlen) + 1; 216 parent = ent; 217 bno = isonum_732(pp->block) + isonum_711(pp->extlen); 218 while ((void *)pp < buf + psize) { 219 if (isonum_722(pp->parent) == parent) 220 break; 221 pp = (struct ptable_ent *)((void *)pp + PTSIZE(pp)); 222 ent++; 223 } 224 } 225 226 /* Now bno has the start of the directory that supposedly contains the file */ 227 bno--; 228 dsize = 1; /* Something stupid, but > 0 XXX */ 229 for (psize = 0; psize < dsize;) { 230 if (!(psize % ISO_DEFAULT_BLOCK_SIZE)) { 231 bno++; 232 twiddle(); 233 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, 234 cdb2devb(bno), 235 ISO_DEFAULT_BLOCK_SIZE, 236 buf, &read); 237 if (rc) 238 goto out; 239 if (read != ISO_DEFAULT_BLOCK_SIZE) { 240 rc = EIO; 241 goto out; 242 } 243 dp = (struct iso_directory_record *)buf; 244 } 245 if (!isonum_711(dp->length)) { 246 if ((void *)dp == buf) 247 psize += ISO_DEFAULT_BLOCK_SIZE; 248 else 249 psize = roundup(psize, ISO_DEFAULT_BLOCK_SIZE); 250 continue; 251 } 252 if (dsize == 1) 253 dsize = isonum_733(dp->size); 254 if (dirmatch(path, dp)) 255 break; 256 psize += isonum_711(dp->length); 257 dp = (struct iso_directory_record *)((void *)dp + isonum_711(dp->length)); 258 } 259 260 if (psize >= dsize) { 261 rc = ENOENT; 262 goto out; 263 } 264 265 /* allocate file system specific data structure */ 266 fp = alloc(sizeof(struct file)); 267 bzero(fp, sizeof(struct file)); 268 f->f_fsdata = (void *)fp; 269 270 fp->off = 0; 271 fp->bno = isonum_733(dp->extent); 272 fp->size = isonum_733(dp->size); 273 free(buf, buf_size); 274 275 return 0; 276 277 out: 278 if (fp) 279 free(fp, sizeof(struct file)); 280 free(buf, buf_size); 281 282 return rc; 283 } 284 285 int 286 cd9660_close(f) 287 struct open_file *f; 288 { 289 struct file *fp = (struct file *)f->f_fsdata; 290 291 f->f_fsdata = 0; 292 free(fp, sizeof *fp); 293 294 return 0; 295 } 296 297 int 298 cd9660_read(f, start, size, resid) 299 struct open_file *f; 300 void *start; 301 size_t size; 302 size_t *resid; 303 { 304 struct file *fp = (struct file *)f->f_fsdata; 305 int rc = 0; 306 daddr_t bno; 307 char buf[ISO_DEFAULT_BLOCK_SIZE]; 308 char *dp; 309 size_t read, off; 310 311 while (size) { 312 if (fp->off < 0 || fp->off >= fp->size) 313 break; 314 bno = (fp->off >> ISO_DEFAULT_BLOCK_SHIFT) + fp->bno; 315 if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1) 316 || size < ISO_DEFAULT_BLOCK_SIZE) 317 dp = buf; 318 else 319 dp = start; 320 twiddle(); 321 rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), 322 ISO_DEFAULT_BLOCK_SIZE, dp, &read); 323 if (rc) 324 return rc; 325 if (read != ISO_DEFAULT_BLOCK_SIZE) 326 return EIO; 327 if (dp == buf) { 328 off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1); 329 if (read > off + size) 330 read = off + size; 331 read -= off; 332 bcopy(buf + off, start, read); 333 start += read; 334 fp->off += read; 335 size -= read; 336 } else { 337 start += ISO_DEFAULT_BLOCK_SIZE; 338 fp->off += ISO_DEFAULT_BLOCK_SIZE; 339 size -= ISO_DEFAULT_BLOCK_SIZE; 340 } 341 } 342 if (resid) 343 *resid = size; 344 return rc; 345 } 346 347 int 348 cd9660_write(f, start, size, resid) 349 struct open_file *f; 350 void *start; 351 size_t size; 352 size_t *resid; 353 { 354 return EROFS; 355 } 356 357 off_t 358 cd9660_seek(f, offset, where) 359 struct open_file *f; 360 off_t offset; 361 int where; 362 { 363 struct file *fp = (struct file *)f->f_fsdata; 364 365 switch (where) { 366 case SEEK_SET: 367 fp->off = offset; 368 break; 369 case SEEK_CUR: 370 fp->off += offset; 371 break; 372 case SEEK_END: 373 fp->off = fp->size - offset; 374 break; 375 default: 376 return -1; 377 } 378 return fp->off; 379 } 380 381 int 382 cd9660_stat(f, sb) 383 struct open_file *f; 384 struct stat *sb; 385 { 386 struct file *fp = (struct file *)f->f_fsdata; 387 388 /* only importatn stuff */ 389 sb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 390 sb->st_uid = sb->st_gid = 0; 391 sb->st_size = fp->size; 392 return 0; 393 } 394 395 /* 396 * Not implemented. 397 */ 398 #ifndef NO_READDIR 399 int 400 cd9660_readdir(f, name) 401 struct open_file *f; 402 char *name; 403 { 404 return (EROFS); 405 } 406 #endif 407 408