1/* $OpenBSD: udf_vnops.c,v 1.72 2024/05/13 11:17:40 semarie 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_vnops.c,v 1.50 2005/01/28 14:42:16 phk Exp $ 29 */ 30 31/* 32 * Ported to OpenBSD by Pedro Martelletto in February 2005. 33 */ 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/namei.h> 38#include <sys/malloc.h> 39#include <sys/mutex.h> 40#include <sys/stat.h> 41#include <sys/buf.h> 42#include <sys/pool.h> 43#include <sys/lock.h> 44#include <sys/mount.h> 45#include <sys/vnode.h> 46#include <sys/dirent.h> 47#include <sys/queue.h> 48#include <sys/endian.h> 49#include <sys/specdev.h> 50#include <sys/unistd.h> 51 52#include <crypto/siphash.h> 53 54#include <isofs/udf/ecma167-udf.h> 55#include <isofs/udf/udf.h> 56#include <isofs/udf/udf_extern.h> 57 58int udf_bmap_internal(struct unode *, off_t, daddr_t *, uint32_t *); 59 60const struct vops udf_vops = { 61 .vop_access = udf_access, 62 .vop_bmap = udf_bmap, 63 .vop_lookup = udf_lookup, 64 .vop_getattr = udf_getattr, 65 .vop_open = udf_open, 66 .vop_close = udf_close, 67 .vop_ioctl = udf_ioctl, 68 .vop_read = udf_read, 69 .vop_readdir = udf_readdir, 70 .vop_readlink = udf_readlink, 71 .vop_inactive = udf_inactive, 72 .vop_reclaim = udf_reclaim, 73 .vop_strategy = udf_strategy, 74 .vop_lock = udf_lock, 75 .vop_unlock = udf_unlock, 76 .vop_pathconf = udf_pathconf, 77 .vop_islocked = udf_islocked, 78 .vop_print = udf_print, 79 80 .vop_abortop = NULL, 81 .vop_advlock = NULL, 82 .vop_bwrite = NULL, 83 .vop_create = NULL, 84 .vop_fsync = NULL, 85 .vop_link = NULL, 86 .vop_mknod = NULL, 87 .vop_remove = eopnotsupp, 88 .vop_rename = NULL, 89 .vop_revoke = NULL, 90 .vop_mkdir = NULL, 91 .vop_rmdir = NULL, 92 .vop_setattr = NULL, 93 .vop_symlink = NULL, 94 .vop_write = NULL, 95 .vop_kqfilter = NULL 96}; 97 98#define UDF_INVALID_BMAP -1 99 100/* Look up a unode based on the udfino_t passed in and return its vnode */ 101int 102udf_hashlookup(struct umount *ump, udfino_t id, int flags, struct vnode **vpp) 103{ 104 struct unode *up; 105 struct udf_hash_lh *lh; 106 int error; 107 108 *vpp = NULL; 109 110loop: 111 mtx_enter(&ump->um_hashmtx); 112 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, &id, sizeof(id)) & 113 ump->um_hashsz]; 114 if (lh == NULL) { 115 mtx_leave(&ump->um_hashmtx); 116 return (ENOENT); 117 } 118 119 LIST_FOREACH(up, lh, u_le) { 120 if (up->u_ino == id) { 121 mtx_leave(&ump->um_hashmtx); 122 error = vget(up->u_vnode, flags); 123 if (error == ENOENT) 124 goto loop; 125 if (error) 126 return (error); 127 *vpp = up->u_vnode; 128 return (0); 129 } 130 } 131 132 mtx_leave(&ump->um_hashmtx); 133 134 return (0); 135} 136 137int 138udf_hashins(struct unode *up) 139{ 140 struct umount *ump; 141 struct udf_hash_lh *lh; 142 143 ump = up->u_ump; 144 145 vn_lock(up->u_vnode, LK_EXCLUSIVE | LK_RETRY); 146 mtx_enter(&ump->um_hashmtx); 147 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, 148 &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz]; 149 if (lh == NULL) 150 panic("hash entry is NULL, up->u_ino = %d", up->u_ino); 151 LIST_INSERT_HEAD(lh, up, u_le); 152 mtx_leave(&ump->um_hashmtx); 153 154 return (0); 155} 156 157int 158udf_hashrem(struct unode *up) 159{ 160 struct umount *ump; 161 struct udf_hash_lh *lh; 162 163 ump = up->u_ump; 164 165 mtx_enter(&ump->um_hashmtx); 166 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, 167 &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz]; 168 if (lh == NULL) 169 panic("hash entry is NULL, up->u_ino = %d", up->u_ino); 170 LIST_REMOVE(up, u_le); 171 mtx_leave(&ump->um_hashmtx); 172 173 return (0); 174} 175 176int 177udf_allocv(struct mount *mp, struct vnode **vpp, struct proc *p) 178{ 179 int error; 180 struct vnode *vp; 181 182 error = getnewvnode(VT_UDF, mp, &udf_vops, &vp); 183 if (error) { 184 printf("udf_allocv: failed to allocate new vnode\n"); 185 return (error); 186 } 187 188 *vpp = vp; 189 return (0); 190} 191 192/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */ 193static mode_t 194udf_permtomode(struct unode *up) 195{ 196 uint32_t perm; 197 uint16_t flags; 198 mode_t mode; 199 200 perm = letoh32(up->u_fentry->perm); 201 flags = letoh16(up->u_fentry->icbtag.flags); 202 203 mode = perm & UDF_FENTRY_PERM_USER_MASK; 204 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2); 205 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4); 206 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4); 207 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6); 208 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8); 209 210 return (mode); 211} 212 213int 214udf_access(void *v) 215{ 216 struct vop_access_args *ap = v; 217 struct vnode *vp; 218 struct unode *up; 219 mode_t a_mode, mode; 220 221 vp = ap->a_vp; 222 up = VTOU(vp); 223 a_mode = ap->a_mode; 224 225 if (a_mode & VWRITE) { 226 switch (vp->v_type) { 227 case VDIR: 228 case VLNK: 229 case VREG: 230 return (EROFS); 231 /* NOTREACHED */ 232 default: 233 break; 234 } 235 } 236 237 mode = udf_permtomode(up); 238 239 return (vaccess(vp->v_type, mode, up->u_fentry->uid, up->u_fentry->gid, 240 a_mode, ap->a_cred)); 241} 242 243static int mon_lens[2][12] = { 244 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 245 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 246}; 247 248static int 249udf_isaleapyear(int year) 250{ 251 int i; 252 253 i = (year % 4) ? 0 : 1; 254 i &= (year % 100) ? 1 : 0; 255 i |= (year % 400) ? 0 : 1; 256 257 return (i); 258} 259 260/* 261 * This is just a rough hack. Daylight savings isn't calculated and tv_nsec 262 * is ignored. 263 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>. 264 */ 265static void 266udf_timetotimespec(struct timestamp *time, struct timespec *t) 267{ 268 int i, lpyear, daysinyear, year; 269 union { 270 uint16_t u_tz_offset; 271 int16_t s_tz_offset; 272 } tz; 273 274 /* DirectCD seems to like using bogus year values */ 275 year = letoh16(time->year); 276 if (year < 1970) { 277 t->tv_sec = 0; 278 t->tv_nsec = 0; 279 return; 280 } 281 282 /* Calculate the time and day */ 283 t->tv_nsec = 1000 * time->usec + 100000 * time->hund_usec 284 + 10000000 * time->centisec; 285 t->tv_sec = time->second; 286 t->tv_sec += time->minute * 60; 287 t->tv_sec += time->hour * 3600; 288 t->tv_sec += time->day * 3600 * 24; 289 290 /* Calculate the month */ 291 lpyear = udf_isaleapyear(year); 292 for (i = 1; i < time->month; i++) 293 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24; 294 295 /* Speed up the calculation */ 296 if (year > 1979) 297 t->tv_sec += 315532800; 298 if (year > 1989) 299 t->tv_sec += 315619200; 300 if (year > 1999) 301 t->tv_sec += 315532800; 302 for (i = 2000; i < year; i++) { 303 daysinyear = udf_isaleapyear(i) + 365 ; 304 t->tv_sec += daysinyear * 3600 * 24; 305 } 306 307 /* 308 * Calculate the time zone. The timezone is 12 bit signed 2's 309 * compliment, so we gotta do some extra magic to handle it right. 310 */ 311 tz.u_tz_offset = letoh16(time->type_tz); 312 tz.u_tz_offset &= 0x0fff; 313 if (tz.u_tz_offset & 0x0800) 314 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */ 315 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047)) 316 t->tv_sec -= tz.s_tz_offset * 60; 317 318 return; 319} 320 321int 322udf_getattr(void *v) 323{ 324 struct vop_getattr_args *ap = v; 325 struct vnode *vp; 326 struct unode *up; 327 struct vattr *vap; 328 struct extfile_entry *xfentry; 329 struct file_entry *fentry; 330 struct timespec ts; 331 332 ts.tv_sec = 0; 333 334 vp = ap->a_vp; 335 vap = ap->a_vap; 336 up = VTOU(vp); 337 338 xfentry = up->u_fentry; 339 fentry = (struct file_entry *)up->u_fentry; 340 341 vap->va_fsid = up->u_dev; 342 vap->va_fileid = up->u_ino; 343 vap->va_mode = udf_permtomode(up); 344 vap->va_nlink = letoh16(fentry->link_cnt); 345 /* 346 * The spec says that -1 is valid for uid/gid and indicates an 347 * invalid uid/gid. How should this be represented? 348 */ 349 vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid); 350 vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid); 351 vap->va_rdev = 0; 352 if (vp->v_type & VDIR) { 353 vap->va_nlink++; /* Count a reference to ourselves */ 354 /* 355 * Directories that are recorded within their ICB will show 356 * as having 0 blocks recorded. Since tradition dictates 357 * that directories consume at least one logical block, 358 * make it appear so. 359 */ 360 vap->va_size = up->u_ump->um_bsize; 361 } else 362 vap->va_size = letoh64(fentry->inf_len); 363 if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { 364 udf_timetotimespec(&xfentry->atime, &vap->va_atime); 365 udf_timetotimespec(&xfentry->mtime, &vap->va_mtime); 366 if ((vp->v_type & VDIR) && xfentry->logblks_rec != 0) 367 vap->va_size = 368 letoh64(xfentry->logblks_rec) * up->u_ump->um_bsize; 369 } else { 370 udf_timetotimespec(&fentry->atime, &vap->va_atime); 371 udf_timetotimespec(&fentry->mtime, &vap->va_mtime); 372 if ((vp->v_type & VDIR) && fentry->logblks_rec != 0) 373 vap->va_size = 374 letoh64(fentry->logblks_rec) * up->u_ump->um_bsize; 375 } 376 vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */ 377 vap->va_flags = 0; 378 vap->va_gen = 1; 379 vap->va_blocksize = up->u_ump->um_bsize; 380 vap->va_bytes = letoh64(fentry->inf_len); 381 vap->va_type = vp->v_type; 382 vap->va_filerev = 0; 383 384 return (0); 385} 386 387int 388udf_open(void *v) 389{ 390 return (0); /* Nothing to be done at this point */ 391} 392 393int 394udf_close(void *v) 395{ 396 return (0); /* Nothing to be done at this point */ 397} 398 399/* 400 * File specific ioctls. 401 */ 402int 403udf_ioctl(void *v) 404{ 405 return (ENOTTY); 406} 407 408/* 409 * I'm not sure that this has much value in a read-only filesystem, but 410 * cd9660 has it too. 411 */ 412int 413udf_pathconf(void *v) 414{ 415 struct vop_pathconf_args *ap = v; 416 int error = 0; 417 418 switch (ap->a_name) { 419 case _PC_LINK_MAX: 420 *ap->a_retval = 65535; 421 break; 422 case _PC_NAME_MAX: 423 *ap->a_retval = NAME_MAX; 424 break; 425 case _PC_CHOWN_RESTRICTED: 426 *ap->a_retval = 1; 427 break; 428 case _PC_NO_TRUNC: 429 *ap->a_retval = 1; 430 break; 431 case _PC_TIMESTAMP_RESOLUTION: 432 *ap->a_retval = 1000; /* 1 microsecond */ 433 break; 434 default: 435 error = EINVAL; 436 break; 437 } 438 439 return (error); 440} 441 442int 443udf_read(void *v) 444{ 445 struct vop_read_args *ap = v; 446 struct vnode *vp = ap->a_vp; 447 struct uio *uio = ap->a_uio; 448 struct unode *up = VTOU(vp); 449 struct buf *bp; 450 uint8_t *data; 451 off_t fsize, offset; 452 int error = 0; 453 int size; 454 455 if (uio->uio_offset < 0) 456 return (EINVAL); 457 458 fsize = letoh64(up->u_fentry->inf_len); 459 460 while (uio->uio_offset < fsize && uio->uio_resid > 0) { 461 offset = uio->uio_offset; 462 size = ulmin(uio->uio_resid, MAXBSIZE); 463 if (size > fsize - offset) 464 size = fsize - offset; 465 error = udf_readatoffset(up, &size, offset, &bp, &data); 466 if (error == 0) 467 error = uiomove(data, (size_t)size, uio); 468 if (bp != NULL) { 469 brelse(bp); 470 bp = NULL; 471 } 472 if (error) 473 break; 474 }; 475 476 return (error); 477} 478 479/* 480 * Translate the name from a CS0 dstring to a 16-bit Unicode String. 481 * Hooks need to be placed in here to translate from Unicode to the encoding 482 * that the kernel/user expects. Return the length of the translated string. 483 */ 484int 485udf_transname(char *cs0string, char *destname, int len, struct umount *ump) 486{ 487 unicode_t *transname; 488 int i, unilen = 0, destlen; 489 490 if (len > MAXNAMLEN) { 491#ifdef DIAGNOSTIC 492 printf("udf_transname(): name too long\n"); 493#endif 494 return (0); 495 } 496 497 /* allocate a buffer big enough to hold an 8->16 bit expansion */ 498 transname = pool_get(&udf_trans_pool, PR_WAITOK); 499 500 if ((unilen = udf_rawnametounicode(len, cs0string, transname)) == -1) { 501#ifdef DIAGNOSTIC 502 printf("udf_transname(): Unicode translation failed\n"); 503#endif 504 pool_put(&udf_trans_pool, transname); 505 return (0); 506 } 507 508 /* Pack it back to 8-bit Unicode. */ 509 for (i = 0; i < unilen ; i++) 510 if (transname[i] & 0xff00) 511 destname[i] = '?'; /* Fudge the 16bit chars */ 512 else 513 destname[i] = transname[i] & 0xff; 514 515 pool_put(&udf_trans_pool, transname); 516 517 /* Don't forget to terminate the string. */ 518 destname[unilen] = 0; 519 destlen = unilen; 520 521 return (destlen); 522} 523 524/* 525 * Compare a CS0 dstring with a name passed in from the VFS layer. Return 526 * 0 on a successful match, nonzero otherwise. Unicode work may need to be 527 * done here also. 528 */ 529static int 530udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct umount *ump) 531{ 532 char *transname; 533 int error = 0; 534 535 /* This is overkill, but not worth creating a new pool */ 536 transname = pool_get(&udf_trans_pool, PR_WAITOK); 537 538 cs0len = udf_transname(cs0string, transname, cs0len, ump); 539 540 /* Easy check. If they aren't the same length, they aren't equal */ 541 if ((cs0len == 0) || (cs0len != cmplen)) 542 error = -1; 543 else 544 error = bcmp(transname, cmpname, cmplen); 545 546 pool_put(&udf_trans_pool, transname); 547 548 return (error); 549} 550 551struct udf_uiodir { 552 struct dirent *dirent; 553 int eofflag; 554}; 555 556static int 557udf_uiodir(struct udf_uiodir *uiodir, struct uio *uio, long off) 558{ 559 size_t de_size = DIRENT_SIZE(uiodir->dirent); 560 561 if (uio->uio_resid < de_size) { 562 uiodir->eofflag = 0; 563 return (-1); 564 } 565 uiodir->dirent->d_off = off; 566 uiodir->dirent->d_reclen = de_size; 567 568 return (uiomove(uiodir->dirent, de_size, uio)); 569} 570 571static struct udf_dirstream * 572udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump) 573{ 574 struct udf_dirstream *ds; 575 576 ds = pool_get(&udf_ds_pool, PR_WAITOK | PR_ZERO); 577 578 ds->node = up; 579 ds->offset = offset; 580 ds->ump = ump; 581 ds->fsize = fsize; 582 583 return (ds); 584} 585 586static struct fileid_desc * 587udf_getfid(struct udf_dirstream *ds) 588{ 589 struct fileid_desc *fid; 590 int error, frag_size = 0, total_fid_size; 591 592 /* End of directory? */ 593 if (ds->offset + ds->off >= ds->fsize) { 594 ds->error = 0; 595 return (NULL); 596 } 597 598 /* Grab the first extent of the directory */ 599 if (ds->off == 0) { 600 ds->size = 0; 601 error = udf_readatoffset(ds->node, &ds->size, ds->offset, 602 &ds->bp, &ds->data); 603 if (error) { 604 ds->error = error; 605 if (ds->bp != NULL) { 606 brelse(ds->bp); 607 ds->bp = NULL; 608 } 609 return (NULL); 610 } 611 } 612 613 /* 614 * Clean up from a previous fragmented FID. 615 * Is this the right place for this? 616 */ 617 if (ds->fid_fragment && ds->buf != NULL) { 618 ds->fid_fragment = 0; 619 free(ds->buf, M_UDFFID, 0); 620 } 621 622 fid = (struct fileid_desc*)&ds->data[ds->off]; 623 624 /* 625 * Check to see if the fid is fragmented. The first test 626 * ensures that we don't wander off the end of the buffer 627 * looking for the l_iu and l_fi fields. 628 */ 629 if (ds->off + UDF_FID_SIZE > ds->size || 630 ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){ 631 632 /* Copy what we have of the fid into a buffer */ 633 frag_size = ds->size - ds->off; 634 if (frag_size >= ds->ump->um_bsize) { 635 printf("udf: invalid FID fragment\n"); 636 ds->error = EINVAL; 637 return (NULL); 638 } 639 640 /* 641 * File ID descriptors can only be at most one 642 * logical sector in size. 643 */ 644 ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK|M_ZERO); 645 bcopy(fid, ds->buf, frag_size); 646 647 /* Reduce all of the casting magic */ 648 fid = (struct fileid_desc*)ds->buf; 649 650 if (ds->bp != NULL) { 651 brelse(ds->bp); 652 ds->bp = NULL; 653 } 654 655 /* Fetch the next allocation */ 656 ds->offset += ds->size; 657 ds->size = 0; 658 error = udf_readatoffset(ds->node, &ds->size, ds->offset, 659 &ds->bp, &ds->data); 660 if (error) { 661 ds->error = error; 662 if (ds->bp != NULL) { 663 brelse(ds->bp); 664 ds->bp = NULL; 665 } 666 return (NULL); 667 } 668 669 /* 670 * If the fragment was so small that we didn't get 671 * the l_iu and l_fi fields, copy those in. 672 */ 673 if (frag_size < UDF_FID_SIZE) 674 bcopy(ds->data, &ds->buf[frag_size], 675 UDF_FID_SIZE - frag_size); 676 677 /* 678 * Now that we have enough of the fid to work with, 679 * copy in the rest of the fid from the new 680 * allocation. 681 */ 682 total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi; 683 if (total_fid_size > ds->ump->um_bsize) { 684 printf("udf: invalid FID\n"); 685 ds->error = EIO; 686 return (NULL); 687 } 688 bcopy(ds->data, &ds->buf[frag_size], 689 total_fid_size - frag_size); 690 691 ds->fid_fragment = 1; 692 } else { 693 total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE; 694 } 695 696 /* 697 * Update the offset. Align on a 4 byte boundary because the 698 * UDF spec says so. 699 */ 700 if (!ds->fid_fragment) { 701 ds->off += (total_fid_size + 3) & ~0x03; 702 } else { 703 ds->off = (total_fid_size - frag_size + 3) & ~0x03; 704 } 705 ds->this_off = ds->offset + ds->off; 706 707 return (fid); 708} 709 710static void 711udf_closedir(struct udf_dirstream *ds) 712{ 713 714 if (ds->bp != NULL) { 715 brelse(ds->bp); 716 ds->bp = NULL; 717 } 718 719 if (ds->fid_fragment && ds->buf != NULL) 720 free(ds->buf, M_UDFFID, 0); 721 722 pool_put(&udf_ds_pool, ds); 723} 724 725#define SELF_OFFSET 1 726#define PARENT_OFFSET 2 727 728int 729udf_readdir(void *v) 730{ 731 struct vop_readdir_args *ap = v; 732 struct vnode *vp; 733 struct uio *uio; 734 struct dirent dir; 735 struct unode *up; 736 struct umount *ump; 737 struct fileid_desc *fid; 738 struct udf_uiodir uiodir; 739 struct udf_dirstream *ds; 740 off_t last_off; 741 enum { MODE_NORMAL, MODE_SELF, MODE_PARENT } mode; 742 int error = 0; 743 744 vp = ap->a_vp; 745 uio = ap->a_uio; 746 up = VTOU(vp); 747 ump = up->u_ump; 748 uiodir.eofflag = 1; 749 uiodir.dirent = &dir; 750 memset(&dir, 0, sizeof(dir)); 751 752 /* 753 * if asked to start at SELF_OFFSET or PARENT_OFFSET, search 754 * for the parent ref 755 */ 756 if (uio->uio_offset == SELF_OFFSET) { 757 mode = MODE_SELF; 758 uio->uio_offset = 0; 759 } else if (uio->uio_offset == PARENT_OFFSET) { 760 mode = MODE_PARENT; 761 uio->uio_offset = 0; 762 } else 763 mode = MODE_NORMAL; 764 765 /* 766 * Iterate through the file id descriptors. Give the parent dir 767 * entry special attention. 768 */ 769 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 770 up->u_ump->um_start += up->u_ump->um_meta_start; 771 up->u_ump->um_len = up->u_ump->um_meta_len; 772 } 773 ds = udf_opendir(up, uio->uio_offset, 774 letoh64(up->u_fentry->inf_len), up->u_ump); 775 776 last_off = ds->offset + ds->off; 777 while ((fid = udf_getfid(ds)) != NULL) { 778 779 /* Should we return an error on a bad fid? */ 780 if (udf_checktag(&fid->tag, TAGID_FID)) { 781 printf("Invalid FID tag (%d)\n", fid->tag.id); 782 error = EIO; 783 break; 784 } 785 786 /* Is this a deleted file? */ 787 if (fid->file_char & UDF_FILE_CHAR_DEL) 788 continue; 789 790 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 791 /* Do up the '.' and '..' entries. Dummy values are 792 * used for the offset since the offset here is 793 * usually zero, and NFS doesn't like that value 794 */ 795 if (mode == MODE_NORMAL) { 796 dir.d_fileno = up->u_ino; 797 dir.d_type = DT_DIR; 798 dir.d_name[0] = '.'; 799 dir.d_name[1] = '\0'; 800 dir.d_namlen = 1; 801 error = udf_uiodir(&uiodir, uio, SELF_OFFSET); 802 if (error) 803 break; 804 } 805 if (mode != MODE_PARENT) { 806 dir.d_fileno = udf_getid(&fid->icb); 807 dir.d_type = DT_DIR; 808 dir.d_name[0] = '.'; 809 dir.d_name[1] = '.'; 810 dir.d_name[2] = '\0'; 811 dir.d_namlen = 2; 812 error = udf_uiodir(&uiodir, uio, PARENT_OFFSET); 813 } 814 mode = MODE_NORMAL; 815 } else if (mode != MODE_NORMAL) { 816 continue; 817 } else { 818 dir.d_namlen = udf_transname(&fid->data[fid->l_iu], 819 &dir.d_name[0], fid->l_fi, ump); 820 dir.d_fileno = udf_getid(&fid->icb); 821 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? 822 DT_DIR : DT_UNKNOWN; 823 error = udf_uiodir(&uiodir, uio, ds->this_off); 824 } 825 if (error) { 826 /* 827 * udf_uiodir() indicates there isn't space for 828 * another entry by returning -1 829 */ 830 if (error == -1) 831 error = 0; 832 break; 833 } 834 last_off = ds->this_off; 835 } 836 837 /* tell the calling layer whether we need to be called again */ 838 *ap->a_eofflag = uiodir.eofflag; 839 uio->uio_offset = last_off; 840 841 if (!error) 842 error = ds->error; 843 844 udf_closedir(ds); 845 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 846 up->u_ump->um_start = up->u_ump->um_realstart; 847 up->u_ump->um_len = up->u_ump->um_reallen; 848 } 849 850 return (error); 851} 852 853/* Are there any implementations out there that do soft-links? */ 854int 855udf_readlink(void *v) 856{ 857 return (EOPNOTSUPP); 858} 859 860int 861udf_strategy(void *v) 862{ 863 struct vop_strategy_args *ap = v; 864 struct buf *bp; 865 struct vnode *vp; 866 struct unode *up; 867 int maxsize, s, error; 868 869 bp = ap->a_bp; 870 vp = bp->b_vp; 871 up = VTOU(vp); 872 873 /* cd9660 has this test reversed, but it seems more logical this way */ 874 if (bp->b_blkno != bp->b_lblkno) { 875 /* 876 * Files that are embedded in the fentry don't translate well 877 * to a block number. Reject. 878 */ 879 if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize, 880 &bp->b_lblkno, &maxsize)) { 881 clrbuf(bp); 882 bp->b_blkno = -1; 883 } 884 } else { 885 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 886 if (error) { 887 bp->b_error = error; 888 bp->b_flags |= B_ERROR; 889 s = splbio(); 890 biodone(bp); 891 splx(s); 892 return (error); 893 } 894 895 if ((long)bp->b_blkno == -1) 896 clrbuf(bp); 897 } 898 899 if ((long)bp->b_blkno == -1) { 900 s = splbio(); 901 biodone(bp); 902 splx(s); 903 } else { 904 bp->b_dev = vp->v_rdev; 905 VOP_STRATEGY(up->u_devvp, bp); 906 } 907 908 return (0); 909} 910 911int 912udf_lock(void *v) 913{ 914 struct vop_lock_args *ap = v; 915 struct vnode *vp = ap->a_vp; 916 917 return rrw_enter(&VTOU(vp)->u_lock, ap->a_flags & LK_RWFLAGS); 918} 919 920int 921udf_unlock(void *v) 922{ 923 struct vop_unlock_args *ap = v; 924 struct vnode *vp = ap->a_vp; 925 926 rrw_exit(&VTOU(vp)->u_lock); 927 return 0; 928} 929 930int 931udf_islocked(void *v) 932{ 933 struct vop_islocked_args *ap = v; 934 935 return rrw_status(&VTOU(ap->a_vp)->u_lock); 936} 937 938int 939udf_print(void *v) 940{ 941 struct vop_print_args *ap = v; 942 struct vnode *vp = ap->a_vp; 943 struct unode *up = VTOU(vp); 944 945 /* 946 * Complete the information given by vprint(). 947 */ 948 printf("tag VT_UDF, hash id %u\n", up->u_ino); 949#ifdef DIAGNOSTIC 950 printf("\n"); 951#endif 952 return (0); 953} 954 955int 956udf_bmap(void *v) 957{ 958 struct vop_bmap_args *ap = v; 959 struct unode *up; 960 uint32_t max_size; 961 daddr_t lsector; 962 int error; 963 964 up = VTOU(ap->a_vp); 965 966 if (ap->a_vpp != NULL) 967 *ap->a_vpp = up->u_devvp; 968 if (ap->a_bnp == NULL) 969 return (0); 970 971 error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize, 972 &lsector, &max_size); 973 if (error) 974 return (error); 975 976 /* Translate logical to physical sector number */ 977 *ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT); 978 979 /* Punt on read-ahead for now */ 980 if (ap->a_runp) 981 *ap->a_runp = 0; 982 983 return (0); 984} 985 986/* 987 * The all powerful VOP_LOOKUP(). 988 */ 989int 990udf_lookup(void *v) 991{ 992 struct vop_lookup_args *ap = v; 993 struct vnode *dvp; 994 struct vnode *tdp = NULL; 995 struct vnode **vpp = ap->a_vpp; 996 struct unode *up; 997 struct umount *ump; 998 struct fileid_desc *fid = NULL; 999 struct udf_dirstream *ds; 1000 struct proc *p; 1001 u_long nameiop; 1002 u_long flags; 1003 char *nameptr; 1004 long namelen; 1005 udfino_t id = 0; 1006 int offset, error = 0; 1007 int numdirpasses, fsize; 1008 1009 extern struct nchstats nchstats; 1010 1011 dvp = ap->a_dvp; 1012 up = VTOU(dvp); 1013 ump = up->u_ump; 1014 nameiop = ap->a_cnp->cn_nameiop; 1015 flags = ap->a_cnp->cn_flags; 1016 nameptr = ap->a_cnp->cn_nameptr; 1017 namelen = ap->a_cnp->cn_namelen; 1018 fsize = letoh64(up->u_fentry->inf_len); 1019 p = ap->a_cnp->cn_proc; 1020 *vpp = NULL; 1021 1022 /* 1023 * Make sure the process can scan the requested directory. 1024 */ 1025 error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p); 1026 if (error) 1027 return (error); 1028 1029 /* 1030 * Check if the (directory, name) tuple has been already cached. 1031 */ 1032 error = cache_lookup(dvp, vpp, ap->a_cnp); 1033 if (error >= 0) 1034 return (error); 1035 else 1036 error = 0; 1037 1038 /* 1039 * If dvp is what's being looked up, then return it. 1040 */ 1041 if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') { 1042 vref(dvp); 1043 *vpp = dvp; 1044 return (0); 1045 } 1046 1047 /* 1048 * If this is a LOOKUP and we've already partially searched through 1049 * the directory, pick up where we left off and flag that the 1050 * directory may need to be searched twice. For a full description, 1051 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup() 1052 */ 1053 if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) { 1054 offset = 0; 1055 numdirpasses = 1; 1056 } else { 1057 offset = up->u_diroff; 1058 numdirpasses = 2; 1059 nchstats.ncs_2passes++; 1060 } 1061 1062 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1063 up->u_ump->um_start += up->u_ump->um_meta_start; 1064 up->u_ump->um_len = up->u_ump->um_meta_len; 1065 } 1066lookloop: 1067 ds = udf_opendir(up, offset, fsize, ump); 1068 1069 while ((fid = udf_getfid(ds)) != NULL) { 1070 /* Check for a valid FID tag. */ 1071 if (udf_checktag(&fid->tag, TAGID_FID)) { 1072 printf("udf_lookup: Invalid tag\n"); 1073 error = EIO; 1074 break; 1075 } 1076 1077 /* Is this a deleted file? */ 1078 if (fid->file_char & UDF_FILE_CHAR_DEL) 1079 continue; 1080 1081 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 1082 if (flags & ISDOTDOT) { 1083 id = udf_getid(&fid->icb); 1084 break; 1085 } 1086 } else { 1087 if (!(udf_cmpname(&fid->data[fid->l_iu], 1088 nameptr, fid->l_fi, namelen, ump))) { 1089 id = udf_getid(&fid->icb); 1090 break; 1091 } 1092 } 1093 } 1094 1095 if (!error) 1096 error = ds->error; 1097 1098 if (error) { 1099 udf_closedir(ds); 1100 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1101 up->u_ump->um_start = up->u_ump->um_realstart; 1102 up->u_ump->um_len = up->u_ump->um_reallen; 1103 } 1104 return (error); 1105 } 1106 1107 /* Did we have a match? */ 1108 if (id) { 1109 error = udf_vget(ump->um_mountp, id, &tdp); 1110 if (!error) { 1111 /* 1112 * Remember where this entry was if it's the final 1113 * component. 1114 */ 1115 if ((flags & ISLASTCN) && nameiop == LOOKUP) 1116 up->u_diroff = ds->offset + ds->off; 1117 if (numdirpasses == 2) 1118 nchstats.ncs_pass2++; 1119 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 1120 ap->a_cnp->cn_flags |= PDIRUNLOCK; 1121 VOP_UNLOCK(dvp); 1122 } 1123 1124 *vpp = tdp; 1125 } 1126 } else { 1127 /* Name wasn't found on this pass. Do another pass? */ 1128 if (numdirpasses == 2) { 1129 numdirpasses--; 1130 offset = 0; 1131 udf_closedir(ds); 1132 goto lookloop; 1133 } 1134 1135 if ((flags & ISLASTCN) && 1136 (nameiop == CREATE || nameiop == RENAME)) { 1137 error = EROFS; 1138 } else { 1139 error = ENOENT; 1140 } 1141 } 1142 1143 /* 1144 * Cache the result of this lookup. 1145 */ 1146 if (flags & MAKEENTRY) 1147 cache_enter(dvp, *vpp, ap->a_cnp); 1148 1149 udf_closedir(ds); 1150 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1151 up->u_ump->um_start = up->u_ump->um_realstart; 1152 up->u_ump->um_len = up->u_ump->um_reallen; 1153 } 1154 1155 return (error); 1156} 1157 1158int 1159udf_inactive(void *v) 1160{ 1161 struct vop_inactive_args *ap = v; 1162 struct vnode *vp = ap->a_vp; 1163 1164 /* 1165 * No need to sync anything, so just unlock the vnode and return. 1166 */ 1167 VOP_UNLOCK(vp); 1168 1169 return (0); 1170} 1171 1172int 1173udf_reclaim(void *v) 1174{ 1175 struct vop_reclaim_args *ap = v; 1176 struct vnode *vp; 1177 struct unode *up; 1178 1179 vp = ap->a_vp; 1180 up = VTOU(vp); 1181 1182 if (up != NULL) { 1183 udf_hashrem(up); 1184 if (up->u_devvp) { 1185 vrele(up->u_devvp); 1186 up->u_devvp = 0; 1187 } 1188 1189 if (up->u_fentry != NULL) 1190 free(up->u_fentry, M_UDFFENTRY, 0); 1191 1192 pool_put(&unode_pool, up); 1193 vp->v_data = NULL; 1194 } 1195 1196 return (0); 1197} 1198 1199/* 1200 * Read the block and then set the data pointer to correspond with the 1201 * offset passed in. Only read in at most 'size' bytes, and then set 'size' 1202 * to the number of bytes pointed to. If 'size' is zero, try to read in a 1203 * whole extent. 1204 * 1205 * Note that *bp may be assigned error or not. 1206 * 1207 */ 1208int 1209udf_readatoffset(struct unode *up, int *size, off_t offset, 1210 struct buf **bp, uint8_t **data) 1211{ 1212 struct umount *ump; 1213 struct extfile_entry *xfentry = NULL; 1214 struct file_entry *fentry = NULL; 1215 struct buf *bp1; 1216 uint32_t max_size; 1217 daddr_t sector; 1218 int error; 1219 1220 ump = up->u_ump; 1221 1222 *bp = NULL; 1223 error = udf_bmap_internal(up, offset, §or, &max_size); 1224 if (error == UDF_INVALID_BMAP) { 1225 /* 1226 * This error means that the file *data* is stored in the 1227 * allocation descriptor field of the file entry. 1228 */ 1229 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) { 1230 xfentry = up->u_fentry; 1231 *data = &xfentry->data[letoh32(xfentry->l_ea)]; 1232 *size = letoh32(xfentry->l_ad); 1233 } else { 1234 fentry = (struct file_entry *)up->u_fentry; 1235 *data = &fentry->data[letoh32(fentry->l_ea)]; 1236 *size = letoh32(fentry->l_ad); 1237 } 1238 return (0); 1239 } else if (error != 0) { 1240 return (error); 1241 } 1242 1243 /* Adjust the size so that it is within range */ 1244 if (*size == 0 || *size > max_size) 1245 *size = max_size; 1246 *size = min(*size, MAXBSIZE); 1247 1248 if ((error = udf_readlblks(ump, sector, *size, bp))) { 1249 printf("warning: udf_readlblks returned error %d\n", error); 1250 /* note: *bp may be non-NULL */ 1251 return (error); 1252 } 1253 1254 bp1 = *bp; 1255 *data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize]; 1256 return (0); 1257} 1258 1259/* 1260 * Translate a file offset into a logical block and then into a physical 1261 * block. 1262 */ 1263int 1264udf_bmap_internal(struct unode *up, off_t offset, daddr_t *sector, 1265 uint32_t *max_size) 1266{ 1267 struct umount *ump; 1268 struct extfile_entry *xfentry; 1269 struct file_entry *fentry; 1270 void *icb; 1271 struct icb_tag *tag; 1272 uint32_t icblen = 0; 1273 daddr_t lsector; 1274 int ad_offset, ad_num = 0; 1275 int i, p_offset, l_ea, l_ad; 1276 1277 ump = up->u_ump; 1278 xfentry = up->u_fentry; 1279 fentry = (struct file_entry *)up->u_fentry; 1280 tag = &fentry->icbtag; 1281 if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { 1282 l_ea = letoh32(xfentry->l_ea); 1283 l_ad = letoh32(xfentry->l_ad); 1284 } else { 1285 l_ea = letoh32(fentry->l_ea); 1286 l_ad = letoh32(fentry->l_ad); 1287 } 1288 1289 switch (letoh16(tag->strat_type)) { 1290 case 4: 1291 break; 1292 1293 case 4096: 1294 printf("Cannot deal with strategy4096 yet!\n"); 1295 return (ENODEV); 1296 1297 default: 1298 printf("Unknown strategy type %d\n", tag->strat_type); 1299 return (ENODEV); 1300 } 1301 1302 switch (letoh16(tag->flags) & 0x7) { 1303 case 0: 1304 /* 1305 * The allocation descriptor field is filled with short_ad's. 1306 * If the offset is beyond the current extent, look for the 1307 * next extent. 1308 */ 1309 do { 1310 offset -= icblen; 1311 ad_offset = sizeof(struct short_ad) * ad_num; 1312 if (ad_offset > l_ad) { 1313 printf("SFile offset out of bounds (%d > %d)\n", 1314 ad_offset, l_ad); 1315 return (EINVAL); 1316 } 1317 1318 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1319 icb = GETICB(short_ad, xfentry, l_ea + ad_offset); 1320 else 1321 icb = GETICB(short_ad, fentry, l_ea + ad_offset); 1322 1323 icblen = GETICBLEN(short_ad, icb); 1324 ad_num++; 1325 } while(offset >= icblen); 1326 1327 lsector = (offset >> ump->um_bshift) + 1328 letoh32(((struct short_ad *)(icb))->lb_num); 1329 1330 *max_size = GETICBLEN(short_ad, icb); 1331 1332 break; 1333 case 1: 1334 /* 1335 * The allocation descriptor field is filled with long_ad's 1336 * If the offset is beyond the current extent, look for the 1337 * next extent. 1338 */ 1339 do { 1340 offset -= icblen; 1341 ad_offset = sizeof(struct long_ad) * ad_num; 1342 if (ad_offset > l_ad) { 1343 printf("LFile offset out of bounds (%d > %d)\n", 1344 ad_offset, l_ad); 1345 return (EINVAL); 1346 } 1347 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1348 icb = GETICB(long_ad, xfentry, l_ea + ad_offset); 1349 else 1350 icb = GETICB(long_ad, fentry, l_ea + ad_offset); 1351 icblen = GETICBLEN(long_ad, icb); 1352 ad_num++; 1353 } while(offset >= icblen); 1354 1355 lsector = (offset >> ump->um_bshift) + 1356 letoh32(((struct long_ad *)(icb))->loc.lb_num); 1357 1358 *max_size = GETICBLEN(long_ad, icb); 1359 1360 break; 1361 case 3: 1362 /* 1363 * This type means that the file *data* is stored in the 1364 * allocation descriptor field of the file entry. 1365 */ 1366 *max_size = 0; 1367 *sector = up->u_ino + ump->um_start; 1368 1369 return (UDF_INVALID_BMAP); 1370 case 2: 1371 /* DirectCD does not use extended_ad's */ 1372 default: 1373 printf("Unsupported allocation descriptor %d\n", 1374 tag->flags & 0x7); 1375 return (ENODEV); 1376 } 1377 1378 *sector = lsector + ump->um_start; 1379 1380 /* 1381 * Check the sparing table. Each entry represents the beginning of 1382 * a packet. 1383 */ 1384 if (ump->um_stbl != NULL) { 1385 for (i = 0; i< ump->um_stbl_len; i++) { 1386 p_offset = 1387 lsector - letoh32(ump->um_stbl->entries[i].org); 1388 if ((p_offset < ump->um_psecs) && (p_offset >= 0)) { 1389 *sector = 1390 letoh32(ump->um_stbl->entries[i].map) + 1391 p_offset; 1392 break; 1393 } 1394 } 1395 } 1396 1397 return (0); 1398} 1399