1 /* $OpenBSD: udf_vfsops.c,v 1.23 2006/08/07 15:50:42 pedro Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.25 2005/01/25 15:52:03 phk Exp $ 29 */ 30 31 /* 32 * Ported to OpenBSD by Pedro Martelletto <pedro@openbsd.org> in February 2005. 33 */ 34 35 /* 36 * Ok, here's how it goes. The UDF specs are pretty clear on how each data 37 * structure is made up, but not very clear on how they relate to each other. 38 * Here is the skinny... This demostrates a filesystem with one file in the 39 * root directory. Subdirectories are treated just as normal files, but they 40 * have File Id Descriptors of their children as their file data. As for the 41 * Anchor Volume Descriptor Pointer, it can exist in two of the following three 42 * places: sector 256, sector n (the max sector of the disk), or sector 43 * n - 256. It's a pretty good bet that one will exist at sector 256 though. 44 * One caveat is unclosed CD media. For that, sector 256 cannot be written, 45 * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the 46 * media is closed. 47 */ 48 49 #include <sys/types.h> 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/uio.h> 53 #include <sys/buf.h> 54 #include <sys/conf.h> 55 #include <sys/dirent.h> 56 #include <sys/fcntl.h> 57 #include <sys/kernel.h> 58 #include <sys/malloc.h> 59 #include <sys/mutex.h> 60 #include <sys/mount.h> 61 #include <sys/namei.h> 62 #include <sys/pool.h> 63 #include <sys/proc.h> 64 #include <sys/lock.h> 65 #include <sys/queue.h> 66 #include <sys/vnode.h> 67 #include <sys/endian.h> 68 69 #include <miscfs/specfs/specdev.h> 70 71 #include <isofs/udf/ecma167-udf.h> 72 #include <isofs/udf/udf.h> 73 #include <isofs/udf/udf_extern.h> 74 75 struct pool udf_trans_pool; 76 struct pool unode_pool; 77 struct pool udf_ds_pool; 78 79 int udf_find_partmaps(struct umount *, struct logvol_desc *); 80 int udf_get_vpartmap(struct umount *, struct part_map_virt *); 81 int udf_get_spartmap(struct umount *, struct part_map_spare *); 82 int udf_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *); 83 84 const struct vfsops udf_vfsops = { 85 .vfs_fhtovp = udf_fhtovp, 86 .vfs_init = udf_init, 87 .vfs_mount = udf_mount, 88 .vfs_start = udf_start, 89 .vfs_root = udf_root, 90 .vfs_quotactl = udf_quotactl, 91 .vfs_statfs = udf_statfs, 92 .vfs_sync = udf_sync, 93 .vfs_unmount = udf_unmount, 94 .vfs_vget = udf_vget, 95 .vfs_vptofh = udf_vptofh, 96 .vfs_sysctl = udf_sysctl, 97 .vfs_checkexp = udf_checkexp, 98 }; 99 100 int 101 udf_init(struct vfsconf *foo) 102 { 103 pool_init(&udf_trans_pool, MAXNAMLEN * sizeof(unicode_t), 0, 0, 0, 104 "udftrpl", &pool_allocator_nointr); 105 pool_init(&unode_pool, sizeof(struct unode), 0, 0, 0, 106 "udfndpl", &pool_allocator_nointr); 107 pool_init(&udf_ds_pool, sizeof(struct udf_dirstream), 0, 0, 0, 108 "udfdspl", &pool_allocator_nointr); 109 110 return (0); 111 } 112 113 int 114 udf_start(struct mount *mp, int flags, struct proc *p) 115 { 116 return (0); 117 } 118 119 int 120 udf_mount(struct mount *mp, const char *path, void *data, 121 struct nameidata *ndp, struct proc *p) 122 { 123 struct vnode *devvp; /* vnode of the mount device */ 124 struct udf_args args; 125 size_t len; 126 int error; 127 128 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 129 mp->mnt_flag |= MNT_RDONLY; 130 printf("udf_mount: enforcing read-only mode\n"); 131 } 132 133 /* 134 * No root filesystem support. Probably not a big deal, since the 135 * bootloader doesn't understand UDF. 136 */ 137 if (mp->mnt_flag & MNT_ROOTFS) 138 return (EOPNOTSUPP); 139 140 error = copyin(data, &args, sizeof(struct udf_args)); 141 if (error) 142 return (error); 143 144 if (args.fspec == NULL) 145 return (EINVAL); 146 147 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 148 if ((error = namei(ndp))) 149 return (error); 150 151 devvp = ndp->ni_vp; 152 if (devvp->v_type != VBLK) { 153 vrele(devvp); 154 return (ENOTBLK); 155 } 156 157 if (major(devvp->v_rdev) >= nblkdev) { 158 vrele(devvp); 159 return (ENXIO); 160 } 161 162 /* Check the access rights on the mount device */ 163 if (p->p_ucred->cr_uid) { 164 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 165 error = VOP_ACCESS(devvp, VREAD, p->p_ucred, p); 166 VOP_UNLOCK(devvp, 0, p); 167 if (error) { 168 vrele(devvp); 169 return (error); 170 } 171 } 172 173 if ((error = udf_mountfs(devvp, mp, args.lastblock, p))) { 174 vrele(devvp); 175 return (error); 176 } 177 178 /* 179 * Keep a copy of the mount information. 180 */ 181 copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &len); 182 bzero(mp->mnt_stat.f_mntonname + len, MNAMELEN - len); 183 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len); 184 bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len); 185 186 return (0); 187 }; 188 189 /* 190 * Check the descriptor tag for both the correct id and correct checksum. 191 * Return zero if all is good, EINVAL if not. 192 */ 193 int 194 udf_checktag(struct desc_tag *tag, uint16_t id) 195 { 196 uint8_t *itag; 197 uint8_t i, cksum = 0; 198 199 itag = (uint8_t *)tag; 200 201 if (letoh16(tag->id) != id) 202 return (EINVAL); 203 204 for (i = 0; i < 15; i++) 205 cksum = cksum + itag[i]; 206 cksum = cksum - itag[4]; 207 208 if (cksum == tag->cksum) 209 return (0); 210 211 return (EINVAL); 212 } 213 214 int 215 udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) 216 { 217 struct buf *bp = NULL; 218 struct anchor_vdp avdp; 219 struct umount *ump = NULL; 220 struct part_desc *pd; 221 struct logvol_desc *lvd; 222 struct fileset_desc *fsd; 223 struct file_entry *root_fentry; 224 uint32_t sector, size, mvds_start, mvds_end; 225 uint32_t fsd_offset = 0; 226 uint16_t part_num = 0, fsd_part = 0; 227 int error = EINVAL; 228 int logvol_found = 0, part_found = 0, fsd_found = 0; 229 int bsize; 230 231 /* 232 * Disallow multiple mounts of the same device. 233 * Disallow mounting of a device that is currently in use 234 * (except for root, which might share swap device for miniroot). 235 * Flush out any old buffers remaining from a previous use. 236 */ 237 if ((error = vfs_mountedon(devvp))) 238 return (error); 239 if (vcount(devvp) > 1 && devvp != rootvp) 240 return (EBUSY); 241 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 242 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 243 VOP_UNLOCK(devvp, 0, p); 244 if (error) 245 return (error); 246 247 error = VOP_OPEN(devvp, FREAD, FSCRED, p); 248 if (error) 249 return (error); 250 251 MALLOC(ump, struct umount *, sizeof(struct umount), M_UDFMOUNT, 252 M_WAITOK); 253 bzero(ump, sizeof(struct umount)); 254 255 mp->mnt_data = (qaddr_t) ump; 256 mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev; 257 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UDF); 258 mp->mnt_flag |= MNT_LOCAL; 259 260 ump->um_mountp = mp; 261 ump->um_dev = devvp->v_rdev; 262 ump->um_devvp = devvp; 263 264 bsize = 2048; /* Should probe the media for its size. */ 265 266 /* 267 * Get the Anchor Volume Descriptor Pointer from sector 256. 268 * Should also check sector n - 256, n, and 512. 269 */ 270 sector = 256; 271 if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED, 272 &bp)) != 0) 273 goto bail; 274 if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) 275 goto bail; 276 277 bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); 278 brelse(bp); 279 bp = NULL; 280 281 /* 282 * Extract the Partition Descriptor and Logical Volume Descriptor 283 * from the Volume Descriptor Sequence. 284 * Should we care about the partition type right now? 285 * What about multiple partitions? 286 */ 287 mvds_start = letoh32(avdp.main_vds_ex.loc); 288 mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize; 289 for (sector = mvds_start; sector < mvds_end; sector++) { 290 if ((error = bread(devvp, sector * btodb(bsize), bsize, 291 NOCRED, &bp)) != 0) { 292 printf("Can't read sector %d of VDS\n", sector); 293 goto bail; 294 } 295 lvd = (struct logvol_desc *)bp->b_data; 296 if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { 297 ump->um_bsize = letoh32(lvd->lb_size); 298 ump->um_bmask = ump->um_bsize - 1; 299 ump->um_bshift = ffs(ump->um_bsize) - 1; 300 fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num); 301 fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num); 302 if (udf_find_partmaps(ump, lvd)) 303 break; 304 logvol_found = 1; 305 } 306 pd = (struct part_desc *)bp->b_data; 307 if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { 308 part_found = 1; 309 part_num = letoh16(pd->part_num); 310 ump->um_len = letoh32(pd->part_len); 311 ump->um_start = letoh32(pd->start_loc); 312 } 313 314 brelse(bp); 315 bp = NULL; 316 if ((part_found) && (logvol_found)) 317 break; 318 } 319 320 if (!part_found || !logvol_found) { 321 error = EINVAL; 322 goto bail; 323 } 324 325 if (fsd_part != part_num) { 326 printf("FSD does not lie within the partition!\n"); 327 error = EINVAL; 328 goto bail; 329 } 330 331 mtx_init(&ump->um_hashmtx, IPL_NONE); 332 ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK, 333 &ump->um_hashsz); 334 335 /* Get the VAT, if needed */ 336 if (ump->um_flags & UDF_MNT_FIND_VAT) { 337 error = udf_vat_get(ump, lb); 338 if (error) 339 goto bail; 340 } 341 342 /* 343 * Grab the Fileset Descriptor 344 * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing 345 * me in the right direction here. 346 */ 347 sector = fsd_offset; 348 udf_vat_map(ump, §or); 349 if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { 350 printf("Cannot read sector %d of FSD\n", sector); 351 goto bail; 352 } 353 fsd = (struct fileset_desc *)bp->b_data; 354 if (!udf_checktag(&fsd->tag, TAGID_FSD)) { 355 fsd_found = 1; 356 bcopy(&fsd->rootdir_icb, &ump->um_root_icb, 357 sizeof(struct long_ad)); 358 } 359 360 brelse(bp); 361 bp = NULL; 362 363 if (!fsd_found) { 364 printf("Couldn't find the fsd\n"); 365 error = EINVAL; 366 goto bail; 367 } 368 369 /* 370 * Find the file entry for the root directory. 371 */ 372 sector = letoh32(ump->um_root_icb.loc.lb_num); 373 size = letoh32(ump->um_root_icb.len); 374 udf_vat_map(ump, §or); 375 if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) { 376 printf("Cannot read sector %d\n", sector); 377 goto bail; 378 } 379 380 root_fentry = (struct file_entry *)bp->b_data; 381 if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) { 382 printf("Invalid root file entry!\n"); 383 goto bail; 384 } 385 386 brelse(bp); 387 bp = NULL; 388 389 devvp->v_specmountpoint = mp; 390 391 return (0); 392 393 bail: 394 if (ump->um_hashtbl != NULL) 395 free(ump->um_hashtbl, M_UDFMOUNT); 396 397 if (ump != NULL) { 398 FREE(ump, M_UDFMOUNT); 399 mp->mnt_data = NULL; 400 mp->mnt_flag &= ~MNT_LOCAL; 401 } 402 if (bp != NULL) 403 brelse(bp); 404 VOP_CLOSE(devvp, FREAD, FSCRED, p); 405 406 return (error); 407 } 408 409 int 410 udf_unmount(struct mount *mp, int mntflags, struct proc *p) 411 { 412 struct umount *ump; 413 struct vnode *devvp; 414 int error, flags = 0; 415 416 ump = VFSTOUDFFS(mp); 417 devvp = ump->um_devvp; 418 419 if (mntflags & MNT_FORCE) 420 flags |= FORCECLOSE; 421 422 if ((error = vflush(mp, NULL, flags))) 423 return (error); 424 425 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 426 vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0); 427 error = VOP_CLOSE(devvp, FREAD, NOCRED, p); 428 VOP_UNLOCK(devvp, 0, p); 429 if (error) 430 return (error); 431 432 devvp->v_specmountpoint = NULL; 433 vrele(devvp); 434 435 if (ump->um_flags & UDF_MNT_USES_VAT) 436 free(ump->um_vat, M_UDFMOUNT); 437 438 if (ump->um_stbl != NULL) 439 free(ump->um_stbl, M_UDFMOUNT); 440 441 if (ump->um_hashtbl != NULL) 442 free(ump->um_hashtbl, M_UDFMOUNT); 443 444 FREE(ump, M_UDFMOUNT); 445 446 mp->mnt_data = (qaddr_t)0; 447 mp->mnt_flag &= ~MNT_LOCAL; 448 449 return (0); 450 } 451 452 int 453 udf_root(struct mount *mp, struct vnode **vpp) 454 { 455 struct umount *ump; 456 struct vnode *vp; 457 ino_t id; 458 int error; 459 460 ump = VFSTOUDFFS(mp); 461 462 id = udf_getid(&ump->um_root_icb); 463 464 error = udf_vget(mp, id, vpp); 465 if (error) 466 return (error); 467 468 vp = *vpp; 469 vp->v_flag |= VROOT; 470 471 return (0); 472 } 473 474 int 475 udf_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg, 476 struct proc *p) 477 { 478 return (EOPNOTSUPP); 479 } 480 481 int 482 udf_statfs(struct mount *mp, struct statfs *sbp, struct proc *p) 483 { 484 struct umount *ump; 485 486 ump = VFSTOUDFFS(mp); 487 488 sbp->f_bsize = ump->um_bsize; 489 sbp->f_iosize = ump->um_bsize; 490 sbp->f_blocks = ump->um_len; 491 sbp->f_bfree = 0; 492 sbp->f_bavail = 0; 493 sbp->f_files = 0; 494 sbp->f_ffree = 0; 495 496 return (0); 497 } 498 499 int 500 udf_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p) 501 { 502 return (0); 503 } 504 505 int 506 udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 507 { 508 struct buf *bp; 509 struct vnode *devvp; 510 struct umount *ump; 511 struct proc *p; 512 struct vnode *vp; 513 struct unode *up; 514 struct file_entry *fe; 515 int error, sector, size; 516 517 p = curproc; 518 bp = NULL; 519 *vpp = NULL; 520 ump = VFSTOUDFFS(mp); 521 522 /* See if we already have this in the cache */ 523 if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0) 524 return (error); 525 if (*vpp != NULL) 526 return (0); 527 528 /* 529 * Allocate memory and check the tag id's before grabbing a new 530 * vnode, since it's hard to roll back if there is a problem. 531 */ 532 up = pool_get(&unode_pool, PR_WAITOK); 533 bzero(up, sizeof(struct unode)); 534 535 /* 536 * Copy in the file entry. Per the spec, the size can only be 1 block. 537 */ 538 sector = ino; 539 devvp = ump->um_devvp; 540 udf_vat_map(ump, §or); 541 if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { 542 printf("Cannot read sector %d\n", sector); 543 pool_put(&unode_pool, up); 544 if (bp != NULL) 545 brelse(bp); 546 return (error); 547 } 548 549 fe = (struct file_entry *)bp->b_data; 550 if (udf_checktag(&fe->tag, TAGID_FENTRY)) { 551 printf("Invalid file entry!\n"); 552 pool_put(&unode_pool, up); 553 brelse(bp); 554 return (ENOMEM); 555 } 556 557 size = UDF_FENTRY_SIZE + letoh32(fe->l_ea) + letoh32(fe->l_ad); 558 559 up->u_fentry = malloc(size, M_UDFFENTRY, M_NOWAIT); 560 if (up->u_fentry == NULL) { 561 pool_put(&unode_pool, up); 562 brelse(bp); 563 return (ENOMEM); /* Cannot allocate file entry block */ 564 } 565 566 bcopy(bp->b_data, up->u_fentry, size); 567 568 brelse(bp); 569 bp = NULL; 570 571 if ((error = udf_allocv(mp, &vp, p))) { 572 free(up->u_fentry, M_UDFFENTRY); 573 pool_put(&unode_pool, up); 574 return (error); /* Error from udf_allocv() */ 575 } 576 577 up->u_vnode = vp; 578 up->u_ino = ino; 579 up->u_devvp = ump->um_devvp; 580 up->u_dev = ump->um_dev; 581 up->u_ump = ump; 582 vp->v_data = up; 583 VREF(ump->um_devvp); 584 585 lockinit(&up->u_lock, PINOD, "unode", 0, 0); 586 587 /* 588 * udf_hashins() will lock the vnode for us. 589 */ 590 udf_hashins(up); 591 592 switch (up->u_fentry->icbtag.file_type) { 593 default: 594 vp->v_type = VBAD; 595 break; 596 case UDF_ICB_TYPE_DIR: 597 vp->v_type = VDIR; 598 break; 599 case UDF_ICB_TYPE_FILE: 600 vp->v_type = VREG; 601 break; 602 case UDF_ICB_TYPE_BLKDEV: 603 vp->v_type = VBLK; 604 break; 605 case UDF_ICB_TYPE_CHRDEV: 606 vp->v_type = VCHR; 607 break; 608 case UDF_ICB_TYPE_FIFO: 609 vp->v_type = VFIFO; 610 break; 611 case UDF_ICB_TYPE_SOCKET: 612 vp->v_type = VSOCK; 613 break; 614 case UDF_ICB_TYPE_SYMLINK: 615 vp->v_type = VLNK; 616 break; 617 case UDF_ICB_TYPE_VAT_150: 618 vp->v_type = VREG; 619 break; 620 } 621 622 *vpp = vp; 623 624 return (0); 625 } 626 627 struct ifid { 628 u_short ifid_len; 629 u_short ifid_pad; 630 int ifid_ino; 631 long ifid_start; 632 }; 633 634 int 635 udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 636 { 637 struct ifid *ifhp; 638 struct vnode *nvp; 639 int error; 640 641 ifhp = (struct ifid *)fhp; 642 643 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { 644 *vpp = NULLVP; 645 return (error); 646 } 647 648 *vpp = nvp; 649 650 return (0); 651 } 652 653 int 654 udf_vptofh(struct vnode *vp, struct fid *fhp) 655 { 656 struct unode *up; 657 struct ifid *ifhp; 658 659 up = VTOU(vp); 660 ifhp = (struct ifid *)fhp; 661 ifhp->ifid_len = sizeof(struct ifid); 662 ifhp->ifid_ino = up->u_ino; 663 664 return (0); 665 } 666 667 int 668 udf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 669 size_t newlen, struct proc *p) 670 { 671 return (EINVAL); 672 } 673 674 int 675 udf_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp, 676 struct ucred **credanonp) 677 { 678 return (EACCES); /* For the time being */ 679 } 680 681 /* Handle a virtual partition map */ 682 int 683 udf_get_vpartmap(struct umount *ump, struct part_map_virt *pmv) 684 { 685 ump->um_flags |= UDF_MNT_FIND_VAT; /* Should do more than this */ 686 return (0); 687 } 688 689 /* Handle a sparable partition map */ 690 int 691 udf_get_spartmap(struct umount *ump, struct part_map_spare *pms) 692 { 693 struct buf *bp; 694 int i, error; 695 696 ump->um_stbl = malloc(letoh32(pms->st_size), M_UDFMOUNT, M_NOWAIT); 697 if (ump->um_stbl == NULL) 698 return (ENOMEM); 699 700 bzero(ump->um_stbl, letoh32(pms->st_size)); 701 702 /* Calculate the number of sectors per packet */ 703 ump->um_psecs = letoh16(pms->packet_len) / ump->um_bsize; 704 705 error = udf_readlblks(ump, letoh32(pms->st_loc[0]), 706 letoh32(pms->st_size), &bp); 707 708 if (error) { 709 if (bp != NULL) 710 brelse(bp); 711 free(ump->um_stbl, M_UDFMOUNT); 712 return (error); /* Failed to read sparing table */ 713 } 714 715 bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size)); 716 brelse(bp); 717 718 if (udf_checktag(&ump->um_stbl->tag, 0)) { 719 free(ump->um_stbl, M_UDFMOUNT); 720 return (EINVAL); /* Invalid sparing table found */ 721 } 722 723 /* 724 * See how many valid entries there are here. The list is 725 * supposed to be sorted, 0xfffffff0 and higher are not valid. 726 */ 727 for (i = 0; i < letoh16(ump->um_stbl->rt_l); i++) { 728 ump->um_stbl_len = i; 729 if (letoh32(ump->um_stbl->entries[i].org) >= 0xfffffff0) 730 break; 731 } 732 733 return (0); 734 } 735 736 /* Scan the partition maps */ 737 int 738 udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd) 739 { 740 struct regid *pmap_id; 741 unsigned char regid_id[UDF_REGID_ID_SIZE + 1]; 742 int i, ptype, psize, error; 743 uint8_t *pmap = (uint8_t *) &lvd->maps[0]; 744 745 for (i = 0; i < letoh32(lvd->n_pm); i++) { 746 ptype = pmap[0]; 747 psize = pmap[1]; 748 749 if (ptype != 1 && ptype != 2) 750 return (EINVAL); /* Invalid partition map type */ 751 752 if (psize != UDF_PMAP_TYPE1_SIZE && 753 psize != UDF_PMAP_TYPE2_SIZE) 754 return (EINVAL); /* Invalid partition map size */ 755 756 if (ptype == 1) { 757 pmap += UDF_PMAP_TYPE1_SIZE; 758 continue; 759 } 760 761 /* Type 2 map. Find out the details */ 762 pmap_id = (struct regid *) &pmap[4]; 763 regid_id[UDF_REGID_ID_SIZE] = '\0'; 764 bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE); 765 766 if (!bcmp(®id_id[0], "*UDF Virtual Partition", 767 UDF_REGID_ID_SIZE)) 768 error = udf_get_vpartmap(ump, 769 (struct part_map_virt *) pmap); 770 else if (!bcmp(®id_id[0], "*UDF Sparable Partition", 771 UDF_REGID_ID_SIZE)) 772 error = udf_get_spartmap(ump, 773 (struct part_map_spare *) pmap); 774 else 775 return (EINVAL); /* Unsupported partition map */ 776 777 if (error) 778 return (error); /* Error getting partition */ 779 780 pmap += UDF_PMAP_TYPE2_SIZE; 781 } 782 783 return (0); 784 } 785