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.14 2004/08/17 18:57:34 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 VOP__UNLOCK(vp, 0, ap->a_td); 274 275 /* XXX since we don't support any filesystem changes 276 * right now, nothing more needs to be done 277 */ 278 return (0); 279 } 280 281 /* 282 * Reclaim an fnode/ntnode so that it can be used for other purposes. 283 * 284 * ntfs_reclaim(struct vnode *a_vp) 285 */ 286 int 287 ntfs_reclaim(struct vop_reclaim_args *ap) 288 { 289 struct vnode *vp = ap->a_vp; 290 struct fnode *fp = VTOF(vp); 291 struct ntnode *ip = FTONT(fp); 292 int error; 293 294 dprintf(("ntfs_reclaim: vnode: %p, ntnode: %d\n", vp, ip->i_number)); 295 296 if (ntfs_prtactive && vp->v_usecount != 0) 297 vprint("ntfs_reclaim: pushing active", vp); 298 299 if ((error = ntfs_ntget(ip)) != 0) 300 return (error); 301 302 /* Purge old data structures associated with the inode. */ 303 cache_purge(vp); 304 305 ntfs_frele(fp); 306 ntfs_ntput(ip); 307 vp->v_data = NULL; 308 309 return (0); 310 } 311 312 /* 313 * ntfs_print(struct vnode *a_vp) 314 */ 315 static int 316 ntfs_print(struct vop_print_args *ap) 317 { 318 return (0); 319 } 320 321 /* 322 * Calculate the logical to physical mapping if not done already, 323 * then call the device strategy routine. 324 * 325 * ntfs_strategy(struct buf *a_bp) 326 */ 327 int 328 ntfs_strategy(struct vop_strategy_args *ap) 329 { 330 struct buf *bp = ap->a_bp; 331 struct vnode *vp = bp->b_vp; 332 struct fnode *fp = VTOF(vp); 333 struct ntnode *ip = FTONT(fp); 334 struct ntfsmount *ntmp = ip->i_mp; 335 int error; 336 337 #ifdef __DragonFly__ 338 dprintf(("ntfs_strategy: offset: %d, blkno: %d, lblkno: %d\n", 339 (u_int32_t)bp->b_offset,(u_int32_t)bp->b_blkno, 340 (u_int32_t)bp->b_lblkno)); 341 #else 342 dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n", 343 (u_int32_t)bp->b_blkno, 344 (u_int32_t)bp->b_lblkno)); 345 #endif 346 347 dprintf(("strategy: bcount: %d flags: 0x%lx\n", 348 (u_int32_t)bp->b_bcount,bp->b_flags)); 349 350 if (bp->b_flags & B_READ) { 351 u_int32_t toread; 352 353 if (ntfs_cntob(bp->b_blkno) >= fp->f_size) { 354 clrbuf(bp); 355 error = 0; 356 } else { 357 toread = min(bp->b_bcount, 358 fp->f_size-ntfs_cntob(bp->b_blkno)); 359 dprintf(("ntfs_strategy: toread: %d, fsize: %d\n", 360 toread,(u_int32_t)fp->f_size)); 361 362 error = ntfs_readattr(ntmp, ip, fp->f_attrtype, 363 fp->f_attrname, ntfs_cntob(bp->b_blkno), 364 toread, bp->b_data, NULL); 365 366 if (error) { 367 printf("ntfs_strategy: ntfs_readattr failed\n"); 368 bp->b_error = error; 369 bp->b_flags |= B_ERROR; 370 } 371 372 bzero(bp->b_data + toread, bp->b_bcount - toread); 373 } 374 } else { 375 size_t tmp; 376 u_int32_t towrite; 377 378 if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) { 379 printf("ntfs_strategy: CAN'T EXTEND FILE\n"); 380 bp->b_error = error = EFBIG; 381 bp->b_flags |= B_ERROR; 382 } else { 383 towrite = min(bp->b_bcount, 384 fp->f_size-ntfs_cntob(bp->b_blkno)); 385 dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n", 386 towrite,(u_int32_t)fp->f_size)); 387 388 error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype, 389 fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite, 390 bp->b_data, &tmp, NULL); 391 392 if (error) { 393 printf("ntfs_strategy: ntfs_writeattr fail\n"); 394 bp->b_error = error; 395 bp->b_flags |= B_ERROR; 396 } 397 } 398 } 399 biodone(bp); 400 return (error); 401 } 402 403 /* 404 * ntfs_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, 405 * struct ucred *a_cred) 406 */ 407 static int 408 ntfs_write(struct vop_write_args *ap) 409 { 410 struct vnode *vp = ap->a_vp; 411 struct fnode *fp = VTOF(vp); 412 struct ntnode *ip = FTONT(fp); 413 struct uio *uio = ap->a_uio; 414 struct ntfsmount *ntmp = ip->i_mp; 415 u_int64_t towrite; 416 size_t written; 417 int error; 418 419 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)); 420 dprintf(("ntfs_write: filesize: %d",(u_int32_t)fp->f_size)); 421 422 if (uio->uio_resid + uio->uio_offset > fp->f_size) { 423 printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n"); 424 return (EFBIG); 425 } 426 427 towrite = min(uio->uio_resid, fp->f_size - uio->uio_offset); 428 429 dprintf((", towrite: %d\n",(u_int32_t)towrite)); 430 431 error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype, 432 fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio); 433 #ifdef NTFS_DEBUG 434 if (error) 435 printf("ntfs_write: ntfs_writeattr failed: %d\n", error); 436 #endif 437 438 return (error); 439 } 440 441 /* 442 * ntfs_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred, 443 * struct thread *a_td) 444 */ 445 int 446 ntfs_access(struct vop_access_args *ap) 447 { 448 struct vnode *vp = ap->a_vp; 449 struct ntnode *ip = VTONT(vp); 450 struct ucred *cred = ap->a_cred; 451 mode_t mask, mode = ap->a_mode; 452 gid_t *gp; 453 int i; 454 #ifdef QUOTA 455 int error; 456 #endif 457 458 dprintf(("ntfs_access: %d\n",ip->i_number)); 459 460 /* 461 * Disallow write attempts on read-only file systems; 462 * unless the file is a socket, fifo, or a block or 463 * character device resident on the file system. 464 */ 465 if (mode & VWRITE) { 466 switch ((int)vp->v_type) { 467 case VDIR: 468 case VLNK: 469 case VREG: 470 if (vp->v_mount->mnt_flag & MNT_RDONLY) 471 return (EROFS); 472 #ifdef QUOTA 473 if (error = getinoquota(ip)) 474 return (error); 475 #endif 476 break; 477 } 478 } 479 480 /* Otherwise, user id 0 always gets access. */ 481 if (cred->cr_uid == 0) 482 return (0); 483 484 mask = 0; 485 486 /* Otherwise, check the owner. */ 487 if (cred->cr_uid == ip->i_mp->ntm_uid) { 488 if (mode & VEXEC) 489 mask |= S_IXUSR; 490 if (mode & VREAD) 491 mask |= S_IRUSR; 492 if (mode & VWRITE) 493 mask |= S_IWUSR; 494 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES); 495 } 496 497 /* Otherwise, check the groups. */ 498 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) 499 if (ip->i_mp->ntm_gid == *gp) { 500 if (mode & VEXEC) 501 mask |= S_IXGRP; 502 if (mode & VREAD) 503 mask |= S_IRGRP; 504 if (mode & VWRITE) 505 mask |= S_IWGRP; 506 return ((ip->i_mp->ntm_mode&mask) == mask ? 0 : EACCES); 507 } 508 509 /* Otherwise, check everyone else. */ 510 if (mode & VEXEC) 511 mask |= S_IXOTH; 512 if (mode & VREAD) 513 mask |= S_IROTH; 514 if (mode & VWRITE) 515 mask |= S_IWOTH; 516 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES); 517 } 518 519 /* 520 * Open called. 521 * 522 * Nothing to do. 523 * 524 * ntfs_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred, 525 * struct thread *a_td) 526 */ 527 /* ARGSUSED */ 528 static int 529 ntfs_open(struct vop_open_args *ap) 530 { 531 #if NTFS_DEBUG 532 struct vnode *vp = ap->a_vp; 533 struct ntnode *ip = VTONT(vp); 534 535 printf("ntfs_open: %d\n",ip->i_number); 536 #endif 537 538 /* 539 * Files marked append-only must be opened for appending. 540 */ 541 542 return (0); 543 } 544 545 /* 546 * Close called. 547 * 548 * Update the times on the inode. 549 * 550 * ntfs_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred, 551 * struct thread *a_td) 552 */ 553 /* ARGSUSED */ 554 static int 555 ntfs_close(struct vop_close_args *ap) 556 { 557 #if NTFS_DEBUG 558 struct vnode *vp = ap->a_vp; 559 struct ntnode *ip = VTONT(vp); 560 561 printf("ntfs_close: %d\n",ip->i_number); 562 #endif 563 564 return (0); 565 } 566 567 /* 568 * ntfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, 569 * int *a_ncookies, u_int **cookies) 570 */ 571 int 572 ntfs_readdir(struct vop_readdir_args *ap) 573 { 574 struct vnode *vp = ap->a_vp; 575 struct fnode *fp = VTOF(vp); 576 struct ntnode *ip = FTONT(fp); 577 struct uio *uio = ap->a_uio; 578 struct ntfsmount *ntmp = ip->i_mp; 579 int i, error = 0; 580 u_int32_t faked = 0, num; 581 int ncookies = 0; 582 struct dirent cde; 583 off_t off; 584 585 dprintf(("ntfs_readdir %d off: %d resid: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid)); 586 587 off = uio->uio_offset; 588 589 /* Simulate . in every dir except ROOT */ 590 if( ip->i_number != NTFS_ROOTINO ) { 591 struct dirent dot = { NTFS_ROOTINO, 592 sizeof(struct dirent), DT_DIR, 1, "." }; 593 594 if( uio->uio_offset < sizeof(struct dirent) ) { 595 dot.d_fileno = ip->i_number; 596 error = uiomove((char *)&dot,sizeof(struct dirent),uio); 597 if(error) 598 return (error); 599 600 ncookies ++; 601 } 602 } 603 604 /* Simulate .. in every dir including ROOT */ 605 if( uio->uio_offset < 2 * sizeof(struct dirent) ) { 606 struct dirent dotdot = { NTFS_ROOTINO, 607 sizeof(struct dirent), DT_DIR, 2, ".." }; 608 609 error = uiomove((char *)&dotdot,sizeof(struct dirent),uio); 610 if(error) 611 return (error); 612 613 ncookies ++; 614 } 615 616 faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2; 617 num = uio->uio_offset / sizeof(struct dirent) - faked; 618 619 while( uio->uio_resid >= sizeof(struct dirent) ) { 620 struct attr_indexentry *iep; 621 622 error = ntfs_ntreaddir(ntmp, fp, num, &iep); 623 624 if(error) 625 return (error); 626 627 if( NULL == iep ) 628 break; 629 630 for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent)); 631 iep = NTFS_NEXTREC(iep, struct attr_indexentry *)) 632 { 633 if(!ntfs_isnamepermitted(ntmp,iep)) 634 continue; 635 636 for(i=0; i<iep->ie_fnamelen; i++) { 637 cde.d_name[i] = NTFS_U28(iep->ie_fname[i]); 638 } 639 cde.d_name[i] = '\0'; 640 dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ", 641 num, cde.d_name, iep->ie_fnametype, 642 iep->ie_flag)); 643 cde.d_namlen = iep->ie_fnamelen; 644 cde.d_fileno = iep->ie_number; 645 cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG; 646 cde.d_reclen = sizeof(struct dirent); 647 dprintf(("%s\n", (cde.d_type == DT_DIR) ? "dir":"reg")); 648 649 error = uiomove((char *)&cde, sizeof(struct dirent), uio); 650 if(error) 651 return (error); 652 653 ncookies++; 654 num++; 655 } 656 } 657 658 dprintf(("ntfs_readdir: %d entries (%d bytes) read\n", 659 ncookies,(u_int)(uio->uio_offset - off))); 660 dprintf(("ntfs_readdir: off: %d resid: %d\n", 661 (u_int32_t)uio->uio_offset,uio->uio_resid)); 662 663 if (!error && ap->a_ncookies != NULL) { 664 struct dirent* dpStart; 665 struct dirent* dp; 666 #if defined(__DragonFly__) 667 u_long *cookies; 668 u_long *cookiep; 669 #else /* defined(__NetBSD__) */ 670 off_t *cookies; 671 off_t *cookiep; 672 #endif 673 674 ddprintf(("ntfs_readdir: %d cookies\n",ncookies)); 675 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) 676 panic("ntfs_readdir: unexpected uio from NFS server"); 677 dpStart = (struct dirent *) 678 ((caddr_t)uio->uio_iov->iov_base - 679 (uio->uio_offset - off)); 680 #if defined(__DragonFly__) 681 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), 682 M_TEMP, M_WAITOK); 683 #else /* defined(__NetBSD__) */ 684 MALLOC(cookies, off_t *, ncookies * sizeof(off_t), 685 M_TEMP, M_WAITOK); 686 #endif 687 for (dp = dpStart, cookiep = cookies, i=0; 688 i < ncookies; 689 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) { 690 off += dp->d_reclen; 691 *cookiep++ = (u_int) off; 692 } 693 *ap->a_ncookies = ncookies; 694 *ap->a_cookies = cookies; 695 } 696 /* 697 if (ap->a_eofflag) 698 *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset; 699 */ 700 return (error); 701 } 702 703 /* 704 * ntfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, 705 * struct componentname *a_cnp) 706 */ 707 int 708 ntfs_lookup(struct vop_lookup_args *ap) 709 { 710 struct vnode *dvp = ap->a_dvp; 711 struct ntnode *dip = VTONT(dvp); 712 struct ntfsmount *ntmp = dip->i_mp; 713 struct componentname *cnp = ap->a_cnp; 714 struct ucred *cred = cnp->cn_cred; 715 int error; 716 int lockparent = cnp->cn_flags & CNP_LOCKPARENT; 717 #if NTFS_DEBUG 718 int wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT); 719 #endif 720 dprintf(("ntfs_lookup: \"%.*s\" (%ld bytes) in %d, lp: %d, wp: %d \n", 721 (int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen, 722 dip->i_number, lockparent, wantparent)); 723 724 error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_td); 725 if(error) 726 return (error); 727 728 if ((cnp->cn_flags & CNP_ISLASTCN) && 729 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 730 (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) 731 return (EROFS); 732 733 #ifdef __NetBSD__ 734 /* 735 * We now have a segment name to search for, and a directory 736 * to search. 737 * 738 * Before tediously performing a linear scan of the directory, 739 * check the name cache to see if the directory/name pair 740 * we are looking for is known already. 741 */ 742 if ((error = cache_lookup(ap->a_dvp, NCPNULL, ap->a_vpp, NCPPNULL, cnp)) >= 0) 743 return (error); 744 #endif 745 746 if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 747 dprintf(("ntfs_lookup: faking . directory in %d\n", 748 dip->i_number)); 749 750 vref(dvp); 751 *ap->a_vpp = dvp; 752 error = 0; 753 } else if (cnp->cn_flags & CNP_ISDOTDOT) { 754 struct ntvattr *vap; 755 756 dprintf(("ntfs_lookup: faking .. directory in %d\n", 757 dip->i_number)); 758 759 error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap); 760 if(error) 761 return (error); 762 763 VOP__UNLOCK(dvp,0,cnp->cn_td); 764 cnp->cn_flags |= CNP_PDIRUNLOCK; 765 766 dprintf(("ntfs_lookup: parentdir: %d\n", 767 vap->va_a_name->n_pnumber)); 768 error = VFS_VGET(ntmp->ntm_mountp, 769 vap->va_a_name->n_pnumber,ap->a_vpp); 770 ntfs_ntvattrrele(vap); 771 if (error) { 772 if (VN_LOCK(dvp,LK_EXCLUSIVE|LK_RETRY,cnp->cn_td)==0) 773 cnp->cn_flags &= ~CNP_PDIRUNLOCK; 774 return (error); 775 } 776 777 if (lockparent && (cnp->cn_flags & CNP_ISLASTCN)) { 778 error = VN_LOCK(dvp, LK_EXCLUSIVE, cnp->cn_td); 779 if (error) { 780 vput( *(ap->a_vpp) ); 781 return (error); 782 } 783 cnp->cn_flags &= ~CNP_PDIRUNLOCK; 784 } 785 } else { 786 error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp); 787 if (error) { 788 dprintf(("ntfs_ntlookupfile: returned %d\n", error)); 789 return (error); 790 } 791 792 dprintf(("ntfs_lookup: found ino: %d\n", 793 VTONT(*ap->a_vpp)->i_number)); 794 795 if(!lockparent || !(cnp->cn_flags & CNP_ISLASTCN)) 796 VOP__UNLOCK(dvp, 0, cnp->cn_td); 797 } 798 799 if (cnp->cn_flags & CNP_MAKEENTRY) 800 cache_enter(dvp, NCPNULL, *ap->a_vpp, cnp); 801 802 return (error); 803 } 804 805 #if defined(__DragonFly__) 806 /* 807 * Flush the blocks of a file to disk. 808 * 809 * This function is worthless for vnodes that represent directories. Maybe we 810 * could just do a sync if they try an fsync on a directory file. 811 * 812 * ntfs_fsync(struct vnode *a_vp, struct ucred *a_cred, int a_waitfor, 813 * struct thread *a_td) 814 */ 815 static int 816 ntfs_fsync(struct vop_fsync_args *ap) 817 { 818 return (0); 819 } 820 #endif 821 822 /* 823 * Return POSIX pathconf information applicable to NTFS filesystem 824 */ 825 int 826 ntfs_pathconf(void *v) 827 { 828 struct vop_pathconf_args /* { 829 struct vnode *a_vp; 830 int a_name; 831 register_t *a_retval; 832 } */ *ap = v; 833 834 switch (ap->a_name) { 835 case _PC_LINK_MAX: 836 *ap->a_retval = 1; 837 return (0); 838 case _PC_NAME_MAX: 839 *ap->a_retval = NTFS_MAXFILENAME; 840 return (0); 841 case _PC_PATH_MAX: 842 *ap->a_retval = PATH_MAX; 843 return (0); 844 case _PC_CHOWN_RESTRICTED: 845 *ap->a_retval = 1; 846 return (0); 847 case _PC_NO_TRUNC: 848 *ap->a_retval = 0; 849 return (0); 850 #if defined(__NetBSD__) 851 case _PC_SYNC_IO: 852 *ap->a_retval = 1; 853 return (0); 854 case _PC_FILESIZEBITS: 855 *ap->a_retval = 64; 856 return (0); 857 #endif 858 default: 859 return (EINVAL); 860 } 861 /* NOTREACHED */ 862 } 863 864 /* 865 * Global vfs data structures 866 */ 867 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = { 868 { &vop_default_desc, vop_defaultop }, 869 870 { &vop_getattr_desc, (void *)ntfs_getattr }, 871 { &vop_inactive_desc, (void *)ntfs_inactive }, 872 { &vop_reclaim_desc, (void *)ntfs_reclaim }, 873 { &vop_print_desc, (void *)ntfs_print }, 874 { &vop_pathconf_desc, (void *)ntfs_pathconf }, 875 876 { &vop_islocked_desc, (void *)vop_stdislocked }, 877 { &vop_unlock_desc, (void *)vop_stdunlock }, 878 { &vop_lock_desc, (void *)vop_stdlock }, 879 { &vop_cachedlookup_desc,(void *)ntfs_lookup }, 880 { &vop_lookup_desc, (void *)vfs_cache_lookup }, 881 882 { &vop_access_desc, (void *)ntfs_access }, 883 { &vop_close_desc, (void *)ntfs_close }, 884 { &vop_open_desc, (void *)ntfs_open }, 885 { &vop_readdir_desc, (void *)ntfs_readdir }, 886 { &vop_fsync_desc, (void *)ntfs_fsync }, 887 888 { &vop_bmap_desc, (void *)ntfs_bmap }, 889 { &vop_getpages_desc, (void *)ntfs_getpages }, 890 { &vop_putpages_desc, (void *)ntfs_putpages }, 891 { &vop_strategy_desc, (void *)ntfs_strategy }, 892 { &vop_bwrite_desc, (void *)vop_stdbwrite }, 893 { &vop_read_desc, (void *)ntfs_read }, 894 { &vop_write_desc, (void *)ntfs_write }, 895 896 { NULL, NULL } 897 }; 898 899