1 /* $NetBSD: udf_vnops.c,v 1.101 2015/04/20 23:03:08 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2008 Reinoud Zandijk 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Generic parts are derived from software contributed to The NetBSD Foundation 28 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 29 * 2005 program. 30 * 31 */ 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.101 2015/04/20 23:03:08 riastradh Exp $"); 36 #endif /* not lint */ 37 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/namei.h> 42 #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ 43 #include <sys/kernel.h> 44 #include <sys/file.h> /* define FWRITE ... */ 45 #include <sys/stat.h> 46 #include <sys/buf.h> 47 #include <sys/proc.h> 48 #include <sys/mount.h> 49 #include <sys/vnode.h> 50 #include <sys/signalvar.h> 51 #include <sys/malloc.h> 52 #include <sys/dirent.h> 53 #include <sys/lockf.h> 54 #include <sys/kauth.h> 55 56 #include <miscfs/genfs/genfs.h> 57 #include <uvm/uvm_extern.h> 58 59 #include <fs/udf/ecma167-udf.h> 60 #include <fs/udf/udf_mount.h> 61 #include <sys/dirhash.h> 62 63 #include "udf.h" 64 #include "udf_subr.h" 65 #include "udf_bswap.h" 66 67 68 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data) 69 70 /* forward declarations */ 71 static int udf_do_readlink(struct udf_node *udf_node, uint64_t filesize, 72 uint8_t *targetbuf, int *length); 73 74 /* externs */ 75 extern int prtactive; 76 77 /* implementations of vnode functions; table follows at end */ 78 /* --------------------------------------------------------------------- */ 79 80 int 81 udf_inactive(void *v) 82 { 83 struct vop_inactive_args /* { 84 struct vnode *a_vp; 85 bool *a_recycle; 86 } */ *ap = v; 87 struct vnode *vp = ap->a_vp; 88 struct udf_node *udf_node = VTOI(vp); 89 int refcnt; 90 91 DPRINTF(NODE, ("udf_inactive called for udf_node %p\n", VTOI(vp))); 92 93 if (udf_node == NULL) { 94 DPRINTF(NODE, ("udf_inactive: inactive NULL UDF node\n")); 95 VOP_UNLOCK(vp); 96 return 0; 97 } 98 99 /* 100 * Optionally flush metadata to disc. 101 */ 102 if (udf_node->fe) { 103 refcnt = udf_rw16(udf_node->fe->link_cnt); 104 } else { 105 assert(udf_node->efe); 106 refcnt = udf_rw16(udf_node->efe->link_cnt); 107 } 108 109 if ((refcnt == 0) && (vp->v_vflag & VV_SYSTEM)) { 110 DPRINTF(VOLUMES, ("UDF_INACTIVE deleting VV_SYSTEM\n")); 111 /* system nodes are not writen out on inactive, so flush */ 112 udf_node->i_flags = 0; 113 } 114 115 *ap->a_recycle = false; 116 if ((refcnt == 0) && ((vp->v_vflag & VV_SYSTEM) == 0)) { 117 *ap->a_recycle = true; 118 VOP_UNLOCK(vp); 119 return 0; 120 } 121 122 /* write out its node */ 123 if (udf_node->i_flags & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) 124 udf_update(vp, NULL, NULL, NULL, 0); 125 VOP_UNLOCK(vp); 126 127 return 0; 128 } 129 130 /* --------------------------------------------------------------------- */ 131 132 int 133 udf_reclaim(void *v) 134 { 135 struct vop_reclaim_args /* { 136 struct vnode *a_vp; 137 } */ *ap = v; 138 struct vnode *vp = ap->a_vp; 139 struct udf_node *udf_node = VTOI(vp); 140 int refcnt; 141 142 DPRINTF(NODE, ("udf_reclaim called for node %p\n", udf_node)); 143 if (prtactive && vp->v_usecount > 1) 144 vprint("udf_reclaim(): pushing active", vp); 145 146 if (udf_node == NULL) { 147 DPRINTF(NODE, ("udf_reclaim(): null udfnode\n")); 148 return 0; 149 } 150 151 /* 152 * If the file has not been referenced anymore in a directory 153 * we ought to free up the resources on disc if applicable. 154 */ 155 if (udf_node->fe) { 156 refcnt = udf_rw16(udf_node->fe->link_cnt); 157 } else { 158 assert(udf_node->efe); 159 refcnt = udf_rw16(udf_node->efe->link_cnt); 160 } 161 162 if ((refcnt == 0) && ((vp->v_vflag & VV_SYSTEM) == 0)) { 163 /* remove this file's allocation */ 164 DPRINTF(NODE, ("udf_inactive deleting unlinked file\n")); 165 udf_delete_node(udf_node); 166 } 167 168 /* update note for closure */ 169 udf_update(vp, NULL, NULL, NULL, UPDATE_CLOSE); 170 171 /* async check to see if all node descriptors are written out */ 172 while ((volatile int) udf_node->outstanding_nodedscr > 0) { 173 vprint("udf_reclaim(): waiting for writeout\n", vp); 174 tsleep(&udf_node->outstanding_nodedscr, PRIBIO, "recl wait", hz/8); 175 } 176 177 vcache_remove(vp->v_mount, &udf_node->loc.loc, 178 sizeof(udf_node->loc.loc)); 179 180 /* dispose all node knowledge */ 181 udf_dispose_node(udf_node); 182 183 return 0; 184 } 185 186 /* --------------------------------------------------------------------- */ 187 188 int 189 udf_read(void *v) 190 { 191 struct vop_read_args /* { 192 struct vnode *a_vp; 193 struct uio *a_uio; 194 int a_ioflag; 195 kauth_cred_t a_cred; 196 } */ *ap = v; 197 struct vnode *vp = ap->a_vp; 198 struct uio *uio = ap->a_uio; 199 int ioflag = ap->a_ioflag; 200 int advice = IO_ADV_DECODE(ap->a_ioflag); 201 struct uvm_object *uobj; 202 struct udf_node *udf_node = VTOI(vp); 203 struct file_entry *fe; 204 struct extfile_entry *efe; 205 uint64_t file_size; 206 vsize_t len; 207 int error; 208 209 /* 210 * XXX reading from extended attributes not yet implemented. FreeBSD 211 * has it in mind to forward the IO_EXT read call to the 212 * VOP_READEXTATTR(). 213 */ 214 215 DPRINTF(READ, ("udf_read called\n")); 216 217 /* can this happen? some filingsystems have this check */ 218 if (uio->uio_offset < 0) 219 return EINVAL; 220 if (uio->uio_resid == 0) 221 return 0; 222 223 /* protect against rogue programs reading raw directories and links */ 224 if ((ioflag & IO_ALTSEMANTICS) == 0) { 225 if (vp->v_type == VDIR) 226 return EISDIR; 227 /* all but regular files just give EINVAL */ 228 if (vp->v_type != VREG) 229 return EINVAL; 230 } 231 232 assert(udf_node); 233 assert(udf_node->fe || udf_node->efe); 234 235 /* get file/directory filesize */ 236 if (udf_node->fe) { 237 fe = udf_node->fe; 238 file_size = udf_rw64(fe->inf_len); 239 } else { 240 assert(udf_node->efe); 241 efe = udf_node->efe; 242 file_size = udf_rw64(efe->inf_len); 243 } 244 245 /* read contents using buffercache */ 246 uobj = &vp->v_uobj; 247 error = 0; 248 while (uio->uio_resid > 0) { 249 /* reached end? */ 250 if (file_size <= uio->uio_offset) 251 break; 252 253 /* maximise length to file extremity */ 254 len = MIN(file_size - uio->uio_offset, uio->uio_resid); 255 if (len == 0) 256 break; 257 258 /* ubc, here we come, prepare to trap */ 259 error = ubc_uiomove(uobj, uio, len, advice, 260 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 261 if (error) 262 break; 263 } 264 265 /* note access time unless not requested */ 266 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) { 267 udf_node->i_flags |= IN_ACCESS; 268 if ((ioflag & IO_SYNC) == IO_SYNC) { 269 int uerror; 270 271 uerror = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT); 272 if (error == 0) 273 error = uerror; 274 } 275 } 276 277 return error; 278 } 279 280 /* --------------------------------------------------------------------- */ 281 282 int 283 udf_write(void *v) 284 { 285 struct vop_write_args /* { 286 struct vnode *a_vp; 287 struct uio *a_uio; 288 int a_ioflag; 289 kauth_cred_t a_cred; 290 } */ *ap = v; 291 struct vnode *vp = ap->a_vp; 292 struct uio *uio = ap->a_uio; 293 int ioflag = ap->a_ioflag; 294 kauth_cred_t cred = ap->a_cred; 295 int advice = IO_ADV_DECODE(ap->a_ioflag); 296 struct uvm_object *uobj; 297 struct udf_node *udf_node = VTOI(vp); 298 struct file_entry *fe; 299 struct extfile_entry *efe; 300 uint64_t file_size, old_size, old_offset; 301 vsize_t len; 302 int aflag = ioflag & IO_SYNC ? B_SYNC : 0; 303 int error; 304 int resid, extended; 305 306 /* 307 * XXX writing to extended attributes not yet implemented. FreeBSD has 308 * it in mind to forward the IO_EXT read call to the 309 * VOP_READEXTATTR(). 310 */ 311 312 DPRINTF(WRITE, ("udf_write called\n")); 313 314 /* can this happen? some filingsystems have this check */ 315 if (uio->uio_offset < 0) 316 return EINVAL; 317 if (uio->uio_resid == 0) 318 return 0; 319 320 /* protect against rogue programs writing raw directories or links */ 321 if ((ioflag & IO_ALTSEMANTICS) == 0) { 322 if (vp->v_type == VDIR) 323 return EISDIR; 324 /* all but regular files just give EINVAL for now */ 325 if (vp->v_type != VREG) 326 return EINVAL; 327 } 328 329 assert(udf_node); 330 assert(udf_node->fe || udf_node->efe); 331 332 /* get file/directory filesize */ 333 if (udf_node->fe) { 334 fe = udf_node->fe; 335 file_size = udf_rw64(fe->inf_len); 336 } else { 337 assert(udf_node->efe); 338 efe = udf_node->efe; 339 file_size = udf_rw64(efe->inf_len); 340 } 341 old_size = file_size; 342 343 /* if explicitly asked to append, uio_offset can be wrong? */ 344 if (ioflag & IO_APPEND) 345 uio->uio_offset = file_size; 346 347 extended = (uio->uio_offset + uio->uio_resid > file_size); 348 if (extended) { 349 DPRINTF(WRITE, ("extending file from %"PRIu64" to %"PRIu64"\n", 350 file_size, uio->uio_offset + uio->uio_resid)); 351 error = udf_grow_node(udf_node, uio->uio_offset + uio->uio_resid); 352 if (error) 353 return error; 354 file_size = uio->uio_offset + uio->uio_resid; 355 } 356 357 /* write contents using buffercache */ 358 uobj = &vp->v_uobj; 359 resid = uio->uio_resid; 360 error = 0; 361 362 uvm_vnp_setwritesize(vp, file_size); 363 old_offset = uio->uio_offset; 364 while (uio->uio_resid > 0) { 365 /* maximise length to file extremity */ 366 len = MIN(file_size - uio->uio_offset, uio->uio_resid); 367 if (len == 0) 368 break; 369 370 genfs_node_wrlock(vp); 371 error = GOP_ALLOC(vp, uio->uio_offset, len, aflag, cred); 372 genfs_node_unlock(vp); 373 if (error) 374 break; 375 376 /* ubc, here we come, prepare to trap */ 377 error = ubc_uiomove(uobj, uio, len, advice, 378 UBC_WRITE | UBC_UNMAP_FLAG(vp)); 379 if (error) 380 break; 381 382 /* 383 * flush what we just wrote if necessary. 384 * XXXUBC simplistic async flushing. 385 * 386 * Directories are excluded since its file data that we want 387 * to purge. 388 */ 389 if ((vp->v_type != VDIR) && 390 (old_offset >> 16 != uio->uio_offset >> 16)) { 391 mutex_enter(vp->v_interlock); 392 error = VOP_PUTPAGES(vp, (old_offset >> 16) << 16, 393 (uio->uio_offset >> 16) << 16, 394 PGO_CLEANIT | PGO_LAZY); 395 old_offset = uio->uio_offset; 396 } 397 } 398 uvm_vnp_setsize(vp, file_size); 399 400 /* mark node changed and request update */ 401 udf_node->i_flags |= IN_CHANGE | IN_UPDATE; 402 if (vp->v_mount->mnt_flag & MNT_RELATIME) 403 udf_node->i_flags |= IN_ACCESS; 404 405 /* 406 * XXX TODO FFS has code here to reset setuid & setgid when we're not 407 * the superuser as a precaution against tampering. 408 */ 409 410 /* if we wrote a thing, note write action on vnode */ 411 if (resid > uio->uio_resid) 412 VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); 413 414 if (error) { 415 /* bring back file size to its former size */ 416 /* take notice of its errors? */ 417 (void) udf_chsize(vp, (u_quad_t) old_size, cred); 418 419 /* roll back uio */ 420 uio->uio_offset -= resid - uio->uio_resid; 421 uio->uio_resid = resid; 422 } else { 423 /* if we write and we're synchronous, update node */ 424 if ((resid > uio->uio_resid) && ((ioflag & IO_SYNC) == IO_SYNC)) 425 error = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT); 426 } 427 428 return error; 429 } 430 431 432 /* --------------------------------------------------------------------- */ 433 434 /* 435 * `Special' bmap functionality that translates all incomming requests to 436 * translate to vop_strategy() calls with the same blocknumbers effectively 437 * not translating at all. 438 */ 439 440 int 441 udf_trivial_bmap(void *v) 442 { 443 struct vop_bmap_args /* { 444 struct vnode *a_vp; 445 daddr_t a_bn; 446 struct vnode **a_vpp; 447 daddr_t *a_bnp; 448 int *a_runp; 449 } */ *ap = v; 450 struct vnode *vp = ap->a_vp; /* our node */ 451 struct vnode **vpp = ap->a_vpp; /* return node */ 452 daddr_t *bnp = ap->a_bnp; /* translated */ 453 daddr_t bn = ap->a_bn; /* origional */ 454 int *runp = ap->a_runp; 455 struct udf_node *udf_node = VTOI(vp); 456 uint32_t lb_size; 457 458 /* get logical block size */ 459 lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 460 461 /* could return `-1' to indicate holes/zeros */ 462 /* translate 1:1 */ 463 *bnp = bn; 464 465 /* set the vnode to read the data from with strategy on itself */ 466 if (vpp) 467 *vpp = vp; 468 469 /* set runlength of maximum block size */ 470 if (runp) 471 *runp = MAXPHYS / lb_size; /* or with -1 ? */ 472 473 /* return success */ 474 return 0; 475 } 476 477 /* --------------------------------------------------------------------- */ 478 479 int 480 udf_vfsstrategy(void *v) 481 { 482 struct vop_strategy_args /* { 483 struct vnode *a_vp; 484 struct buf *a_bp; 485 } */ *ap = v; 486 struct vnode *vp = ap->a_vp; 487 struct buf *bp = ap->a_bp; 488 struct udf_node *udf_node = VTOI(vp); 489 uint32_t lb_size, sectors; 490 491 DPRINTF(STRATEGY, ("udf_strategy called\n")); 492 493 /* check if we ought to be here */ 494 if (vp->v_type == VBLK || vp->v_type == VCHR) 495 panic("udf_strategy: spec"); 496 497 /* only filebuffers ought to be read/write by this, no descriptors */ 498 assert(bp->b_blkno >= 0); 499 500 /* get sector size */ 501 lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 502 503 /* calculate length to fetch/store in sectors */ 504 sectors = bp->b_bcount / lb_size; 505 assert(bp->b_bcount > 0); 506 507 /* NEVER assume later that this buffer is already translated */ 508 /* bp->b_lblkno = bp->b_blkno; */ 509 510 /* check assertions: we OUGHT to always get multiples of this */ 511 assert(sectors * lb_size == bp->b_bcount); 512 __USE(sectors); 513 514 /* issue buffer */ 515 if (bp->b_flags & B_READ) { 516 DPRINTF(STRATEGY, ("\tread vp %p buf %p (blk no %"PRIu64")" 517 ", for %d sectors\n", 518 vp, bp, bp->b_blkno, sectors)); 519 520 /* read buffer from the udf_node, translate vtop on the way*/ 521 udf_read_filebuf(udf_node, bp); 522 } else { 523 DPRINTF(STRATEGY, ("\twrite vp %p buf %p (blk no %"PRIu64")" 524 ", for %d sectors\n", 525 vp, bp, bp->b_blkno, sectors)); 526 527 /* write buffer to the udf_node, translate vtop on the way*/ 528 udf_write_filebuf(udf_node, bp); 529 } 530 531 return bp->b_error; 532 } 533 534 /* --------------------------------------------------------------------- */ 535 536 int 537 udf_readdir(void *v) 538 { 539 struct vop_readdir_args /* { 540 struct vnode *a_vp; 541 struct uio *a_uio; 542 kauth_cred_t a_cred; 543 int *a_eofflag; 544 off_t **a_cookies; 545 int *a_ncookies; 546 } */ *ap = v; 547 struct uio *uio = ap->a_uio; 548 struct vnode *vp = ap->a_vp; 549 struct udf_node *udf_node = VTOI(vp); 550 struct file_entry *fe; 551 struct extfile_entry *efe; 552 struct fileid_desc *fid; 553 struct dirent *dirent; 554 uint64_t file_size, diroffset, transoffset; 555 uint32_t lb_size; 556 int error; 557 558 DPRINTF(READDIR, ("udf_readdir called\n")); 559 560 /* This operation only makes sense on directory nodes. */ 561 if (vp->v_type != VDIR) 562 return ENOTDIR; 563 564 /* get directory filesize */ 565 if (udf_node->fe) { 566 fe = udf_node->fe; 567 file_size = udf_rw64(fe->inf_len); 568 } else { 569 assert(udf_node->efe); 570 efe = udf_node->efe; 571 file_size = udf_rw64(efe->inf_len); 572 } 573 574 dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK | M_ZERO); 575 576 /* 577 * Add `.' pseudo entry if at offset zero since its not in the fid 578 * stream 579 */ 580 if (uio->uio_offset == 0) { 581 DPRINTF(READDIR, ("\t'.' inserted\n")); 582 strcpy(dirent->d_name, "."); 583 dirent->d_fileno = udf_get_node_id(&udf_node->loc); 584 dirent->d_type = DT_DIR; 585 dirent->d_namlen = strlen(dirent->d_name); 586 dirent->d_reclen = _DIRENT_SIZE(dirent); 587 uiomove(dirent, _DIRENT_SIZE(dirent), uio); 588 589 /* mark with magic value that we have done the dummy */ 590 uio->uio_offset = UDF_DIRCOOKIE_DOT; 591 } 592 593 /* we are called just as long as we keep on pushing data in */ 594 error = 0; 595 if (uio->uio_offset < file_size) { 596 /* allocate temporary space for fid */ 597 lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 598 fid = malloc(lb_size, M_UDFTEMP, M_WAITOK); 599 600 if (uio->uio_offset == UDF_DIRCOOKIE_DOT) 601 uio->uio_offset = 0; 602 603 diroffset = uio->uio_offset; 604 transoffset = diroffset; 605 while (diroffset < file_size) { 606 DPRINTF(READDIR, ("\tread in fid stream\n")); 607 /* transfer a new fid/dirent */ 608 error = udf_read_fid_stream(vp, &diroffset, fid, dirent); 609 DPRINTFIF(READDIR, error, ("read error in read fid " 610 "stream : %d\n", error)); 611 if (error) 612 break; 613 614 /* 615 * If there isn't enough space in the uio to return a 616 * whole dirent, break off read 617 */ 618 if (uio->uio_resid < _DIRENT_SIZE(dirent)) 619 break; 620 621 /* remember the last entry we transfered */ 622 transoffset = diroffset; 623 624 /* skip deleted entries */ 625 if (fid->file_char & UDF_FILE_CHAR_DEL) 626 continue; 627 628 /* skip not visible files */ 629 if (fid->file_char & UDF_FILE_CHAR_VIS) 630 continue; 631 632 /* copy dirent to the caller */ 633 DPRINTF(READDIR, ("\tread dirent `%s', type %d\n", 634 dirent->d_name, dirent->d_type)); 635 uiomove(dirent, _DIRENT_SIZE(dirent), uio); 636 } 637 638 /* pass on last transfered offset */ 639 uio->uio_offset = transoffset; 640 free(fid, M_UDFTEMP); 641 } 642 643 if (ap->a_eofflag) 644 *ap->a_eofflag = (uio->uio_offset >= file_size); 645 646 #ifdef DEBUG 647 if (udf_verbose & UDF_DEBUG_READDIR) { 648 printf("returning offset %d\n", (uint32_t) uio->uio_offset); 649 if (ap->a_eofflag) 650 printf("returning EOF ? %d\n", *ap->a_eofflag); 651 if (error) 652 printf("readdir returning error %d\n", error); 653 } 654 #endif 655 656 free(dirent, M_UDFTEMP); 657 return error; 658 } 659 660 /* --------------------------------------------------------------------- */ 661 662 int 663 udf_lookup(void *v) 664 { 665 struct vop_lookup_v2_args /* { 666 struct vnode *a_dvp; 667 struct vnode **a_vpp; 668 struct componentname *a_cnp; 669 } */ *ap = v; 670 struct vnode *dvp = ap->a_dvp; 671 struct vnode **vpp = ap->a_vpp; 672 struct componentname *cnp = ap->a_cnp; 673 struct udf_node *dir_node, *res_node; 674 struct udf_mount *ump; 675 struct long_ad icb_loc; 676 mode_t mode; 677 uid_t d_uid; 678 gid_t d_gid; 679 const char *name; 680 int namelen, nameiop, islastcn, mounted_ro; 681 int error, found; 682 683 dir_node = VTOI(dvp); 684 ump = dir_node->ump; 685 *vpp = NULL; 686 687 DPRINTF(LOOKUP, ("udf_lookup called, lookup `%s`\n", 688 cnp->cn_nameptr)); 689 690 /* simplify/clarification flags */ 691 nameiop = cnp->cn_nameiop; 692 islastcn = cnp->cn_flags & ISLASTCN; 693 mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY; 694 695 /* check exec/dirread permissions first */ 696 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 697 if (error) 698 return error; 699 700 DPRINTF(LOOKUP, ("\taccess ok\n")); 701 702 /* 703 * If requesting a modify on the last path element on a read-only 704 * filingsystem, reject lookup; XXX why is this repeated in every FS ? 705 */ 706 if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) 707 return EROFS; 708 709 DPRINTF(LOOKUP, ("\tlooking up cnp->cn_nameptr '%s'\n", 710 cnp->cn_nameptr)); 711 /* look in the namecache */ 712 if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 713 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) { 714 return *vpp == NULLVP ? ENOENT : 0; 715 } 716 717 DPRINTF(LOOKUP, ("\tNOT found in cache\n")); 718 719 /* 720 * Obviously, the file is not (anymore) in the namecache, we have to 721 * search for it. There are three basic cases: '.', '..' and others. 722 * 723 * Following the guidelines of VOP_LOOKUP manpage and tmpfs. 724 */ 725 error = 0; 726 if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) { 727 DPRINTF(LOOKUP, ("\tlookup '.'\n")); 728 /* special case 1 '.' */ 729 if (islastcn && cnp->cn_nameiop == RENAME) { 730 error = EISDIR; 731 goto out; 732 } 733 vref(dvp); 734 *vpp = dvp; 735 /* done */ 736 goto done; 737 } else if (cnp->cn_flags & ISDOTDOT) { 738 /* special case 2 '..' */ 739 DPRINTF(LOOKUP, ("\tlookup '..'\n")); 740 741 if (islastcn && cnp->cn_nameiop == RENAME) { 742 error = EINVAL; 743 goto out; 744 } 745 746 /* get our node */ 747 name = ".."; 748 namelen = 2; 749 error = udf_lookup_name_in_dir(dvp, name, namelen, 750 &icb_loc, &found); 751 if (error) 752 goto out; 753 if (!found) 754 error = ENOENT; 755 756 /* first unlock parent */ 757 VOP_UNLOCK(dvp); 758 759 if (error == 0) { 760 DPRINTF(LOOKUP, ("\tfound '..'\n")); 761 /* try to create/reuse the node */ 762 error = udf_get_node(ump, &icb_loc, &res_node); 763 764 if (!error) { 765 DPRINTF(LOOKUP, 766 ("\tnode retrieved/created OK\n")); 767 *vpp = res_node->vnode; 768 } 769 } 770 771 /* try to relock parent */ 772 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 773 goto out; 774 } 775 776 /* all other files */ 777 DPRINTF(LOOKUP, ("\tlookup file/dir in directory\n")); 778 779 /* lookup filename in the directory; location icb_loc */ 780 name = cnp->cn_nameptr; 781 namelen = cnp->cn_namelen; 782 error = udf_lookup_name_in_dir(dvp, name, namelen, 783 &icb_loc, &found); 784 if (error) 785 goto out; 786 if (!found) { 787 DPRINTF(LOOKUP, ("\tNOT found\n")); 788 /* 789 * The entry was not found in the directory. This is 790 * valid if we are creating or renaming an entry and 791 * are working on the last component of the path name. 792 */ 793 if (islastcn && (cnp->cn_nameiop == CREATE || 794 cnp->cn_nameiop == RENAME)) { 795 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); 796 if (error) { 797 goto out; 798 } 799 error = EJUSTRETURN; 800 } else { 801 error = ENOENT; 802 } 803 /* done */ 804 goto done; 805 } 806 807 /* 808 * XXX NOTE tmpfs has a test here that tests that intermediate 809 * components i.e. not the last one ought to be either a directory or 810 * a link. It seems to function well without this code. 811 */ 812 813 /* try to create/reuse the node */ 814 error = udf_get_node(ump, &icb_loc, &res_node); 815 if (error) 816 goto out; 817 818 /* check permissions */ 819 if (islastcn && (cnp->cn_nameiop == DELETE || 820 cnp->cn_nameiop == RENAME) ) { 821 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); 822 if (error) { 823 vput(res_node->vnode); 824 goto out; 825 } 826 827 /* 828 * Check if the directory has its sticky bit set. If so, ask 829 * for clearance since only the owner of a file or directory 830 * can remove/rename from taht directory. 831 */ 832 mode = udf_getaccessmode(dir_node); 833 if ((mode & S_ISTXT) != 0) { 834 udf_getownership(dir_node, &d_uid, &d_gid); 835 error = kauth_authorize_vnode(cnp->cn_cred, 836 KAUTH_VNODE_DELETE, res_node->vnode, 837 dir_node->vnode, genfs_can_sticky(cnp->cn_cred, 838 d_uid, d_uid)); 839 if (error) { 840 error = EPERM; 841 vput(res_node->vnode); 842 goto out; 843 } 844 } 845 } 846 847 *vpp = res_node->vnode; 848 849 done: 850 /* 851 * Store result in the cache if requested. If we are creating a file, 852 * the file might not be found and thus putting it into the namecache 853 * might be seen as negative caching. 854 */ 855 if (nameiop != CREATE) 856 cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, 857 cnp->cn_flags); 858 859 out: 860 if (error == 0 && *vpp != dvp) 861 VOP_UNLOCK(*vpp); 862 DPRINTFIF(LOOKUP, error, ("udf_lookup returing error %d\n", error)); 863 864 return error; 865 } 866 867 /* --------------------------------------------------------------------- */ 868 869 int 870 udf_getattr(void *v) 871 { 872 struct vop_getattr_args /* { 873 struct vnode *a_vp; 874 struct vattr *a_vap; 875 kauth_cred_t a_cred; 876 struct lwp *a_l; 877 } */ *ap = v; 878 struct vnode *vp = ap->a_vp; 879 struct udf_node *udf_node = VTOI(vp); 880 struct udf_mount *ump = udf_node->ump; 881 struct file_entry *fe = udf_node->fe; 882 struct extfile_entry *efe = udf_node->efe; 883 struct filetimes_extattr_entry *ft_extattr; 884 struct device_extattr_entry *devattr; 885 struct vattr *vap = ap->a_vap; 886 struct timestamp *atime, *mtime, *attrtime, *creatime; 887 uint64_t filesize, blkssize; 888 uint32_t nlink; 889 uint32_t offset, a_l; 890 uint8_t *filedata, *targetbuf; 891 uid_t uid; 892 gid_t gid; 893 int length, error; 894 895 DPRINTF(CALL, ("udf_getattr called\n")); 896 897 /* update times before we returning values */ 898 udf_itimes(udf_node, NULL, NULL, NULL); 899 900 /* get descriptor information */ 901 if (fe) { 902 nlink = udf_rw16(fe->link_cnt); 903 uid = (uid_t)udf_rw32(fe->uid); 904 gid = (gid_t)udf_rw32(fe->gid); 905 filesize = udf_rw64(fe->inf_len); 906 blkssize = udf_rw64(fe->logblks_rec); 907 atime = &fe->atime; 908 mtime = &fe->mtime; 909 attrtime = &fe->attrtime; 910 filedata = fe->data; 911 912 /* initial guess */ 913 creatime = mtime; 914 915 /* check our extended attribute if present */ 916 error = udf_extattr_search_intern(udf_node, 917 UDF_FILETIMES_ATTR_NO, "", &offset, &a_l); 918 if (!error) { 919 ft_extattr = (struct filetimes_extattr_entry *) 920 (filedata + offset); 921 if (ft_extattr->existence & UDF_FILETIMES_FILE_CREATION) 922 creatime = &ft_extattr->times[0]; 923 } 924 } else { 925 assert(udf_node->efe); 926 nlink = udf_rw16(efe->link_cnt); 927 uid = (uid_t)udf_rw32(efe->uid); 928 gid = (gid_t)udf_rw32(efe->gid); 929 filesize = udf_rw64(efe->inf_len); /* XXX or obj_size? */ 930 blkssize = udf_rw64(efe->logblks_rec); 931 atime = &efe->atime; 932 mtime = &efe->mtime; 933 attrtime = &efe->attrtime; 934 creatime = &efe->ctime; 935 filedata = efe->data; 936 } 937 938 /* do the uid/gid translation game */ 939 if (uid == (uid_t) -1) 940 uid = ump->mount_args.anon_uid; 941 if (gid == (gid_t) -1) 942 gid = ump->mount_args.anon_gid; 943 944 /* fill in struct vattr with values from the node */ 945 vattr_null(vap); 946 vap->va_type = vp->v_type; 947 vap->va_mode = udf_getaccessmode(udf_node); 948 vap->va_nlink = nlink; 949 vap->va_uid = uid; 950 vap->va_gid = gid; 951 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 952 vap->va_fileid = udf_get_node_id(&udf_node->loc); /* inode hash XXX */ 953 vap->va_size = filesize; 954 vap->va_blocksize = udf_node->ump->discinfo.sector_size; /* wise? */ 955 956 /* 957 * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add 958 * 1 to the link count if its a directory we're requested attributes 959 * of. 960 */ 961 if (vap->va_type == VDIR) 962 vap->va_nlink++; 963 964 /* 965 * BUG-ALERT: Posix requires the va_size to be pathlength for symbolic 966 * links. 967 */ 968 if (vap->va_type == VLNK) { 969 /* claim temporary buffers for translation */ 970 targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); 971 error = udf_do_readlink(udf_node, filesize, targetbuf, &length); 972 if (!error) { 973 vap->va_size = length; 974 KASSERT(length == strlen(targetbuf)); 975 } 976 free(targetbuf, M_UDFTEMP); 977 /* XXX return error? */ 978 } 979 980 /* access times */ 981 udf_timestamp_to_timespec(ump, atime, &vap->va_atime); 982 udf_timestamp_to_timespec(ump, mtime, &vap->va_mtime); 983 udf_timestamp_to_timespec(ump, attrtime, &vap->va_ctime); 984 udf_timestamp_to_timespec(ump, creatime, &vap->va_birthtime); 985 986 vap->va_gen = 1; /* no multiple generations yes (!?) */ 987 vap->va_flags = 0; /* no flags */ 988 vap->va_bytes = blkssize * udf_node->ump->discinfo.sector_size; 989 vap->va_filerev = 1; /* TODO file revision numbers? */ 990 vap->va_vaflags = 0; 991 /* TODO get vaflags from the extended attributes? */ 992 993 if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) { 994 error = udf_extattr_search_intern(udf_node, 995 UDF_DEVICESPEC_ATTR_NO, "", 996 &offset, &a_l); 997 /* if error, deny access */ 998 if (error || (filedata == NULL)) { 999 vap->va_mode = 0; /* or v_type = VNON? */ 1000 } else { 1001 devattr = (struct device_extattr_entry *) 1002 filedata + offset; 1003 vap->va_rdev = makedev( 1004 udf_rw32(devattr->major), 1005 udf_rw32(devattr->minor) 1006 ); 1007 /* TODO we could check the implementator */ 1008 } 1009 } 1010 1011 return 0; 1012 } 1013 1014 /* --------------------------------------------------------------------- */ 1015 1016 static int 1017 udf_chown(struct vnode *vp, uid_t new_uid, gid_t new_gid, 1018 kauth_cred_t cred) 1019 { 1020 struct udf_node *udf_node = VTOI(vp); 1021 uid_t uid; 1022 gid_t gid; 1023 int error; 1024 1025 #ifdef notyet 1026 /* TODO get vaflags from the extended attributes? */ 1027 /* Immutable or append-only files cannot be modified, either. */ 1028 if (udf_node->flags & (IMMUTABLE | APPEND)) 1029 return EPERM; 1030 #endif 1031 1032 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1033 return EROFS; 1034 1035 /* retrieve old values */ 1036 udf_getownership(udf_node, &uid, &gid); 1037 1038 /* only one could be specified */ 1039 if (new_uid == VNOVAL) 1040 new_uid = uid; 1041 if (new_gid == VNOVAL) 1042 new_gid = gid; 1043 1044 /* check if we can fit it in an 32 bits */ 1045 if ((uid_t) ((uint32_t) new_uid) != new_uid) 1046 return EINVAL; 1047 if ((gid_t) ((uint32_t) new_gid) != new_gid) 1048 return EINVAL; 1049 1050 /* check permissions */ 1051 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, 1052 vp, NULL, genfs_can_chown(cred, uid, gid, new_uid, new_gid)); 1053 if (error) 1054 return (error); 1055 1056 /* change the ownership */ 1057 udf_setownership(udf_node, new_uid, new_gid); 1058 1059 /* mark node changed */ 1060 udf_node->i_flags |= IN_CHANGE; 1061 1062 return 0; 1063 } 1064 1065 1066 static int 1067 udf_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred) 1068 { 1069 struct udf_node *udf_node = VTOI(vp); 1070 uid_t uid; 1071 gid_t gid; 1072 int error; 1073 1074 #ifdef notyet 1075 /* TODO get vaflags from the extended attributes? */ 1076 /* Immutable or append-only files cannot be modified, either. */ 1077 if (udf_node->flags & (IMMUTABLE | APPEND)) 1078 return EPERM; 1079 #endif 1080 1081 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1082 return EROFS; 1083 1084 /* retrieve uid/gid values */ 1085 udf_getownership(udf_node, &uid, &gid); 1086 1087 /* check permissions */ 1088 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 1089 NULL, genfs_can_chmod(vp->v_type, cred, uid, gid, mode)); 1090 if (error) 1091 return (error); 1092 1093 /* change mode */ 1094 udf_setaccessmode(udf_node, mode); 1095 1096 /* mark node changed */ 1097 udf_node->i_flags |= IN_CHANGE; 1098 1099 return 0; 1100 } 1101 1102 1103 /* exported */ 1104 int 1105 udf_chsize(struct vnode *vp, u_quad_t newsize, kauth_cred_t cred) 1106 { 1107 struct udf_node *udf_node = VTOI(vp); 1108 int error, extended; 1109 1110 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1111 return EROFS; 1112 1113 /* Decide whether this is a valid operation based on the file type. */ 1114 switch (vp->v_type) { 1115 case VDIR: 1116 return EISDIR; 1117 case VREG: 1118 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1119 return EROFS; 1120 break; 1121 case VBLK: 1122 /* FALLTHROUGH */ 1123 case VCHR: 1124 /* FALLTHROUGH */ 1125 case VFIFO: 1126 /* Allow modifications of special files even if in the file 1127 * system is mounted read-only (we are not modifying the 1128 * files themselves, but the objects they represent). */ 1129 return 0; 1130 default: 1131 /* Anything else is unsupported. */ 1132 return EOPNOTSUPP; 1133 } 1134 1135 #if notyet 1136 /* TODO get vaflags from the extended attributes? */ 1137 /* Immutable or append-only files cannot be modified, either. */ 1138 if (node->flags & (IMMUTABLE | APPEND)) 1139 return EPERM; 1140 #endif 1141 1142 /* resize file to the requested size */ 1143 error = udf_resize_node(udf_node, newsize, &extended); 1144 1145 if (error == 0) { 1146 /* mark change */ 1147 udf_node->i_flags |= IN_CHANGE | IN_MODIFY; 1148 if (vp->v_mount->mnt_flag & MNT_RELATIME) 1149 udf_node->i_flags |= IN_ACCESS; 1150 VN_KNOTE(vp, NOTE_ATTRIB | (extended ? NOTE_EXTEND : 0)); 1151 udf_update(vp, NULL, NULL, NULL, 0); 1152 } 1153 1154 return error; 1155 } 1156 1157 1158 static int 1159 udf_chflags(struct vnode *vp, mode_t mode, kauth_cred_t cred) 1160 { 1161 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1162 return EROFS; 1163 1164 /* 1165 * XXX we can't do this yet, as its not described in the standard yet 1166 */ 1167 1168 return EOPNOTSUPP; 1169 } 1170 1171 1172 static int 1173 udf_chtimes(struct vnode *vp, 1174 struct timespec *atime, struct timespec *mtime, 1175 struct timespec *birthtime, int setattrflags, 1176 kauth_cred_t cred) 1177 { 1178 struct udf_node *udf_node = VTOI(vp); 1179 uid_t uid; 1180 gid_t gid; 1181 int error; 1182 1183 #ifdef notyet 1184 /* TODO get vaflags from the extended attributes? */ 1185 /* Immutable or append-only files cannot be modified, either. */ 1186 if (udf_node->flags & (IMMUTABLE | APPEND)) 1187 return EPERM; 1188 #endif 1189 1190 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1191 return EROFS; 1192 1193 /* retrieve uid/gid values */ 1194 udf_getownership(udf_node, &uid, &gid); 1195 1196 /* check permissions */ 1197 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 1198 NULL, genfs_can_chtimes(vp, setattrflags, uid, cred)); 1199 if (error) 1200 return (error); 1201 1202 /* update node flags depending on what times are passed */ 1203 if (atime->tv_sec != VNOVAL) 1204 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 1205 udf_node->i_flags |= IN_ACCESS; 1206 if ((mtime->tv_sec != VNOVAL) || (birthtime->tv_sec != VNOVAL)) { 1207 udf_node->i_flags |= IN_CHANGE | IN_UPDATE; 1208 if (vp->v_mount->mnt_flag & MNT_RELATIME) 1209 udf_node->i_flags |= IN_ACCESS; 1210 } 1211 1212 return udf_update(vp, atime, mtime, birthtime, 0); 1213 } 1214 1215 1216 int 1217 udf_setattr(void *v) 1218 { 1219 struct vop_setattr_args /* { 1220 struct vnode *a_vp; 1221 struct vattr *a_vap; 1222 kauth_cred_t a_cred; 1223 struct lwp *a_l; 1224 } */ *ap = v; 1225 struct vnode *vp = ap->a_vp; 1226 /* struct udf_node *udf_node = VTOI(vp); */ 1227 /* struct udf_mount *ump = udf_node->ump; */ 1228 kauth_cred_t cred = ap->a_cred; 1229 struct vattr *vap = ap->a_vap; 1230 int error; 1231 1232 DPRINTF(CALL, ("udf_setattr called\n")); 1233 1234 /* Abort if any unsettable attribute is given. */ 1235 error = 0; 1236 if (vap->va_type != VNON || 1237 vap->va_nlink != VNOVAL || 1238 vap->va_fsid != VNOVAL || 1239 vap->va_fileid != VNOVAL || 1240 vap->va_blocksize != VNOVAL || 1241 #ifdef notyet 1242 /* checks are debated */ 1243 vap->va_ctime.tv_sec != VNOVAL || 1244 vap->va_ctime.tv_nsec != VNOVAL || 1245 vap->va_birthtime.tv_sec != VNOVAL || 1246 vap->va_birthtime.tv_nsec != VNOVAL || 1247 #endif 1248 vap->va_gen != VNOVAL || 1249 vap->va_rdev != VNOVAL || 1250 vap->va_bytes != VNOVAL) 1251 error = EINVAL; 1252 1253 DPRINTF(ATTR, ("setattr changing:\n")); 1254 if (error == 0 && (vap->va_flags != VNOVAL)) { 1255 DPRINTF(ATTR, ("\tchflags\n")); 1256 error = udf_chflags(vp, vap->va_flags, cred); 1257 } 1258 1259 if (error == 0 && (vap->va_size != VNOVAL)) { 1260 DPRINTF(ATTR, ("\tchsize\n")); 1261 error = udf_chsize(vp, vap->va_size, cred); 1262 } 1263 1264 if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) { 1265 DPRINTF(ATTR, ("\tchown\n")); 1266 error = udf_chown(vp, vap->va_uid, vap->va_gid, cred); 1267 } 1268 1269 if (error == 0 && (vap->va_mode != VNOVAL)) { 1270 DPRINTF(ATTR, ("\tchmod\n")); 1271 error = udf_chmod(vp, vap->va_mode, cred); 1272 } 1273 1274 if (error == 0 && 1275 ((vap->va_atime.tv_sec != VNOVAL && 1276 vap->va_atime.tv_nsec != VNOVAL) || 1277 (vap->va_mtime.tv_sec != VNOVAL && 1278 vap->va_mtime.tv_nsec != VNOVAL)) 1279 ) { 1280 DPRINTF(ATTR, ("\tchtimes\n")); 1281 error = udf_chtimes(vp, &vap->va_atime, &vap->va_mtime, 1282 &vap->va_birthtime, vap->va_vaflags, cred); 1283 } 1284 VN_KNOTE(vp, NOTE_ATTRIB); 1285 1286 return error; 1287 } 1288 1289 /* --------------------------------------------------------------------- */ 1290 1291 /* 1292 * Return POSIX pathconf information for UDF file systems. 1293 */ 1294 int 1295 udf_pathconf(void *v) 1296 { 1297 struct vop_pathconf_args /* { 1298 struct vnode *a_vp; 1299 int a_name; 1300 register_t *a_retval; 1301 } */ *ap = v; 1302 uint32_t bits; 1303 1304 DPRINTF(CALL, ("udf_pathconf called\n")); 1305 1306 switch (ap->a_name) { 1307 case _PC_LINK_MAX: 1308 *ap->a_retval = (1<<16)-1; /* 16 bits */ 1309 return 0; 1310 case _PC_NAME_MAX: 1311 *ap->a_retval = UDF_MAXNAMLEN; 1312 return 0; 1313 case _PC_PATH_MAX: 1314 *ap->a_retval = PATH_MAX; 1315 return 0; 1316 case _PC_PIPE_BUF: 1317 *ap->a_retval = PIPE_BUF; 1318 return 0; 1319 case _PC_CHOWN_RESTRICTED: 1320 *ap->a_retval = 1; 1321 return 0; 1322 case _PC_NO_TRUNC: 1323 *ap->a_retval = 1; 1324 return 0; 1325 case _PC_SYNC_IO: 1326 *ap->a_retval = 0; /* synchronised is off for performance */ 1327 return 0; 1328 case _PC_FILESIZEBITS: 1329 /* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */ 1330 bits = 64; /* XXX ought to deliver 65 */ 1331 #if 0 1332 if (udf_node) 1333 bits = 64 * vp->v_mount->mnt_dev_bshift; 1334 #endif 1335 *ap->a_retval = bits; 1336 return 0; 1337 } 1338 1339 return EINVAL; 1340 } 1341 1342 1343 /* --------------------------------------------------------------------- */ 1344 1345 int 1346 udf_open(void *v) 1347 { 1348 struct vop_open_args /* { 1349 struct vnode *a_vp; 1350 int a_mode; 1351 kauth_cred_t a_cred; 1352 struct proc *a_p; 1353 } */ *ap = v; 1354 int flags; 1355 1356 DPRINTF(CALL, ("udf_open called\n")); 1357 1358 /* 1359 * Files marked append-only must be opened for appending. 1360 * TODO: get chflags(2) flags from extened attribute. 1361 */ 1362 flags = 0; 1363 if ((flags & APPEND) && (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 1364 return (EPERM); 1365 1366 return 0; 1367 } 1368 1369 1370 /* --------------------------------------------------------------------- */ 1371 1372 int 1373 udf_close(void *v) 1374 { 1375 struct vop_close_args /* { 1376 struct vnode *a_vp; 1377 int a_fflag; 1378 kauth_cred_t a_cred; 1379 struct proc *a_p; 1380 } */ *ap = v; 1381 struct vnode *vp = ap->a_vp; 1382 struct udf_node *udf_node = VTOI(vp); 1383 int async = vp->v_mount->mnt_flag & MNT_ASYNC; 1384 int error; 1385 1386 DPRINTF(CALL, ("udf_close called\n")); 1387 udf_node = udf_node; /* shut up gcc */ 1388 1389 if (!async && (vp->v_type != VDIR)) { 1390 mutex_enter(vp->v_interlock); 1391 error = VOP_PUTPAGES(vp, 0, 0, PGO_CLEANIT); 1392 if (error) 1393 return error; 1394 } 1395 1396 mutex_enter(vp->v_interlock); 1397 if (vp->v_usecount > 1) 1398 udf_itimes(udf_node, NULL, NULL, NULL); 1399 mutex_exit(vp->v_interlock); 1400 1401 return 0; 1402 } 1403 1404 1405 /* --------------------------------------------------------------------- */ 1406 1407 static int 1408 udf_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) 1409 { 1410 int flags; 1411 1412 /* check if we are allowed to write */ 1413 switch (vap->va_type) { 1414 case VDIR: 1415 case VLNK: 1416 case VREG: 1417 /* 1418 * normal nodes: check if we're on a read-only mounted 1419 * filingsystem and bomb out if we're trying to write. 1420 */ 1421 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 1422 return EROFS; 1423 break; 1424 case VBLK: 1425 case VCHR: 1426 case VSOCK: 1427 case VFIFO: 1428 /* 1429 * special nodes: even on read-only mounted filingsystems 1430 * these are allowed to be written to if permissions allow. 1431 */ 1432 break; 1433 default: 1434 /* no idea what this is */ 1435 return EINVAL; 1436 } 1437 1438 /* noone may write immutable files */ 1439 /* TODO: get chflags(2) flags from extened attribute. */ 1440 flags = 0; 1441 if ((mode & VWRITE) && (flags & IMMUTABLE)) 1442 return EPERM; 1443 1444 return 0; 1445 } 1446 1447 static int 1448 udf_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode, 1449 kauth_cred_t cred) 1450 { 1451 /* ask the generic genfs_can_access to advice on security */ 1452 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, 1453 vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp->v_type, 1454 vap->va_mode, vap->va_uid, vap->va_gid, mode, cred)); 1455 } 1456 1457 int 1458 udf_access(void *v) 1459 { 1460 struct vop_access_args /* { 1461 struct vnode *a_vp; 1462 int a_mode; 1463 kauth_cred_t a_cred; 1464 struct proc *a_p; 1465 } */ *ap = v; 1466 struct vnode *vp = ap->a_vp; 1467 mode_t mode = ap->a_mode; 1468 kauth_cred_t cred = ap->a_cred; 1469 /* struct udf_node *udf_node = VTOI(vp); */ 1470 struct vattr vap; 1471 int error; 1472 1473 DPRINTF(CALL, ("udf_access called\n")); 1474 1475 error = VOP_GETATTR(vp, &vap, NULL); 1476 if (error) 1477 return error; 1478 1479 error = udf_check_possible(vp, &vap, mode); 1480 if (error) 1481 return error; 1482 1483 error = udf_check_permitted(vp, &vap, mode, cred); 1484 1485 return error; 1486 } 1487 1488 /* --------------------------------------------------------------------- */ 1489 1490 int 1491 udf_create(void *v) 1492 { 1493 struct vop_create_v3_args /* { 1494 struct vnode *a_dvp; 1495 struct vnode **a_vpp; 1496 struct componentname *a_cnp; 1497 struct vattr *a_vap; 1498 } */ *ap = v; 1499 struct vnode *dvp = ap->a_dvp; 1500 struct vnode **vpp = ap->a_vpp; 1501 struct vattr *vap = ap->a_vap; 1502 struct componentname *cnp = ap->a_cnp; 1503 int error; 1504 1505 DPRINTF(CALL, ("udf_create called\n")); 1506 error = udf_create_node(dvp, vpp, vap, cnp); 1507 1508 return error; 1509 } 1510 1511 /* --------------------------------------------------------------------- */ 1512 1513 int 1514 udf_mknod(void *v) 1515 { 1516 struct vop_mknod_v3_args /* { 1517 struct vnode *a_dvp; 1518 struct vnode **a_vpp; 1519 struct componentname *a_cnp; 1520 struct vattr *a_vap; 1521 } */ *ap = v; 1522 struct vnode *dvp = ap->a_dvp; 1523 struct vnode **vpp = ap->a_vpp; 1524 struct vattr *vap = ap->a_vap; 1525 struct componentname *cnp = ap->a_cnp; 1526 int error; 1527 1528 DPRINTF(CALL, ("udf_mknod called\n")); 1529 error = udf_create_node(dvp, vpp, vap, cnp); 1530 1531 return error; 1532 } 1533 1534 /* --------------------------------------------------------------------- */ 1535 1536 int 1537 udf_mkdir(void *v) 1538 { 1539 struct vop_mkdir_v3_args /* { 1540 struct vnode *a_dvp; 1541 struct vnode **a_vpp; 1542 struct componentname *a_cnp; 1543 struct vattr *a_vap; 1544 } */ *ap = v; 1545 struct vnode *dvp = ap->a_dvp; 1546 struct vnode **vpp = ap->a_vpp; 1547 struct vattr *vap = ap->a_vap; 1548 struct componentname *cnp = ap->a_cnp; 1549 int error; 1550 1551 DPRINTF(CALL, ("udf_mkdir called\n")); 1552 error = udf_create_node(dvp, vpp, vap, cnp); 1553 1554 return error; 1555 } 1556 1557 /* --------------------------------------------------------------------- */ 1558 1559 static int 1560 udf_do_link(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 1561 { 1562 struct udf_node *udf_node, *dir_node; 1563 struct vattr vap; 1564 int error; 1565 1566 DPRINTF(CALL, ("udf_link called\n")); 1567 KASSERT(dvp != vp); 1568 KASSERT(vp->v_type != VDIR); 1569 KASSERT(dvp->v_mount == vp->v_mount); 1570 1571 /* get attributes */ 1572 dir_node = VTOI(dvp); 1573 udf_node = VTOI(vp); 1574 1575 error = VOP_GETATTR(vp, &vap, FSCRED); 1576 if (error) { 1577 VOP_UNLOCK(vp); 1578 return error; 1579 } 1580 1581 /* check link count overflow */ 1582 if (vap.va_nlink >= (1<<16)-1) { /* uint16_t */ 1583 VOP_UNLOCK(vp); 1584 return EMLINK; 1585 } 1586 1587 error = udf_dir_attach(dir_node->ump, dir_node, udf_node, &vap, cnp); 1588 if (error) 1589 VOP_UNLOCK(vp); 1590 return error; 1591 } 1592 1593 int 1594 udf_link(void *v) 1595 { 1596 struct vop_link_v2_args /* { 1597 struct vnode *a_dvp; 1598 struct vnode *a_vp; 1599 struct componentname *a_cnp; 1600 } */ *ap = v; 1601 struct vnode *dvp = ap->a_dvp; 1602 struct vnode *vp = ap->a_vp; 1603 struct componentname *cnp = ap->a_cnp; 1604 int error; 1605 1606 error = udf_do_link(dvp, vp, cnp); 1607 if (error) 1608 VOP_ABORTOP(dvp, cnp); 1609 1610 VN_KNOTE(vp, NOTE_LINK); 1611 VN_KNOTE(dvp, NOTE_WRITE); 1612 1613 return error; 1614 } 1615 1616 /* --------------------------------------------------------------------- */ 1617 1618 static int 1619 udf_do_symlink(struct udf_node *udf_node, char *target) 1620 { 1621 struct pathcomp pathcomp; 1622 uint8_t *pathbuf, *pathpos, *compnamepos; 1623 char *mntonname; 1624 int pathlen, len, compnamelen, mntonnamelen; 1625 int error; 1626 1627 /* process `target' to an UDF structure */ 1628 pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK); 1629 pathpos = pathbuf; 1630 pathlen = 0; 1631 1632 if (*target == '/') { 1633 /* symlink starts from the root */ 1634 len = UDF_PATH_COMP_SIZE; 1635 memset(&pathcomp, 0, len); 1636 pathcomp.type = UDF_PATH_COMP_ROOT; 1637 1638 /* check if its mount-point relative! */ 1639 mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname; 1640 mntonnamelen = strlen(mntonname); 1641 if (strlen(target) >= mntonnamelen) { 1642 if (strncmp(target, mntonname, mntonnamelen) == 0) { 1643 pathcomp.type = UDF_PATH_COMP_MOUNTROOT; 1644 target += mntonnamelen; 1645 } 1646 } else { 1647 target++; 1648 } 1649 1650 memcpy(pathpos, &pathcomp, len); 1651 pathpos += len; 1652 pathlen += len; 1653 } 1654 1655 error = 0; 1656 while (*target) { 1657 /* ignore multiple '/' */ 1658 while (*target == '/') { 1659 target++; 1660 } 1661 if (!*target) 1662 break; 1663 1664 /* extract component name */ 1665 compnamelen = 0; 1666 compnamepos = target; 1667 while ((*target) && (*target != '/')) { 1668 target++; 1669 compnamelen++; 1670 } 1671 1672 /* just trunc if too long ?? (security issue) */ 1673 if (compnamelen >= 127) { 1674 error = ENAMETOOLONG; 1675 break; 1676 } 1677 1678 /* convert unix name to UDF name */ 1679 len = sizeof(struct pathcomp); 1680 memset(&pathcomp, 0, len); 1681 pathcomp.type = UDF_PATH_COMP_NAME; 1682 len = UDF_PATH_COMP_SIZE; 1683 1684 if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0)) 1685 pathcomp.type = UDF_PATH_COMP_PARENTDIR; 1686 if ((compnamelen == 1) && (*compnamepos == '.')) 1687 pathcomp.type = UDF_PATH_COMP_CURDIR; 1688 1689 if (pathcomp.type == UDF_PATH_COMP_NAME) { 1690 unix_to_udf_name( 1691 (char *) &pathcomp.ident, &pathcomp.l_ci, 1692 compnamepos, compnamelen, 1693 &udf_node->ump->logical_vol->desc_charset); 1694 len = UDF_PATH_COMP_SIZE + pathcomp.l_ci; 1695 } 1696 1697 if (pathlen + len >= UDF_SYMLINKBUFLEN) { 1698 error = ENAMETOOLONG; 1699 break; 1700 } 1701 1702 memcpy(pathpos, &pathcomp, len); 1703 pathpos += len; 1704 pathlen += len; 1705 } 1706 1707 if (error) { 1708 /* aparently too big */ 1709 free(pathbuf, M_UDFTEMP); 1710 return error; 1711 } 1712 1713 error = udf_grow_node(udf_node, pathlen); 1714 if (error) { 1715 /* failed to pregrow node */ 1716 free(pathbuf, M_UDFTEMP); 1717 return error; 1718 } 1719 1720 /* write out structure on the new file */ 1721 error = vn_rdwr(UIO_WRITE, udf_node->vnode, 1722 pathbuf, pathlen, 0, 1723 UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS, 1724 FSCRED, NULL, NULL); 1725 1726 /* return status of symlink contents writeout */ 1727 free(pathbuf, M_UDFTEMP); 1728 return error; 1729 } 1730 1731 1732 int 1733 udf_symlink(void *v) 1734 { 1735 struct vop_symlink_v3_args /* { 1736 struct vnode *a_dvp; 1737 struct vnode **a_vpp; 1738 struct componentname *a_cnp; 1739 struct vattr *a_vap; 1740 char *a_target; 1741 } */ *ap = v; 1742 struct vnode *dvp = ap->a_dvp; 1743 struct vnode **vpp = ap->a_vpp; 1744 struct vattr *vap = ap->a_vap; 1745 struct componentname *cnp = ap->a_cnp; 1746 struct udf_node *dir_node; 1747 struct udf_node *udf_node; 1748 int error; 1749 1750 DPRINTF(CALL, ("udf_symlink called\n")); 1751 DPRINTF(CALL, ("\tlinking to `%s`\n", ap->a_target)); 1752 error = udf_create_node(dvp, vpp, vap, cnp); 1753 KASSERT(((error == 0) && (*vpp != NULL)) || ((error && (*vpp == NULL)))); 1754 if (!error) { 1755 dir_node = VTOI(dvp); 1756 udf_node = VTOI(*vpp); 1757 KASSERT(udf_node); 1758 error = udf_do_symlink(udf_node, ap->a_target); 1759 if (error) { 1760 /* remove node */ 1761 udf_dir_detach(udf_node->ump, dir_node, udf_node, cnp); 1762 vrele(*vpp); 1763 *vpp = NULL; 1764 } 1765 } 1766 return error; 1767 } 1768 1769 /* --------------------------------------------------------------------- */ 1770 1771 static int 1772 udf_do_readlink(struct udf_node *udf_node, uint64_t filesize, 1773 uint8_t *targetbuf, int *length) 1774 { 1775 struct pathcomp pathcomp; 1776 uint8_t *pathbuf, *tmpname; 1777 uint8_t *pathpos, *targetpos; 1778 char *mntonname; 1779 int pathlen, targetlen, namelen, mntonnamelen, len, l_ci; 1780 int first, error; 1781 1782 pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK); 1783 tmpname = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); 1784 memset(pathbuf, 0, UDF_SYMLINKBUFLEN); 1785 memset(targetbuf, 0, PATH_MAX); 1786 1787 /* read contents of file in our temporary buffer */ 1788 error = vn_rdwr(UIO_READ, udf_node->vnode, 1789 pathbuf, filesize, 0, 1790 UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS, 1791 FSCRED, NULL, NULL); 1792 if (error) { 1793 /* failed to read in symlink contents */ 1794 free(pathbuf, M_UDFTEMP); 1795 free(tmpname, M_UDFTEMP); 1796 return error; 1797 } 1798 1799 /* convert to a unix path */ 1800 pathpos = pathbuf; 1801 pathlen = 0; 1802 targetpos = targetbuf; 1803 targetlen = PATH_MAX; 1804 mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname; 1805 mntonnamelen = strlen(mntonname); 1806 1807 error = 0; 1808 first = 1; 1809 while (filesize - pathlen >= UDF_PATH_COMP_SIZE) { 1810 len = UDF_PATH_COMP_SIZE; 1811 memcpy(&pathcomp, pathpos, len); 1812 l_ci = pathcomp.l_ci; 1813 switch (pathcomp.type) { 1814 case UDF_PATH_COMP_ROOT : 1815 /* XXX should check for l_ci; bugcompatible now */ 1816 if ((targetlen < 1) || !first) { 1817 error = EINVAL; 1818 break; 1819 } 1820 *targetpos++ = '/'; targetlen--; 1821 break; 1822 case UDF_PATH_COMP_MOUNTROOT : 1823 /* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */ 1824 if (l_ci || (targetlen < mntonnamelen+1) || !first) { 1825 error = EINVAL; 1826 break; 1827 } 1828 memcpy(targetpos, mntonname, mntonnamelen); 1829 targetpos += mntonnamelen; targetlen -= mntonnamelen; 1830 if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) { 1831 /* more follows, so must be directory */ 1832 *targetpos++ = '/'; targetlen--; 1833 } 1834 break; 1835 case UDF_PATH_COMP_PARENTDIR : 1836 /* XXX should check for l_ci; bugcompatible now */ 1837 if (targetlen < 3) { 1838 error = EINVAL; 1839 break; 1840 } 1841 *targetpos++ = '.'; targetlen--; 1842 *targetpos++ = '.'; targetlen--; 1843 *targetpos++ = '/'; targetlen--; 1844 break; 1845 case UDF_PATH_COMP_CURDIR : 1846 /* XXX should check for l_ci; bugcompatible now */ 1847 if (targetlen < 2) { 1848 error = EINVAL; 1849 break; 1850 } 1851 *targetpos++ = '.'; targetlen--; 1852 *targetpos++ = '/'; targetlen--; 1853 break; 1854 case UDF_PATH_COMP_NAME : 1855 if (l_ci == 0) { 1856 error = EINVAL; 1857 break; 1858 } 1859 memset(tmpname, 0, PATH_MAX); 1860 memcpy(&pathcomp, pathpos, len + l_ci); 1861 udf_to_unix_name(tmpname, MAXPATHLEN, 1862 pathcomp.ident, l_ci, 1863 &udf_node->ump->logical_vol->desc_charset); 1864 namelen = strlen(tmpname); 1865 if (targetlen < namelen + 1) { 1866 error = EINVAL; 1867 break; 1868 } 1869 memcpy(targetpos, tmpname, namelen); 1870 targetpos += namelen; targetlen -= namelen; 1871 if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) { 1872 /* more follows, so must be directory */ 1873 *targetpos++ = '/'; targetlen--; 1874 } 1875 break; 1876 default : 1877 error = EINVAL; 1878 break; 1879 } 1880 first = 0; 1881 if (error) 1882 break; 1883 pathpos += UDF_PATH_COMP_SIZE + l_ci; 1884 pathlen += UDF_PATH_COMP_SIZE + l_ci; 1885 1886 } 1887 /* all processed? */ 1888 if (filesize - pathlen > 0) 1889 error = EINVAL; 1890 1891 free(pathbuf, M_UDFTEMP); 1892 free(tmpname, M_UDFTEMP); 1893 1894 *length = PATH_MAX - targetlen; 1895 return error; 1896 } 1897 1898 1899 int 1900 udf_readlink(void *v) 1901 { 1902 struct vop_readlink_args /* { 1903 struct vnode *a_vp; 1904 struct uio *a_uio; 1905 kauth_cred_t a_cred; 1906 } */ *ap = v; 1907 struct vnode *vp = ap->a_vp; 1908 struct udf_node *udf_node = VTOI(vp); 1909 struct file_entry *fe = udf_node->fe; 1910 struct extfile_entry *efe = udf_node->efe; 1911 struct uio *uio = ap->a_uio; 1912 uint64_t filesize; 1913 uint8_t *targetbuf; 1914 int length; 1915 int error; 1916 1917 DPRINTF(CALL, ("udf_readlink called\n")); 1918 1919 if (fe) { 1920 filesize = udf_rw64(fe->inf_len); 1921 } else { 1922 assert(udf_node->efe); 1923 filesize = udf_rw64(efe->inf_len); 1924 } 1925 1926 /* claim temporary buffers for translation */ 1927 targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK); 1928 1929 error = udf_do_readlink(udf_node, filesize, targetbuf, &length); 1930 1931 /* uiomove() to destination */ 1932 if (!error) 1933 uiomove(targetbuf, length, uio); 1934 1935 free(targetbuf, M_UDFTEMP); 1936 return error; 1937 } 1938 1939 /* --------------------------------------------------------------------- */ 1940 1941 /* 1942 * udf_rename() moved to udf_rename.c 1943 */ 1944 1945 /* --------------------------------------------------------------------- */ 1946 1947 int 1948 udf_remove(void *v) 1949 { 1950 struct vop_remove_args /* { 1951 struct vnode *a_dvp; 1952 struct vnode *a_vp; 1953 struct componentname *a_cnp; 1954 } */ *ap = v; 1955 struct vnode *dvp = ap->a_dvp; 1956 struct vnode *vp = ap->a_vp; 1957 struct componentname *cnp = ap->a_cnp; 1958 struct udf_node *dir_node = VTOI(dvp); 1959 struct udf_node *udf_node = VTOI(vp); 1960 struct udf_mount *ump = dir_node->ump; 1961 int error; 1962 1963 DPRINTF(CALL, ("udf_remove called\n")); 1964 if (vp->v_type != VDIR) { 1965 error = udf_dir_detach(ump, dir_node, udf_node, cnp); 1966 DPRINTFIF(NODE, error, ("\tgot error removing file\n")); 1967 } else { 1968 DPRINTF(NODE, ("\tis a directory: perm. denied\n")); 1969 error = EPERM; 1970 } 1971 1972 if (error == 0) { 1973 VN_KNOTE(vp, NOTE_DELETE); 1974 VN_KNOTE(dvp, NOTE_WRITE); 1975 } 1976 1977 if (dvp == vp) 1978 vrele(vp); 1979 else 1980 vput(vp); 1981 vput(dvp); 1982 1983 return error; 1984 } 1985 1986 /* --------------------------------------------------------------------- */ 1987 1988 int 1989 udf_rmdir(void *v) 1990 { 1991 struct vop_rmdir_args /* { 1992 struct vnode *a_dvp; 1993 struct vnode *a_vp; 1994 struct componentname *a_cnp; 1995 } */ *ap = v; 1996 struct vnode *vp = ap->a_vp; 1997 struct vnode *dvp = ap->a_dvp; 1998 struct componentname *cnp = ap->a_cnp; 1999 struct udf_node *dir_node = VTOI(dvp); 2000 struct udf_node *udf_node = VTOI(vp); 2001 struct udf_mount *ump = dir_node->ump; 2002 int error, isempty; 2003 2004 DPRINTF(NOTIMPL, ("udf_rmdir '%s' called\n", cnp->cn_nameptr)); 2005 2006 /* don't allow '.' to be deleted */ 2007 if (dir_node == udf_node) { 2008 vrele(dvp); 2009 vput(vp); 2010 return EINVAL; 2011 } 2012 2013 /* make sure our `leaf' node's hash is populated */ 2014 dirhash_get(&udf_node->dir_hash); 2015 error = udf_dirhash_fill(udf_node); 2016 if (error) { 2017 dirhash_put(udf_node->dir_hash); 2018 return error; 2019 } 2020 2021 /* check to see if the directory is empty */ 2022 isempty = dirhash_dir_isempty(udf_node->dir_hash); 2023 dirhash_put(udf_node->dir_hash); 2024 2025 if (!isempty) { 2026 vput(dvp); 2027 vput(vp); 2028 return ENOTEMPTY; 2029 } 2030 2031 /* detach the node from the directory, udf_node is an empty dir here */ 2032 error = udf_dir_detach(ump, dir_node, udf_node, cnp); 2033 if (error == 0) { 2034 cache_purge(vp); 2035 // cache_purge(dvp); /* XXX from msdosfs, why? */ 2036 /* 2037 * Bug alert: we need to remove '..' from the detaching 2038 * udf_node so further lookups of this are not possible. This 2039 * prevents a process in a deleted directory from going to its 2040 * deleted parent. Since `udf_node' is garanteed to be empty 2041 * here, trunc it so no fids are there. 2042 */ 2043 dirhash_purge(&udf_node->dir_hash); 2044 udf_shrink_node(udf_node, 0); 2045 VN_KNOTE(vp, NOTE_DELETE); 2046 } 2047 DPRINTFIF(NODE, error, ("\tgot error removing dir\n")); 2048 2049 /* unput the nodes and exit */ 2050 vput(dvp); 2051 vput(vp); 2052 2053 return error; 2054 } 2055 2056 /* --------------------------------------------------------------------- */ 2057 2058 int 2059 udf_fsync(void *v) 2060 { 2061 struct vop_fsync_args /* { 2062 struct vnode *a_vp; 2063 kauth_cred_t a_cred; 2064 int a_flags; 2065 off_t offlo; 2066 off_t offhi; 2067 struct proc *a_p; 2068 } */ *ap = v; 2069 struct vnode *vp = ap->a_vp; 2070 struct udf_node *udf_node = VTOI(vp); 2071 int error, flags, wait; 2072 2073 DPRINTF(SYNC, ("udf_fsync called on %p : %s, %s\n", 2074 udf_node, 2075 (ap->a_flags & FSYNC_WAIT) ? "wait":"no wait", 2076 (ap->a_flags & FSYNC_DATAONLY) ? "data_only":"complete")); 2077 2078 /* flush data and wait for it when requested */ 2079 wait = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; 2080 error = vflushbuf(vp, ap->a_flags); 2081 if (error) 2082 return error; 2083 2084 if (udf_node == NULL) { 2085 printf("udf_fsync() called on NULL udf_node!\n"); 2086 return 0; 2087 } 2088 if (vp->v_tag != VT_UDF) { 2089 printf("udf_fsync() called on node not tagged as UDF node!\n"); 2090 return 0; 2091 } 2092 2093 /* set our times */ 2094 udf_itimes(udf_node, NULL, NULL, NULL); 2095 2096 /* if called when mounted readonly, never write back */ 2097 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2098 return 0; 2099 2100 /* if only data is requested, return */ 2101 if (ap->a_flags & FSYNC_DATAONLY) 2102 return 0; 2103 2104 /* check if the node is dirty 'enough'*/ 2105 flags = udf_node->i_flags & (IN_MODIFIED | IN_ACCESSED); 2106 if (flags == 0) 2107 return 0; 2108 2109 /* if we don't have to wait, check for IO pending */ 2110 if (!wait) { 2111 if (vp->v_numoutput > 0) { 2112 DPRINTF(SYNC, ("udf_fsync %p, rejecting on v_numoutput\n", udf_node)); 2113 return 0; 2114 } 2115 if (udf_node->outstanding_bufs > 0) { 2116 DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_bufs\n", udf_node)); 2117 return 0; 2118 } 2119 if (udf_node->outstanding_nodedscr > 0) { 2120 DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_nodedscr\n", udf_node)); 2121 return 0; 2122 } 2123 } 2124 2125 /* wait until vp->v_numoutput reaches zero i.e. is finished */ 2126 if (wait) { 2127 DPRINTF(SYNC, ("udf_fsync %p, waiting\n", udf_node)); 2128 mutex_enter(vp->v_interlock); 2129 while (vp->v_numoutput) { 2130 DPRINTF(SYNC, ("udf_fsync %p, v_numoutput %d\n", udf_node, vp->v_numoutput)); 2131 cv_timedwait(&vp->v_cv, vp->v_interlock, hz/8); 2132 } 2133 mutex_exit(vp->v_interlock); 2134 DPRINTF(SYNC, ("udf_fsync %p, fin wait\n", udf_node)); 2135 } 2136 2137 /* write out node and wait for it if requested */ 2138 DPRINTF(SYNC, ("udf_fsync %p, writeout node\n", udf_node)); 2139 error = udf_writeout_node(udf_node, wait); 2140 if (error) 2141 return error; 2142 2143 /* TODO/XXX if ap->a_flags & FSYNC_CACHE, we ought to do a disc sync */ 2144 2145 return 0; 2146 } 2147 2148 /* --------------------------------------------------------------------- */ 2149 2150 int 2151 udf_advlock(void *v) 2152 { 2153 struct vop_advlock_args /* { 2154 struct vnode *a_vp; 2155 void *a_id; 2156 int a_op; 2157 struct flock *a_fl; 2158 int a_flags; 2159 } */ *ap = v; 2160 struct vnode *vp = ap->a_vp; 2161 struct udf_node *udf_node = VTOI(vp); 2162 struct file_entry *fe; 2163 struct extfile_entry *efe; 2164 uint64_t file_size; 2165 2166 DPRINTF(LOCKING, ("udf_advlock called\n")); 2167 2168 /* get directory filesize */ 2169 if (udf_node->fe) { 2170 fe = udf_node->fe; 2171 file_size = udf_rw64(fe->inf_len); 2172 } else { 2173 assert(udf_node->efe); 2174 efe = udf_node->efe; 2175 file_size = udf_rw64(efe->inf_len); 2176 } 2177 2178 return lf_advlock(ap, &udf_node->lockf, file_size); 2179 } 2180 2181 /* --------------------------------------------------------------------- */ 2182 2183 /* Global vfs vnode data structures for udfs */ 2184 int (**udf_vnodeop_p)(void *); 2185 2186 const struct vnodeopv_entry_desc udf_vnodeop_entries[] = { 2187 { &vop_default_desc, vn_default_error }, 2188 { &vop_lookup_desc, udf_lookup }, /* lookup */ 2189 { &vop_create_desc, udf_create }, /* create */ 2190 { &vop_mknod_desc, udf_mknod }, /* mknod */ /* TODO */ 2191 { &vop_open_desc, udf_open }, /* open */ 2192 { &vop_close_desc, udf_close }, /* close */ 2193 { &vop_access_desc, udf_access }, /* access */ 2194 { &vop_getattr_desc, udf_getattr }, /* getattr */ 2195 { &vop_setattr_desc, udf_setattr }, /* setattr */ /* TODO chflags */ 2196 { &vop_read_desc, udf_read }, /* read */ 2197 { &vop_write_desc, udf_write }, /* write */ /* WRITE */ 2198 { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 2199 { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 2200 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ /* TODO? */ 2201 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ /* TODO? */ 2202 { &vop_poll_desc, genfs_poll }, /* poll */ /* TODO/OK? */ 2203 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ /* ? */ 2204 { &vop_revoke_desc, genfs_revoke }, /* revoke */ /* TODO? */ 2205 { &vop_mmap_desc, genfs_mmap }, /* mmap */ /* OK? */ 2206 { &vop_fsync_desc, udf_fsync }, /* fsync */ 2207 { &vop_seek_desc, genfs_seek }, /* seek */ 2208 { &vop_remove_desc, udf_remove }, /* remove */ 2209 { &vop_link_desc, udf_link }, /* link */ /* TODO */ 2210 { &vop_rename_desc, udf_rename }, /* rename */ /* TODO */ 2211 { &vop_mkdir_desc, udf_mkdir }, /* mkdir */ 2212 { &vop_rmdir_desc, udf_rmdir }, /* rmdir */ 2213 { &vop_symlink_desc, udf_symlink }, /* symlink */ /* TODO */ 2214 { &vop_readdir_desc, udf_readdir }, /* readdir */ 2215 { &vop_readlink_desc, udf_readlink }, /* readlink */ /* TEST ME */ 2216 { &vop_abortop_desc, genfs_abortop }, /* abortop */ /* TODO/OK? */ 2217 { &vop_inactive_desc, udf_inactive }, /* inactive */ 2218 { &vop_reclaim_desc, udf_reclaim }, /* reclaim */ 2219 { &vop_lock_desc, genfs_lock }, /* lock */ 2220 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 2221 { &vop_bmap_desc, udf_trivial_bmap }, /* bmap */ /* 1:1 bmap */ 2222 { &vop_strategy_desc, udf_vfsstrategy },/* strategy */ 2223 /* { &vop_print_desc, udf_print }, */ /* print */ 2224 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 2225 { &vop_pathconf_desc, udf_pathconf }, /* pathconf */ 2226 { &vop_advlock_desc, udf_advlock }, /* advlock */ /* TEST ME */ 2227 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ /* ->strategy */ 2228 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 2229 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 2230 { NULL, NULL } 2231 }; 2232 2233 2234 const struct vnodeopv_desc udf_vnodeop_opv_desc = { 2235 &udf_vnodeop_p, udf_vnodeop_entries 2236 }; 2237