1 /* $OpenBSD: udf_vnops.c,v 1.75 2024/10/18 05:52:32 miod 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 58 int udf_bmap_internal(struct unode *, off_t, daddr_t *, uint32_t *); 59 60 const 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 */ 101 int 102 udf_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 110 loop: 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 137 int 138 udf_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 157 int 158 udf_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 176 int 177 udf_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 */ 193 static mode_t 194 udf_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 213 int 214 udf_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 243 static 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 248 static int 249 udf_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 */ 265 static void 266 udf_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 321 int 322 udf_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 387 int 388 udf_open(void *v) 389 { 390 return (0); /* Nothing to be done at this point */ 391 } 392 393 int 394 udf_close(void *v) 395 { 396 return (0); /* Nothing to be done at this point */ 397 } 398 399 /* 400 * File specific ioctls. 401 */ 402 int 403 udf_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 */ 412 int 413 udf_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 442 int 443 udf_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 */ 484 int 485 udf_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 */ 529 static int 530 udf_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 551 struct udf_uiodir { 552 struct dirent *dirent; 553 int eofflag; 554 }; 555 556 static int 557 udf_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 if (memchr(uiodir->dirent->d_name, '/', 569 uiodir->dirent->d_namlen) != NULL) { 570 /* illegal file name */ 571 return (EINVAL); 572 } 573 574 return (uiomove(uiodir->dirent, de_size, uio)); 575 } 576 577 static struct udf_dirstream * 578 udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump) 579 { 580 struct udf_dirstream *ds; 581 582 ds = pool_get(&udf_ds_pool, PR_WAITOK | PR_ZERO); 583 584 ds->node = up; 585 ds->offset = offset; 586 ds->ump = ump; 587 ds->fsize = fsize; 588 589 return (ds); 590 } 591 592 static struct fileid_desc * 593 udf_getfid(struct udf_dirstream *ds) 594 { 595 struct fileid_desc *fid; 596 int error, frag_size = 0, total_fid_size; 597 598 /* End of directory? */ 599 if (ds->offset + ds->off >= ds->fsize) { 600 ds->error = 0; 601 return (NULL); 602 } 603 604 /* Grab the first extent of the directory */ 605 if (ds->off == 0) { 606 ds->size = 0; 607 error = udf_readatoffset(ds->node, &ds->size, ds->offset, 608 &ds->bp, &ds->data); 609 if (error) { 610 ds->error = error; 611 if (ds->bp != NULL) { 612 brelse(ds->bp); 613 ds->bp = NULL; 614 } 615 return (NULL); 616 } 617 } 618 619 /* 620 * Clean up from a previous fragmented FID. 621 * Is this the right place for this? 622 */ 623 if (ds->fid_fragment && ds->buf != NULL) { 624 ds->fid_fragment = 0; 625 free(ds->buf, M_UDFFID, 0); 626 } 627 628 fid = (struct fileid_desc*)&ds->data[ds->off]; 629 630 /* 631 * Check to see if the fid is fragmented. The first test 632 * ensures that we don't wander off the end of the buffer 633 * looking for the l_iu and l_fi fields. 634 */ 635 if (ds->off + UDF_FID_SIZE > ds->size || 636 ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){ 637 638 /* Copy what we have of the fid into a buffer */ 639 frag_size = ds->size - ds->off; 640 if (frag_size >= ds->ump->um_bsize) { 641 printf("udf: invalid FID fragment\n"); 642 ds->error = EINVAL; 643 return (NULL); 644 } 645 646 /* 647 * File ID descriptors can only be at most one 648 * logical sector in size. 649 */ 650 ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK|M_ZERO); 651 bcopy(fid, ds->buf, frag_size); 652 653 /* Reduce all of the casting magic */ 654 fid = (struct fileid_desc*)ds->buf; 655 656 if (ds->bp != NULL) { 657 brelse(ds->bp); 658 ds->bp = NULL; 659 } 660 661 /* Fetch the next allocation */ 662 ds->offset += ds->size; 663 ds->size = 0; 664 error = udf_readatoffset(ds->node, &ds->size, ds->offset, 665 &ds->bp, &ds->data); 666 if (error) { 667 ds->error = error; 668 if (ds->bp != NULL) { 669 brelse(ds->bp); 670 ds->bp = NULL; 671 } 672 return (NULL); 673 } 674 675 /* 676 * If the fragment was so small that we didn't get 677 * the l_iu and l_fi fields, copy those in. 678 */ 679 if (frag_size < UDF_FID_SIZE) 680 bcopy(ds->data, &ds->buf[frag_size], 681 UDF_FID_SIZE - frag_size); 682 683 /* 684 * Now that we have enough of the fid to work with, 685 * copy in the rest of the fid from the new 686 * allocation. 687 */ 688 total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi; 689 if (total_fid_size > ds->ump->um_bsize) { 690 printf("udf: invalid FID\n"); 691 ds->error = EIO; 692 return (NULL); 693 } 694 bcopy(ds->data, &ds->buf[frag_size], 695 total_fid_size - frag_size); 696 697 ds->fid_fragment = 1; 698 } else { 699 total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE; 700 } 701 702 /* 703 * Update the offset. Align on a 4 byte boundary because the 704 * UDF spec says so. 705 */ 706 if (!ds->fid_fragment) { 707 ds->off += (total_fid_size + 3) & ~0x03; 708 } else { 709 ds->off = (total_fid_size - frag_size + 3) & ~0x03; 710 } 711 ds->this_off = ds->offset + ds->off; 712 713 return (fid); 714 } 715 716 static void 717 udf_closedir(struct udf_dirstream *ds) 718 { 719 720 if (ds->bp != NULL) { 721 brelse(ds->bp); 722 ds->bp = NULL; 723 } 724 725 if (ds->fid_fragment && ds->buf != NULL) 726 free(ds->buf, M_UDFFID, 0); 727 728 pool_put(&udf_ds_pool, ds); 729 } 730 731 #define SELF_OFFSET 1 732 #define PARENT_OFFSET 2 733 734 int 735 udf_readdir(void *v) 736 { 737 struct vop_readdir_args *ap = v; 738 struct vnode *vp; 739 struct uio *uio; 740 struct dirent dir; 741 struct unode *up; 742 struct umount *ump; 743 struct fileid_desc *fid; 744 struct udf_uiodir uiodir; 745 struct udf_dirstream *ds; 746 off_t last_off; 747 enum { MODE_NORMAL, MODE_SELF, MODE_PARENT } mode; 748 int error = 0; 749 750 vp = ap->a_vp; 751 uio = ap->a_uio; 752 up = VTOU(vp); 753 ump = up->u_ump; 754 uiodir.eofflag = 1; 755 uiodir.dirent = &dir; 756 memset(&dir, 0, sizeof(dir)); 757 758 /* 759 * if asked to start at SELF_OFFSET or PARENT_OFFSET, search 760 * for the parent ref 761 */ 762 if (uio->uio_offset == SELF_OFFSET) { 763 mode = MODE_SELF; 764 uio->uio_offset = 0; 765 } else if (uio->uio_offset == PARENT_OFFSET) { 766 mode = MODE_PARENT; 767 uio->uio_offset = 0; 768 } else 769 mode = MODE_NORMAL; 770 771 /* 772 * Iterate through the file id descriptors. Give the parent dir 773 * entry special attention. 774 */ 775 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 776 up->u_ump->um_start += up->u_ump->um_meta_start; 777 up->u_ump->um_len = up->u_ump->um_meta_len; 778 } 779 ds = udf_opendir(up, uio->uio_offset, 780 letoh64(up->u_fentry->inf_len), up->u_ump); 781 782 last_off = ds->offset + ds->off; 783 while ((fid = udf_getfid(ds)) != NULL) { 784 785 /* Should we return an error on a bad fid? */ 786 if (udf_checktag(&fid->tag, TAGID_FID)) { 787 printf("Invalid FID tag (%d)\n", fid->tag.id); 788 error = EIO; 789 break; 790 } 791 792 /* Is this a deleted file? */ 793 if (fid->file_char & UDF_FILE_CHAR_DEL) 794 continue; 795 796 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 797 /* Do up the '.' and '..' entries. Dummy values are 798 * used for the offset since the offset here is 799 * usually zero, and NFS doesn't like that value 800 */ 801 if (mode == MODE_NORMAL) { 802 dir.d_fileno = up->u_ino; 803 dir.d_type = DT_DIR; 804 dir.d_name[0] = '.'; 805 dir.d_name[1] = '\0'; 806 dir.d_namlen = 1; 807 error = udf_uiodir(&uiodir, uio, SELF_OFFSET); 808 if (error) 809 break; 810 } 811 if (mode != MODE_PARENT) { 812 dir.d_fileno = udf_getid(&fid->icb); 813 dir.d_type = DT_DIR; 814 dir.d_name[0] = '.'; 815 dir.d_name[1] = '.'; 816 dir.d_name[2] = '\0'; 817 dir.d_namlen = 2; 818 error = udf_uiodir(&uiodir, uio, PARENT_OFFSET); 819 } 820 mode = MODE_NORMAL; 821 } else if (mode != MODE_NORMAL) { 822 continue; 823 } else { 824 dir.d_namlen = udf_transname(&fid->data[fid->l_iu], 825 &dir.d_name[0], fid->l_fi, ump); 826 dir.d_fileno = udf_getid(&fid->icb); 827 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? 828 DT_DIR : DT_UNKNOWN; 829 error = udf_uiodir(&uiodir, uio, ds->this_off); 830 } 831 if (error) { 832 /* 833 * udf_uiodir() indicates there isn't space for 834 * another entry by returning -1 835 */ 836 if (error == -1) 837 error = 0; 838 break; 839 } 840 last_off = ds->this_off; 841 } 842 843 /* tell the calling layer whether we need to be called again */ 844 *ap->a_eofflag = uiodir.eofflag; 845 uio->uio_offset = last_off; 846 847 if (!error) 848 error = ds->error; 849 850 udf_closedir(ds); 851 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 852 up->u_ump->um_start = up->u_ump->um_realstart; 853 up->u_ump->um_len = up->u_ump->um_reallen; 854 } 855 856 return (error); 857 } 858 859 /* Are there any implementations out there that do soft-links? */ 860 int 861 udf_readlink(void *v) 862 { 863 return (EOPNOTSUPP); 864 } 865 866 int 867 udf_strategy(void *v) 868 { 869 struct vop_strategy_args *ap = v; 870 struct buf *bp; 871 struct vnode *vp; 872 struct unode *up; 873 int maxsize, s, error; 874 875 bp = ap->a_bp; 876 vp = bp->b_vp; 877 up = VTOU(vp); 878 879 /* cd9660 has this test reversed, but it seems more logical this way */ 880 if (bp->b_blkno != bp->b_lblkno) { 881 /* 882 * Files that are embedded in the fentry don't translate well 883 * to a block number. Reject. 884 */ 885 if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize, 886 &bp->b_lblkno, &maxsize)) { 887 clrbuf(bp); 888 bp->b_blkno = -1; 889 } 890 } else { 891 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 892 if (error) { 893 bp->b_error = error; 894 bp->b_flags |= B_ERROR; 895 s = splbio(); 896 biodone(bp); 897 splx(s); 898 return (error); 899 } 900 901 if ((long)bp->b_blkno == -1) 902 clrbuf(bp); 903 } 904 905 if ((long)bp->b_blkno == -1) { 906 s = splbio(); 907 biodone(bp); 908 splx(s); 909 } else { 910 bp->b_dev = vp->v_rdev; 911 VOP_STRATEGY(up->u_devvp, bp); 912 } 913 914 return (0); 915 } 916 917 int 918 udf_lock(void *v) 919 { 920 struct vop_lock_args *ap = v; 921 struct vnode *vp = ap->a_vp; 922 923 return rrw_enter(&VTOU(vp)->u_lock, ap->a_flags & LK_RWFLAGS); 924 } 925 926 int 927 udf_unlock(void *v) 928 { 929 struct vop_unlock_args *ap = v; 930 struct vnode *vp = ap->a_vp; 931 932 rrw_exit(&VTOU(vp)->u_lock); 933 return 0; 934 } 935 936 int 937 udf_islocked(void *v) 938 { 939 struct vop_islocked_args *ap = v; 940 941 return rrw_status(&VTOU(ap->a_vp)->u_lock); 942 } 943 944 int 945 udf_print(void *v) 946 { 947 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG) 948 struct vop_print_args *ap = v; 949 struct vnode *vp = ap->a_vp; 950 struct unode *up = VTOU(vp); 951 952 /* 953 * Complete the information given by vprint(). 954 */ 955 printf("tag VT_UDF, hash id %u\n", up->u_ino); 956 #ifdef DIAGNOSTIC 957 printf("\n"); 958 #endif 959 #endif 960 return (0); 961 } 962 963 int 964 udf_bmap(void *v) 965 { 966 struct vop_bmap_args *ap = v; 967 struct unode *up; 968 uint32_t max_size; 969 daddr_t lsector; 970 int error; 971 972 up = VTOU(ap->a_vp); 973 974 if (ap->a_vpp != NULL) 975 *ap->a_vpp = up->u_devvp; 976 if (ap->a_bnp == NULL) 977 return (0); 978 979 error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize, 980 &lsector, &max_size); 981 if (error) 982 return (error); 983 984 /* Translate logical to physical sector number */ 985 *ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT); 986 987 /* Punt on read-ahead for now */ 988 if (ap->a_runp) 989 *ap->a_runp = 0; 990 991 return (0); 992 } 993 994 /* 995 * The all powerful VOP_LOOKUP(). 996 */ 997 int 998 udf_lookup(void *v) 999 { 1000 struct vop_lookup_args *ap = v; 1001 struct vnode *dvp; 1002 struct vnode *tdp = NULL; 1003 struct vnode **vpp = ap->a_vpp; 1004 struct unode *up; 1005 struct umount *ump; 1006 struct fileid_desc *fid = NULL; 1007 struct udf_dirstream *ds; 1008 struct proc *p; 1009 u_long nameiop; 1010 u_long flags; 1011 char *nameptr; 1012 long namelen; 1013 udfino_t id = 0; 1014 int offset, error = 0; 1015 int numdirpasses, fsize; 1016 1017 extern struct nchstats nchstats; 1018 1019 dvp = ap->a_dvp; 1020 up = VTOU(dvp); 1021 ump = up->u_ump; 1022 nameiop = ap->a_cnp->cn_nameiop; 1023 flags = ap->a_cnp->cn_flags; 1024 nameptr = ap->a_cnp->cn_nameptr; 1025 namelen = ap->a_cnp->cn_namelen; 1026 fsize = letoh64(up->u_fentry->inf_len); 1027 p = ap->a_cnp->cn_proc; 1028 *vpp = NULL; 1029 1030 /* 1031 * Make sure the process can scan the requested directory. 1032 */ 1033 error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p); 1034 if (error) 1035 return (error); 1036 1037 /* 1038 * Check if the (directory, name) tuple has been already cached. 1039 */ 1040 error = cache_lookup(dvp, vpp, ap->a_cnp); 1041 if (error >= 0) 1042 return (error); 1043 else 1044 error = 0; 1045 1046 /* 1047 * If dvp is what's being looked up, then return it. 1048 */ 1049 if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') { 1050 vref(dvp); 1051 *vpp = dvp; 1052 return (0); 1053 } 1054 1055 /* 1056 * If this is a LOOKUP and we've already partially searched through 1057 * the directory, pick up where we left off and flag that the 1058 * directory may need to be searched twice. For a full description, 1059 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup() 1060 */ 1061 if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) { 1062 offset = 0; 1063 numdirpasses = 1; 1064 } else { 1065 offset = up->u_diroff; 1066 numdirpasses = 2; 1067 nchstats.ncs_2passes++; 1068 } 1069 1070 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1071 up->u_ump->um_start += up->u_ump->um_meta_start; 1072 up->u_ump->um_len = up->u_ump->um_meta_len; 1073 } 1074 lookloop: 1075 ds = udf_opendir(up, offset, fsize, ump); 1076 1077 while ((fid = udf_getfid(ds)) != NULL) { 1078 /* Check for a valid FID tag. */ 1079 if (udf_checktag(&fid->tag, TAGID_FID)) { 1080 printf("udf_lookup: Invalid tag\n"); 1081 error = EIO; 1082 break; 1083 } 1084 1085 /* Is this a deleted file? */ 1086 if (fid->file_char & UDF_FILE_CHAR_DEL) 1087 continue; 1088 1089 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 1090 if (flags & ISDOTDOT) { 1091 id = udf_getid(&fid->icb); 1092 break; 1093 } 1094 } else { 1095 if (!(udf_cmpname(&fid->data[fid->l_iu], 1096 nameptr, fid->l_fi, namelen, ump))) { 1097 id = udf_getid(&fid->icb); 1098 break; 1099 } 1100 } 1101 } 1102 1103 if (!error) 1104 error = ds->error; 1105 1106 if (error) { 1107 udf_closedir(ds); 1108 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1109 up->u_ump->um_start = up->u_ump->um_realstart; 1110 up->u_ump->um_len = up->u_ump->um_reallen; 1111 } 1112 return (error); 1113 } 1114 1115 /* Did we have a match? */ 1116 if (id) { 1117 error = udf_vget(ump->um_mountp, id, &tdp); 1118 if (!error) { 1119 /* 1120 * Remember where this entry was if it's the final 1121 * component. 1122 */ 1123 if ((flags & ISLASTCN) && nameiop == LOOKUP) 1124 up->u_diroff = ds->offset + ds->off; 1125 if (numdirpasses == 2) 1126 nchstats.ncs_pass2++; 1127 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 1128 ap->a_cnp->cn_flags |= PDIRUNLOCK; 1129 VOP_UNLOCK(dvp); 1130 } 1131 1132 *vpp = tdp; 1133 } 1134 } else { 1135 /* Name wasn't found on this pass. Do another pass? */ 1136 if (numdirpasses == 2) { 1137 numdirpasses--; 1138 offset = 0; 1139 udf_closedir(ds); 1140 goto lookloop; 1141 } 1142 1143 if ((flags & ISLASTCN) && 1144 (nameiop == CREATE || nameiop == RENAME)) { 1145 error = EROFS; 1146 } else { 1147 error = ENOENT; 1148 } 1149 } 1150 1151 /* 1152 * Cache the result of this lookup. 1153 */ 1154 if (flags & MAKEENTRY) 1155 cache_enter(dvp, *vpp, ap->a_cnp); 1156 1157 udf_closedir(ds); 1158 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1159 up->u_ump->um_start = up->u_ump->um_realstart; 1160 up->u_ump->um_len = up->u_ump->um_reallen; 1161 } 1162 1163 return (error); 1164 } 1165 1166 int 1167 udf_inactive(void *v) 1168 { 1169 struct vop_inactive_args *ap = v; 1170 struct vnode *vp = ap->a_vp; 1171 1172 /* 1173 * No need to sync anything, so just unlock the vnode and return. 1174 */ 1175 VOP_UNLOCK(vp); 1176 1177 return (0); 1178 } 1179 1180 int 1181 udf_reclaim(void *v) 1182 { 1183 struct vop_reclaim_args *ap = v; 1184 struct vnode *vp; 1185 struct unode *up; 1186 1187 vp = ap->a_vp; 1188 up = VTOU(vp); 1189 1190 if (up != NULL) { 1191 udf_hashrem(up); 1192 if (up->u_devvp) { 1193 vrele(up->u_devvp); 1194 up->u_devvp = 0; 1195 } 1196 1197 if (up->u_fentry != NULL) 1198 free(up->u_fentry, M_UDFFENTRY, 0); 1199 1200 pool_put(&unode_pool, up); 1201 vp->v_data = NULL; 1202 } 1203 1204 return (0); 1205 } 1206 1207 /* 1208 * Read the block and then set the data pointer to correspond with the 1209 * offset passed in. Only read in at most 'size' bytes, and then set 'size' 1210 * to the number of bytes pointed to. If 'size' is zero, try to read in a 1211 * whole extent. 1212 * 1213 * Note that *bp may be assigned error or not. 1214 * 1215 */ 1216 int 1217 udf_readatoffset(struct unode *up, int *size, off_t offset, 1218 struct buf **bp, uint8_t **data) 1219 { 1220 struct umount *ump; 1221 struct extfile_entry *xfentry = NULL; 1222 struct file_entry *fentry = NULL; 1223 struct buf *bp1; 1224 uint32_t max_size; 1225 daddr_t sector; 1226 int error; 1227 1228 ump = up->u_ump; 1229 1230 *bp = NULL; 1231 error = udf_bmap_internal(up, offset, §or, &max_size); 1232 if (error == UDF_INVALID_BMAP) { 1233 /* 1234 * This error means that the file *data* is stored in the 1235 * allocation descriptor field of the file entry. 1236 */ 1237 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) { 1238 xfentry = up->u_fentry; 1239 *data = &xfentry->data[letoh32(xfentry->l_ea)]; 1240 *size = letoh32(xfentry->l_ad); 1241 } else { 1242 fentry = (struct file_entry *)up->u_fentry; 1243 *data = &fentry->data[letoh32(fentry->l_ea)]; 1244 *size = letoh32(fentry->l_ad); 1245 } 1246 return (0); 1247 } else if (error != 0) { 1248 return (error); 1249 } 1250 1251 /* Adjust the size so that it is within range */ 1252 if (*size == 0 || *size > max_size) 1253 *size = max_size; 1254 *size = min(*size, MAXBSIZE); 1255 1256 if ((error = udf_readlblks(ump, sector, *size, bp))) { 1257 printf("warning: udf_readlblks returned error %d\n", error); 1258 /* note: *bp may be non-NULL */ 1259 return (error); 1260 } 1261 1262 bp1 = *bp; 1263 *data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize]; 1264 return (0); 1265 } 1266 1267 /* 1268 * Translate a file offset into a logical block and then into a physical 1269 * block. 1270 */ 1271 int 1272 udf_bmap_internal(struct unode *up, off_t offset, daddr_t *sector, 1273 uint32_t *max_size) 1274 { 1275 struct umount *ump; 1276 struct extfile_entry *xfentry; 1277 struct file_entry *fentry; 1278 void *icb; 1279 struct icb_tag *tag; 1280 uint32_t icblen = 0; 1281 daddr_t lsector; 1282 int ad_offset, ad_num = 0; 1283 int i, p_offset, l_ea, l_ad; 1284 1285 ump = up->u_ump; 1286 xfentry = up->u_fentry; 1287 fentry = (struct file_entry *)up->u_fentry; 1288 tag = &fentry->icbtag; 1289 if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { 1290 l_ea = letoh32(xfentry->l_ea); 1291 l_ad = letoh32(xfentry->l_ad); 1292 } else { 1293 l_ea = letoh32(fentry->l_ea); 1294 l_ad = letoh32(fentry->l_ad); 1295 } 1296 1297 switch (letoh16(tag->strat_type)) { 1298 case 4: 1299 break; 1300 1301 case 4096: 1302 printf("Cannot deal with strategy4096 yet!\n"); 1303 return (ENODEV); 1304 1305 default: 1306 printf("Unknown strategy type %d\n", tag->strat_type); 1307 return (ENODEV); 1308 } 1309 1310 switch (letoh16(tag->flags) & 0x7) { 1311 case 0: 1312 /* 1313 * The allocation descriptor field is filled with short_ad's. 1314 * If the offset is beyond the current extent, look for the 1315 * next extent. 1316 */ 1317 do { 1318 offset -= icblen; 1319 ad_offset = sizeof(struct short_ad) * ad_num; 1320 if (ad_offset > l_ad) { 1321 printf("SFile offset out of bounds (%d > %d)\n", 1322 ad_offset, l_ad); 1323 return (EINVAL); 1324 } 1325 1326 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1327 icb = GETICB(short_ad, xfentry, l_ea + ad_offset); 1328 else 1329 icb = GETICB(short_ad, fentry, l_ea + ad_offset); 1330 1331 icblen = GETICBLEN(short_ad, icb); 1332 ad_num++; 1333 } while(offset >= icblen); 1334 1335 lsector = (offset >> ump->um_bshift) + 1336 letoh32(((struct short_ad *)(icb))->lb_num); 1337 1338 *max_size = GETICBLEN(short_ad, icb); 1339 1340 break; 1341 case 1: 1342 /* 1343 * The allocation descriptor field is filled with long_ad's 1344 * If the offset is beyond the current extent, look for the 1345 * next extent. 1346 */ 1347 do { 1348 offset -= icblen; 1349 ad_offset = sizeof(struct long_ad) * ad_num; 1350 if (ad_offset > l_ad) { 1351 printf("LFile offset out of bounds (%d > %d)\n", 1352 ad_offset, l_ad); 1353 return (EINVAL); 1354 } 1355 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1356 icb = GETICB(long_ad, xfentry, l_ea + ad_offset); 1357 else 1358 icb = GETICB(long_ad, fentry, l_ea + ad_offset); 1359 icblen = GETICBLEN(long_ad, icb); 1360 ad_num++; 1361 } while(offset >= icblen); 1362 1363 lsector = (offset >> ump->um_bshift) + 1364 letoh32(((struct long_ad *)(icb))->loc.lb_num); 1365 1366 *max_size = GETICBLEN(long_ad, icb); 1367 1368 break; 1369 case 3: 1370 /* 1371 * This type means that the file *data* is stored in the 1372 * allocation descriptor field of the file entry. 1373 */ 1374 *max_size = 0; 1375 *sector = up->u_ino + ump->um_start; 1376 1377 return (UDF_INVALID_BMAP); 1378 case 2: 1379 /* DirectCD does not use extended_ad's */ 1380 default: 1381 printf("Unsupported allocation descriptor %d\n", 1382 tag->flags & 0x7); 1383 return (ENODEV); 1384 } 1385 1386 *sector = lsector + ump->um_start; 1387 1388 /* 1389 * Check the sparing table. Each entry represents the beginning of 1390 * a packet. 1391 */ 1392 if (ump->um_stbl != NULL) { 1393 for (i = 0; i< ump->um_stbl_len; i++) { 1394 p_offset = 1395 lsector - letoh32(ump->um_stbl->entries[i].org); 1396 if ((p_offset < ump->um_psecs) && (p_offset >= 0)) { 1397 *sector = 1398 letoh32(ump->um_stbl->entries[i].map) + 1399 p_offset; 1400 break; 1401 } 1402 } 1403 } 1404 1405 return (0); 1406 } 1407