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