1 /* $NetBSD: ntfs_vnops.c,v 1.23 1999/10/31 19:45:27 jdolecek Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * John Heidemann of the UCLA Ficus project. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * $FreeBSD: src/sys/ntfs/ntfs_vnops.c,v 1.9.2.4 2002/08/06 19:35:18 semenu Exp $ 39 * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.19 2004/11/12 00:09:38 dillon Exp $ 40 * 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/time.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/namei.h> 53 #include <sys/malloc.h> 54 #include <sys/buf.h> 55 #include <sys/dirent.h> 56 57 #include <vm/vm.h> 58 #include <vm/vm_param.h> 59 #if defined(__NetBSD__) 60 #include <vm/vm_prot.h> 61 #endif 62 #include <vm/vm_page.h> 63 #include <vm/vm_object.h> 64 #include <vm/vm_pager.h> 65 #if defined(__DragonFly__) 66 #include <vm/vnode_pager.h> 67 #endif 68 #include <vm/vm_extern.h> 69 70 #include <sys/sysctl.h> 71 72 /*#define NTFS_DEBUG 1*/ 73 #include "ntfs.h" 74 #include "ntfs_inode.h" 75 #include "ntfs_subr.h" 76 #if defined(__NetBSD__) 77 #include <miscfs/specfs/specdev.h> 78 #include <miscfs/genfs/genfs.h> 79 #endif 80 81 #include <sys/unistd.h> /* for pathconf(2) constants */ 82 83 static int ntfs_read (struct vop_read_args *); 84 static int ntfs_write (struct vop_write_args *ap); 85 static int ntfs_getattr (struct vop_getattr_args *ap); 86 static int ntfs_inactive (struct vop_inactive_args *ap); 87 static int ntfs_print (struct vop_print_args *ap); 88 static int ntfs_reclaim (struct vop_reclaim_args *ap); 89 static int ntfs_strategy (struct vop_strategy_args *ap); 90 static int ntfs_access (struct vop_access_args *ap); 91 static int ntfs_open (struct vop_open_args *ap); 92 static int ntfs_close (struct vop_close_args *ap); 93 static int ntfs_readdir (struct vop_readdir_args *ap); 94 static int ntfs_lookup (struct vop_lookup_args *ap); 95 static int ntfs_bmap (struct vop_bmap_args *ap); 96 #if defined(__DragonFly__) 97 static int ntfs_getpages (struct vop_getpages_args *ap); 98 static int ntfs_putpages (struct vop_putpages_args *); 99 static int ntfs_fsync (struct vop_fsync_args *ap); 100 #else 101 static int ntfs_bypass (struct vop_generic_args *); 102 #endif 103 static int ntfs_pathconf (void *); 104 105 int ntfs_prtactive = 1; /* 1 => print out reclaim of active vnodes */ 106 107 #if defined(__DragonFly__) 108 int 109 ntfs_getpages(struct vop_getpages_args *ap) 110 { 111 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, 112 ap->a_reqpage); 113 } 114 115 int 116 ntfs_putpages(struct vop_putpages_args *ap) 117 { 118 return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, 119 ap->a_sync, ap->a_rtvals); 120 } 121 #endif 122 123 /* 124 * This is a noop, simply returning what one has been given. 125 * 126 * ntfs_bmap(struct vnode *a_vp, daddr_t a_bn, struct vnode **a_vpp, 127 * daddr_t *a_bnp, int *a_runp, int *a_runb) 128 */ 129 int 130 ntfs_bmap(struct vop_bmap_args *ap) 131 { 132 dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn)); 133 if (ap->a_vpp != NULL) 134 *ap->a_vpp = ap->a_vp; 135 if (ap->a_bnp != NULL) 136 *ap->a_bnp = ap->a_bn; 137 if (ap->a_runp != NULL) 138 *ap->a_runp = 0; 139 #if !defined(__NetBSD__) 140 if (ap->a_runb != NULL) 141 *ap->a_runb = 0; 142 #endif 143 return (0); 144 } 145 146 /* 147 * ntfs_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, 148 * struct ucred *a_cred) 149 */ 150 static int 151 ntfs_read(struct vop_read_args *ap) 152 { 153 struct vnode *vp = ap->a_vp; 154 struct fnode *fp = VTOF(vp); 155 struct ntnode *ip = FTONT(fp); 156 struct uio *uio = ap->a_uio; 157 struct ntfsmount *ntmp = ip->i_mp; 158 struct buf *bp; 159 daddr_t cn; 160 int resid, off, toread; 161 int error; 162 163 dprintf(("ntfs_read: ino: %d, off: %d resid: %d, segflg: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg)); 164 165 dprintf(("ntfs_read: filesize: %d",(u_int32_t)fp->f_size)); 166 167 /* don't allow reading after end of file */ 168 if (uio->uio_offset > fp->f_size) 169 return (0); 170 171 resid = min(uio->uio_resid, fp->f_size - uio->uio_offset); 172 173 dprintf((", resid: %d\n", resid)); 174 175 error = 0; 176 while (resid) { 177 cn = ntfs_btocn(uio->uio_offset); 178 off = ntfs_btocnoff(uio->uio_offset); 179 180 toread = min(off + resid, ntfs_cntob(1)); 181 182 error = bread(vp, cn, ntfs_cntob(1), &bp); 183 if (error) { 184 brelse(bp); 185 break; 186 } 187 188 error = uiomove(bp->b_data + off, toread - off, uio); 189 if(error) { 190 brelse(bp); 191 break; 192 } 193 brelse(bp); 194 195 resid -= toread - off; 196 } 197 198 return (error); 199 } 200 201 #if !defined(__DragonFly__) 202 203 /* 204 * ntfs_bypass(struct vnodeop_desc *a_desc, ...) 205 */ 206 static int 207 ntfs_bypass(struct vop_generic_args *ap) 208 { 209 int error = ENOTTY; 210 dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name)); 211 return (error); 212 } 213 214 #endif 215 216 /* 217 * ntfs_getattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred, 218 * struct thread *a_td) 219 */ 220 static int 221 ntfs_getattr(struct vop_getattr_args *ap) 222 { 223 struct vnode *vp = ap->a_vp; 224 struct fnode *fp = VTOF(vp); 225 struct ntnode *ip = FTONT(fp); 226 struct vattr *vap = ap->a_vap; 227 228 dprintf(("ntfs_getattr: %d, flags: %d\n",ip->i_number,ip->i_flag)); 229 230 #if defined(__DragonFly__) 231 vap->va_fsid = dev2udev(ip->i_dev); 232 #else /* NetBSD */ 233 vap->va_fsid = ip->i_dev; 234 #endif 235 vap->va_fileid = ip->i_number; 236 vap->va_mode = ip->i_mp->ntm_mode; 237 vap->va_nlink = ip->i_nlink; 238 vap->va_uid = ip->i_mp->ntm_uid; 239 vap->va_gid = ip->i_mp->ntm_gid; 240 vap->va_rdev = 0; /* XXX UNODEV ? */ 241 vap->va_size = fp->f_size; 242 vap->va_bytes = fp->f_allocated; 243 vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access); 244 vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write); 245 vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create); 246 vap->va_flags = ip->i_flag; 247 vap->va_gen = 0; 248 vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps; 249 vap->va_type = vp->v_type; 250 vap->va_filerev = 0; 251 return (0); 252 } 253 254 255 /* 256 * Last reference to an ntnode. If necessary, write or delete it. 257 * 258 * ntfs_inactive(struct vnode *a_vp) 259 */ 260 int 261 ntfs_inactive(struct vop_inactive_args *ap) 262 { 263 struct vnode *vp = ap->a_vp; 264 #ifdef NTFS_DEBUG 265 struct ntnode *ip = VTONT(vp); 266 #endif 267 268 dprintf(("ntfs_inactive: vnode: %p, ntnode: %d\n", vp, ip->i_number)); 269 270 if (ntfs_prtactive && vp->v_usecount != 0) 271 vprint("ntfs_inactive: pushing active", vp); 272 273 /* 274 * XXX since we don't support any filesystem changes 275 * right now, nothing more needs to be done 276 */ 277 return (0); 278 } 279 280 /* 281 * Reclaim an fnode/ntnode so that it can be used for other purposes. 282 * 283 * ntfs_reclaim(struct vnode *a_vp) 284 */ 285 int 286 ntfs_reclaim(struct vop_reclaim_args *ap) 287 { 288 struct vnode *vp = ap->a_vp; 289 struct fnode *fp = VTOF(vp); 290 struct ntnode *ip = FTONT(fp); 291 int error; 292 293 dprintf(("ntfs_reclaim: vnode: %p, ntnode: %d\n", vp, ip->i_number)); 294 295 if (ntfs_prtactive && vp->v_usecount != 0) 296 vprint("ntfs_reclaim: pushing active", vp); 297 298 if ((error = ntfs_ntget(ip)) != 0) 299 return (error); 300 301 ntfs_frele(fp); 302 ntfs_ntput(ip); 303 vp->v_data = NULL; 304 305 return (0); 306 } 307 308 /* 309 * ntfs_print(struct vnode *a_vp) 310 */ 311 static int 312 ntfs_print(struct vop_print_args *ap) 313 { 314 return (0); 315 } 316 317 /* 318 * Calculate the logical to physical mapping if not done already, 319 * then call the device strategy routine. 320 * 321 * ntfs_strategy(struct buf *a_bp) 322 */ 323 int 324 ntfs_strategy(struct vop_strategy_args *ap) 325 { 326 struct buf *bp = ap->a_bp; 327 struct vnode *vp = bp->b_vp; 328 struct fnode *fp = VTOF(vp); 329 struct ntnode *ip = FTONT(fp); 330 struct ntfsmount *ntmp = ip->i_mp; 331 int error; 332 333 #ifdef __DragonFly__ 334 dprintf(("ntfs_strategy: offset: %d, blkno: %d, lblkno: %d\n", 335 (u_int32_t)bp->b_offset,(u_int32_t)bp->b_blkno, 336 (u_int32_t)bp->b_lblkno)); 337 #else 338 dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n", 339 (u_int32_t)bp->b_blkno, 340 (u_int32_t)bp->b_lblkno)); 341 #endif 342 343 dprintf(("strategy: bcount: %d flags: 0x%lx\n", 344 (u_int32_t)bp->b_bcount,bp->b_flags)); 345 346 if (bp->b_flags & B_READ) { 347 u_int32_t toread; 348 349 if (ntfs_cntob(bp->b_blkno) >= fp->f_size) { 350 clrbuf(bp); 351 error = 0; 352 } else { 353 toread = min(bp->b_bcount, 354 fp->f_size-ntfs_cntob(bp->b_blkno)); 355 dprintf(("ntfs_strategy: toread: %d, fsize: %d\n", 356 toread,(u_int32_t)fp->f_size)); 357 358 error = ntfs_readattr(ntmp, ip, fp->f_attrtype, 359 fp->f_attrname, ntfs_cntob(bp->b_blkno), 360 toread, bp->b_data, NULL); 361 362 if (error) { 363 printf("ntfs_strategy: ntfs_readattr failed\n"); 364 bp->b_error = error; 365 bp->b_flags |= B_ERROR; 366 } 367 368 bzero(bp->b_data + toread, bp->b_bcount - toread); 369 } 370 } else { 371 size_t tmp; 372 u_int32_t towrite; 373 374 if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) { 375 printf("ntfs_strategy: CAN'T EXTEND FILE\n"); 376 bp->b_error = error = EFBIG; 377 bp->b_flags |= B_ERROR; 378 } else { 379 towrite = min(bp->b_bcount, 380 fp->f_size-ntfs_cntob(bp->b_blkno)); 381 dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n", 382 towrite,(u_int32_t)fp->f_size)); 383 384 error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype, 385 fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite, 386 bp->b_data, &tmp, NULL); 387 388 if (error) { 389 printf("ntfs_strategy: ntfs_writeattr fail\n"); 390 bp->b_error = error; 391 bp->b_flags |= B_ERROR; 392 } 393 } 394 } 395 biodone(bp); 396 return (error); 397 } 398 399 /* 400 * ntfs_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, 401 * struct ucred *a_cred) 402 */ 403 static int 404 ntfs_write(struct vop_write_args *ap) 405 { 406 struct vnode *vp = ap->a_vp; 407 struct fnode *fp = VTOF(vp); 408 struct ntnode *ip = FTONT(fp); 409 struct uio *uio = ap->a_uio; 410 struct ntfsmount *ntmp = ip->i_mp; 411 u_int64_t towrite; 412 size_t written; 413 int error; 414 415 dprintf(("ntfs_write: ino: %d, off: %d resid: %d, segflg: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg)); 416 dprintf(("ntfs_write: filesize: %d",(u_int32_t)fp->f_size)); 417 418 if (uio->uio_resid + uio->uio_offset > fp->f_size) { 419 printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n"); 420 return (EFBIG); 421 } 422 423 towrite = min(uio->uio_resid, fp->f_size - uio->uio_offset); 424 425 dprintf((", towrite: %d\n",(u_int32_t)towrite)); 426 427 error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype, 428 fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio); 429 #ifdef NTFS_DEBUG 430 if (error) 431 printf("ntfs_write: ntfs_writeattr failed: %d\n", error); 432 #endif 433 434 return (error); 435 } 436 437 /* 438 * ntfs_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred, 439 * struct thread *a_td) 440 */ 441 int 442 ntfs_access(struct vop_access_args *ap) 443 { 444 struct vnode *vp = ap->a_vp; 445 struct ntnode *ip = VTONT(vp); 446 struct ucred *cred = ap->a_cred; 447 mode_t mask, mode = ap->a_mode; 448 gid_t *gp; 449 int i; 450 #ifdef QUOTA 451 int error; 452 #endif 453 454 dprintf(("ntfs_access: %d\n",ip->i_number)); 455 456 /* 457 * Disallow write attempts on read-only file systems; 458 * unless the file is a socket, fifo, or a block or 459 * character device resident on the file system. 460 */ 461 if (mode & VWRITE) { 462 switch ((int)vp->v_type) { 463 case VDIR: 464 case VLNK: 465 case VREG: 466 if (vp->v_mount->mnt_flag & MNT_RDONLY) 467 return (EROFS); 468 #ifdef QUOTA 469 if (error = getinoquota(ip)) 470 return (error); 471 #endif 472 break; 473 } 474 } 475 476 /* Otherwise, user id 0 always gets access. */ 477 if (cred->cr_uid == 0) 478 return (0); 479 480 mask = 0; 481 482 /* Otherwise, check the owner. */ 483 if (cred->cr_uid == ip->i_mp->ntm_uid) { 484 if (mode & VEXEC) 485 mask |= S_IXUSR; 486 if (mode & VREAD) 487 mask |= S_IRUSR; 488 if (mode & VWRITE) 489 mask |= S_IWUSR; 490 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES); 491 } 492 493 /* Otherwise, check the groups. */ 494 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) 495 if (ip->i_mp->ntm_gid == *gp) { 496 if (mode & VEXEC) 497 mask |= S_IXGRP; 498 if (mode & VREAD) 499 mask |= S_IRGRP; 500 if (mode & VWRITE) 501 mask |= S_IWGRP; 502 return ((ip->i_mp->ntm_mode&mask) == mask ? 0 : EACCES); 503 } 504 505 /* Otherwise, check everyone else. */ 506 if (mode & VEXEC) 507 mask |= S_IXOTH; 508 if (mode & VREAD) 509 mask |= S_IROTH; 510 if (mode & VWRITE) 511 mask |= S_IWOTH; 512 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES); 513 } 514 515 /* 516 * Open called. 517 * 518 * Nothing to do. 519 * 520 * ntfs_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred, 521 * struct thread *a_td) 522 */ 523 /* ARGSUSED */ 524 static int 525 ntfs_open(struct vop_open_args *ap) 526 { 527 #if NTFS_DEBUG 528 struct vnode *vp = ap->a_vp; 529 struct ntnode *ip = VTONT(vp); 530 531 printf("ntfs_open: %d\n",ip->i_number); 532 #endif 533 534 /* 535 * Files marked append-only must be opened for appending. 536 */ 537 538 return (0); 539 } 540 541 /* 542 * Close called. 543 * 544 * Update the times on the inode. 545 * 546 * ntfs_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred, 547 * struct thread *a_td) 548 */ 549 /* ARGSUSED */ 550 static int 551 ntfs_close(struct vop_close_args *ap) 552 { 553 #if NTFS_DEBUG 554 struct vnode *vp = ap->a_vp; 555 struct ntnode *ip = VTONT(vp); 556 557 printf("ntfs_close: %d\n",ip->i_number); 558 #endif 559 560 return (0); 561 } 562 563 /* 564 * ntfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, 565 * int *a_ncookies, u_int **cookies) 566 */ 567 int 568 ntfs_readdir(struct vop_readdir_args *ap) 569 { 570 struct vnode *vp = ap->a_vp; 571 struct fnode *fp = VTOF(vp); 572 struct ntnode *ip = FTONT(fp); 573 struct uio *uio = ap->a_uio; 574 struct ntfsmount *ntmp = ip->i_mp; 575 int i, error = 0; 576 u_int32_t faked = 0, num; 577 int ncookies = 0; 578 struct dirent cde; 579 off_t off; 580 581 dprintf(("ntfs_readdir %d off: %d resid: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid)); 582 583 off = uio->uio_offset; 584 585 /* Simulate . in every dir except ROOT */ 586 if( ip->i_number != NTFS_ROOTINO ) { 587 struct dirent dot = { NTFS_ROOTINO, 588 sizeof(struct dirent), DT_DIR, 1, "." }; 589 590 if( uio->uio_offset < sizeof(struct dirent) ) { 591 dot.d_fileno = ip->i_number; 592 error = uiomove((char *)&dot,sizeof(struct dirent),uio); 593 if(error) 594 return (error); 595 596 ncookies ++; 597 } 598 } 599 600 /* Simulate .. in every dir including ROOT */ 601 if( uio->uio_offset < 2 * sizeof(struct dirent) ) { 602 struct dirent dotdot = { NTFS_ROOTINO, 603 sizeof(struct dirent), DT_DIR, 2, ".." }; 604 605 error = uiomove((char *)&dotdot,sizeof(struct dirent),uio); 606 if(error) 607 return (error); 608 609 ncookies ++; 610 } 611 612 faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2; 613 num = uio->uio_offset / sizeof(struct dirent) - faked; 614 615 while( uio->uio_resid >= sizeof(struct dirent) ) { 616 struct attr_indexentry *iep; 617 618 error = ntfs_ntreaddir(ntmp, fp, num, &iep); 619 620 if(error) 621 return (error); 622 623 if( NULL == iep ) 624 break; 625 626 for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent)); 627 iep = NTFS_NEXTREC(iep, struct attr_indexentry *)) 628 { 629 if(!ntfs_isnamepermitted(ntmp,iep)) 630 continue; 631 632 for(i=0; i<iep->ie_fnamelen; i++) { 633 cde.d_name[i] = NTFS_U28(iep->ie_fname[i]); 634 } 635 cde.d_name[i] = '\0'; 636 dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ", 637 num, cde.d_name, iep->ie_fnametype, 638 iep->ie_flag)); 639 cde.d_namlen = iep->ie_fnamelen; 640 cde.d_fileno = iep->ie_number; 641 cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG; 642 cde.d_reclen = sizeof(struct dirent); 643 dprintf(("%s\n", (cde.d_type == DT_DIR) ? "dir":"reg")); 644 645 error = uiomove((char *)&cde, sizeof(struct dirent), uio); 646 if(error) 647 return (error); 648 649 ncookies++; 650 num++; 651 } 652 } 653 654 dprintf(("ntfs_readdir: %d entries (%d bytes) read\n", 655 ncookies,(u_int)(uio->uio_offset - off))); 656 dprintf(("ntfs_readdir: off: %d resid: %d\n", 657 (u_int32_t)uio->uio_offset,uio->uio_resid)); 658 659 if (!error && ap->a_ncookies != NULL) { 660 struct dirent* dpStart; 661 struct dirent* dp; 662 #if defined(__DragonFly__) 663 u_long *cookies; 664 u_long *cookiep; 665 #else /* defined(__NetBSD__) */ 666 off_t *cookies; 667 off_t *cookiep; 668 #endif 669 670 ddprintf(("ntfs_readdir: %d cookies\n",ncookies)); 671 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) 672 panic("ntfs_readdir: unexpected uio from NFS server"); 673 dpStart = (struct dirent *) 674 ((caddr_t)uio->uio_iov->iov_base - 675 (uio->uio_offset - off)); 676 #if defined(__DragonFly__) 677 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), 678 M_TEMP, M_WAITOK); 679 #else /* defined(__NetBSD__) */ 680 MALLOC(cookies, off_t *, ncookies * sizeof(off_t), 681 M_TEMP, M_WAITOK); 682 #endif 683 for (dp = dpStart, cookiep = cookies, i=0; 684 i < ncookies; 685 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) { 686 off += dp->d_reclen; 687 *cookiep++ = (u_int) off; 688 } 689 *ap->a_ncookies = ncookies; 690 *ap->a_cookies = cookies; 691 } 692 /* 693 if (ap->a_eofflag) 694 *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset; 695 */ 696 return (error); 697 } 698 699 /* 700 * ntfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, 701 * struct componentname *a_cnp) 702 */ 703 int 704 ntfs_lookup(struct vop_lookup_args *ap) 705 { 706 struct vnode *dvp = ap->a_dvp; 707 struct ntnode *dip = VTONT(dvp); 708 struct ntfsmount *ntmp = dip->i_mp; 709 struct componentname *cnp = ap->a_cnp; 710 struct ucred *cred = cnp->cn_cred; 711 int error; 712 int lockparent = cnp->cn_flags & CNP_LOCKPARENT; 713 #if NTFS_DEBUG 714 int wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT); 715 #endif 716 dprintf(("ntfs_lookup: \"%.*s\" (%ld bytes) in %d, lp: %d, wp: %d \n", 717 (int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen, 718 dip->i_number, lockparent, wantparent)); 719 720 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 721 dprintf(("ntfs_lookup: faking . directory in %d\n", 722 dip->i_number)); 723 724 vref(dvp); 725 *ap->a_vpp = dvp; 726 error = 0; 727 } else if (cnp->cn_flags & CNP_ISDOTDOT) { 728 struct ntvattr *vap; 729 730 dprintf(("ntfs_lookup: faking .. directory in %d\n", 731 dip->i_number)); 732 733 error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap); 734 if(error) 735 return (error); 736 737 VOP__UNLOCK(dvp,0,cnp->cn_td); 738 cnp->cn_flags |= CNP_PDIRUNLOCK; 739 740 dprintf(("ntfs_lookup: parentdir: %d\n", 741 vap->va_a_name->n_pnumber)); 742 error = VFS_VGET(ntmp->ntm_mountp, 743 vap->va_a_name->n_pnumber,ap->a_vpp); 744 ntfs_ntvattrrele(vap); 745 if (error) { 746 if (VN_LOCK(dvp,LK_EXCLUSIVE|LK_RETRY,cnp->cn_td)==0) 747 cnp->cn_flags &= ~CNP_PDIRUNLOCK; 748 return (error); 749 } 750 751 if (lockparent) { 752 error = VN_LOCK(dvp, LK_EXCLUSIVE, cnp->cn_td); 753 if (error) { 754 vput( *(ap->a_vpp) ); 755 return (error); 756 } 757 cnp->cn_flags &= ~CNP_PDIRUNLOCK; 758 } 759 } else { 760 error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp); 761 if (error) { 762 dprintf(("ntfs_ntlookupfile: returned %d\n", error)); 763 return (error); 764 } 765 766 dprintf(("ntfs_lookup: found ino: %d\n", 767 VTONT(*ap->a_vpp)->i_number)); 768 769 if (!lockparent) 770 VOP__UNLOCK(dvp, 0, cnp->cn_td); 771 } 772 return (error); 773 } 774 775 #if defined(__DragonFly__) 776 /* 777 * Flush the blocks of a file to disk. 778 * 779 * This function is worthless for vnodes that represent directories. Maybe we 780 * could just do a sync if they try an fsync on a directory file. 781 * 782 * ntfs_fsync(struct vnode *a_vp, struct ucred *a_cred, int a_waitfor, 783 * struct thread *a_td) 784 */ 785 static int 786 ntfs_fsync(struct vop_fsync_args *ap) 787 { 788 return (0); 789 } 790 #endif 791 792 /* 793 * Return POSIX pathconf information applicable to NTFS filesystem 794 */ 795 int 796 ntfs_pathconf(void *v) 797 { 798 struct vop_pathconf_args /* { 799 struct vnode *a_vp; 800 int a_name; 801 register_t *a_retval; 802 } */ *ap = v; 803 804 switch (ap->a_name) { 805 case _PC_LINK_MAX: 806 *ap->a_retval = 1; 807 return (0); 808 case _PC_NAME_MAX: 809 *ap->a_retval = NTFS_MAXFILENAME; 810 return (0); 811 case _PC_PATH_MAX: 812 *ap->a_retval = PATH_MAX; 813 return (0); 814 case _PC_CHOWN_RESTRICTED: 815 *ap->a_retval = 1; 816 return (0); 817 case _PC_NO_TRUNC: 818 *ap->a_retval = 0; 819 return (0); 820 #if defined(__NetBSD__) 821 case _PC_SYNC_IO: 822 *ap->a_retval = 1; 823 return (0); 824 case _PC_FILESIZEBITS: 825 *ap->a_retval = 64; 826 return (0); 827 #endif 828 default: 829 return (EINVAL); 830 } 831 /* NOTREACHED */ 832 } 833 834 /* 835 * Global vfs data structures 836 */ 837 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = { 838 { &vop_default_desc, vop_defaultop }, 839 840 { &vop_getattr_desc, (void *)ntfs_getattr }, 841 { &vop_inactive_desc, (void *)ntfs_inactive }, 842 { &vop_reclaim_desc, (void *)ntfs_reclaim }, 843 { &vop_print_desc, (void *)ntfs_print }, 844 { &vop_pathconf_desc, (void *)ntfs_pathconf }, 845 846 { &vop_islocked_desc, (void *)vop_stdislocked }, 847 { &vop_unlock_desc, (void *)vop_stdunlock }, 848 { &vop_lock_desc, (void *)vop_stdlock }, 849 { &vop_lookup_desc, (void *)ntfs_lookup }, 850 851 { &vop_access_desc, (void *)ntfs_access }, 852 { &vop_close_desc, (void *)ntfs_close }, 853 { &vop_open_desc, (void *)ntfs_open }, 854 { &vop_readdir_desc, (void *)ntfs_readdir }, 855 { &vop_fsync_desc, (void *)ntfs_fsync }, 856 857 { &vop_bmap_desc, (void *)ntfs_bmap }, 858 { &vop_getpages_desc, (void *)ntfs_getpages }, 859 { &vop_putpages_desc, (void *)ntfs_putpages }, 860 { &vop_strategy_desc, (void *)ntfs_strategy }, 861 { &vop_bwrite_desc, (void *)vop_stdbwrite }, 862 { &vop_read_desc, (void *)ntfs_read }, 863 { &vop_write_desc, (void *)ntfs_write }, 864 865 { NULL, NULL } 866 }; 867 868