1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/t_lock.h> 33 #include <sys/systm.h> 34 #include <sys/sysmacros.h> 35 #include <sys/user.h> 36 #include <sys/buf.h> 37 #include <sys/stat.h> 38 #include <sys/vfs.h> 39 #include <sys/vfs_opreg.h> 40 #include <sys/dirent.h> 41 #include <sys/vnode.h> 42 #include <sys/proc.h> 43 #include <sys/file.h> 44 #include <sys/fcntl.h> 45 #include <sys/uio.h> 46 #include <sys/fs/pc_label.h> 47 #include <sys/fs/pc_fs.h> 48 #include <sys/fs/pc_dir.h> 49 #include <sys/fs/pc_node.h> 50 #include <sys/mman.h> 51 #include <sys/pathname.h> 52 #include <sys/vmsystm.h> 53 #include <sys/cmn_err.h> 54 #include <sys/debug.h> 55 #include <sys/statvfs.h> 56 #include <sys/unistd.h> 57 #include <sys/kmem.h> 58 #include <sys/conf.h> 59 #include <sys/flock.h> 60 #include <sys/policy.h> 61 #include <sys/sdt.h> 62 #include <sys/sunddi.h> 63 #include <sys/types.h> 64 #include <sys/errno.h> 65 66 #include <vm/seg.h> 67 #include <vm/page.h> 68 #include <vm/pvn.h> 69 #include <vm/seg_map.h> 70 #include <vm/seg_vn.h> 71 #include <vm/hat.h> 72 #include <vm/as.h> 73 #include <vm/seg_kmem.h> 74 75 #include <fs/fs_subr.h> 76 77 static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct); 78 static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *, 79 caller_context_t *ct); 80 static int pcfs_read(struct vnode *, struct uio *, int, struct cred *, 81 caller_context_t *); 82 static int pcfs_write(struct vnode *, struct uio *, int, struct cred *, 83 caller_context_t *); 84 static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *, 85 caller_context_t *ct); 86 static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *, 87 caller_context_t *); 88 static int pcfs_access(struct vnode *, int, int, struct cred *, 89 caller_context_t *ct); 90 static int pcfs_lookup(struct vnode *, char *, struct vnode **, 91 struct pathname *, int, struct vnode *, struct cred *, 92 caller_context_t *, int *, pathname_t *); 93 static int pcfs_create(struct vnode *, char *, struct vattr *, 94 enum vcexcl, int mode, struct vnode **, struct cred *, int, 95 caller_context_t *, vsecattr_t *); 96 static int pcfs_remove(struct vnode *, char *, struct cred *, 97 caller_context_t *, int); 98 static int pcfs_rename(struct vnode *, char *, struct vnode *, char *, 99 struct cred *, caller_context_t *, int); 100 static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **, 101 struct cred *, caller_context_t *, int, vsecattr_t *); 102 static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *, 103 caller_context_t *, int); 104 static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *, 105 caller_context_t *, int); 106 static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *); 107 static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *); 108 static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *); 109 static int pcfs_space(struct vnode *, int, struct flock64 *, int, 110 offset_t, cred_t *, caller_context_t *); 111 static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[], 112 size_t, struct seg *, caddr_t, enum seg_rw, struct cred *, 113 caller_context_t *); 114 static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *, 115 page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 116 static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *, 117 caller_context_t *); 118 static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t, 119 uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 120 static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t, 121 size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 122 static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t, 123 size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *); 124 static int pcfs_seek(struct vnode *, offset_t, offset_t *, 125 caller_context_t *); 126 static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *, 127 caller_context_t *); 128 129 int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int, 130 struct cred *); 131 static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int); 132 static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf); 133 134 extern krwlock_t pcnodes_lock; 135 136 #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1))) 137 138 /* 139 * vnode op vectors for files and directories. 140 */ 141 struct vnodeops *pcfs_fvnodeops; 142 struct vnodeops *pcfs_dvnodeops; 143 144 const fs_operation_def_t pcfs_fvnodeops_template[] = { 145 VOPNAME_OPEN, { .vop_open = pcfs_open }, 146 VOPNAME_CLOSE, { .vop_close = pcfs_close }, 147 VOPNAME_READ, { .vop_read = pcfs_read }, 148 VOPNAME_WRITE, { .vop_write = pcfs_write }, 149 VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 150 VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 151 VOPNAME_ACCESS, { .vop_access = pcfs_access }, 152 VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 153 VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 154 VOPNAME_FID, { .vop_fid = pcfs_fid }, 155 VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 156 VOPNAME_SPACE, { .vop_space = pcfs_space }, 157 VOPNAME_GETPAGE, { .vop_getpage = pcfs_getpage }, 158 VOPNAME_PUTPAGE, { .vop_putpage = pcfs_putpage }, 159 VOPNAME_MAP, { .vop_map = pcfs_map }, 160 VOPNAME_ADDMAP, { .vop_addmap = pcfs_addmap }, 161 VOPNAME_DELMAP, { .vop_delmap = pcfs_delmap }, 162 VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 163 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 164 NULL, NULL 165 }; 166 167 const fs_operation_def_t pcfs_dvnodeops_template[] = { 168 VOPNAME_OPEN, { .vop_open = pcfs_open }, 169 VOPNAME_CLOSE, { .vop_close = pcfs_close }, 170 VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 171 VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 172 VOPNAME_ACCESS, { .vop_access = pcfs_access }, 173 VOPNAME_LOOKUP, { .vop_lookup = pcfs_lookup }, 174 VOPNAME_CREATE, { .vop_create = pcfs_create }, 175 VOPNAME_REMOVE, { .vop_remove = pcfs_remove }, 176 VOPNAME_RENAME, { .vop_rename = pcfs_rename }, 177 VOPNAME_MKDIR, { .vop_mkdir = pcfs_mkdir }, 178 VOPNAME_RMDIR, { .vop_rmdir = pcfs_rmdir }, 179 VOPNAME_READDIR, { .vop_readdir = pcfs_readdir }, 180 VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 181 VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 182 VOPNAME_FID, { .vop_fid = pcfs_fid }, 183 VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 184 VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 185 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 186 NULL, NULL 187 }; 188 189 190 /*ARGSUSED*/ 191 static int 192 pcfs_open( 193 struct vnode **vpp, 194 int flag, 195 struct cred *cr, 196 caller_context_t *ct) 197 { 198 return (0); 199 } 200 201 /* 202 * files are sync'ed on close to keep floppy up to date 203 */ 204 205 /*ARGSUSED*/ 206 static int 207 pcfs_close( 208 struct vnode *vp, 209 int flag, 210 int count, 211 offset_t offset, 212 struct cred *cr, 213 caller_context_t *ct) 214 { 215 return (0); 216 } 217 218 /*ARGSUSED*/ 219 static int 220 pcfs_read( 221 struct vnode *vp, 222 struct uio *uiop, 223 int ioflag, 224 struct cred *cr, 225 struct caller_context *ct) 226 { 227 struct pcfs *fsp; 228 struct pcnode *pcp; 229 int error; 230 231 fsp = VFSTOPCFS(vp->v_vfsp); 232 if (error = pc_verify(fsp)) 233 return (error); 234 error = pc_lockfs(fsp, 0, 0); 235 if (error) 236 return (error); 237 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 238 pc_unlockfs(fsp); 239 return (EIO); 240 } 241 error = rwpcp(pcp, uiop, UIO_READ, ioflag); 242 if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) { 243 pc_mark_acc(fsp, pcp); 244 } 245 pc_unlockfs(fsp); 246 if (error) { 247 PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error); 248 } 249 return (error); 250 } 251 252 /*ARGSUSED*/ 253 static int 254 pcfs_write( 255 struct vnode *vp, 256 struct uio *uiop, 257 int ioflag, 258 struct cred *cr, 259 struct caller_context *ct) 260 { 261 struct pcfs *fsp; 262 struct pcnode *pcp; 263 int error; 264 265 fsp = VFSTOPCFS(vp->v_vfsp); 266 if (error = pc_verify(fsp)) 267 return (error); 268 error = pc_lockfs(fsp, 0, 0); 269 if (error) 270 return (error); 271 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 272 pc_unlockfs(fsp); 273 return (EIO); 274 } 275 if (ioflag & FAPPEND) { 276 /* 277 * in append mode start at end of file. 278 */ 279 uiop->uio_loffset = pcp->pc_size; 280 } 281 error = rwpcp(pcp, uiop, UIO_WRITE, ioflag); 282 pcp->pc_flags |= PC_MOD; 283 pc_mark_mod(fsp, pcp); 284 if (ioflag & (FSYNC|FDSYNC)) 285 (void) pc_nodeupdate(pcp); 286 287 pc_unlockfs(fsp); 288 if (error) { 289 PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error); 290 } 291 return (error); 292 } 293 294 /* 295 * read or write a vnode 296 */ 297 static int 298 rwpcp( 299 struct pcnode *pcp, 300 struct uio *uio, 301 enum uio_rw rw, 302 int ioflag) 303 { 304 struct vnode *vp = PCTOV(pcp); 305 struct pcfs *fsp; 306 daddr_t bn; /* phys block number */ 307 int n; 308 offset_t off; 309 caddr_t base; 310 int mapon, pagecreate; 311 int newpage; 312 int error = 0; 313 rlim64_t limit = uio->uio_llimit; 314 int oresid = uio->uio_resid; 315 316 /* 317 * If the filesystem was umounted by force, return immediately. 318 */ 319 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 320 return (EIO); 321 322 PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp, 323 uio->uio_loffset, uio->uio_resid, pcp->pc_size); 324 325 ASSERT(rw == UIO_READ || rw == UIO_WRITE); 326 ASSERT(vp->v_type == VREG); 327 328 if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) { 329 return (0); 330 } 331 332 if (uio->uio_loffset < 0) 333 return (EINVAL); 334 335 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 336 limit = MAXOFFSET_T; 337 338 if (uio->uio_loffset >= limit && rw == UIO_WRITE) { 339 proc_t *p = ttoproc(curthread); 340 341 mutex_enter(&p->p_lock); 342 (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls, 343 p, RCA_UNSAFE_SIGINFO); 344 mutex_exit(&p->p_lock); 345 return (EFBIG); 346 } 347 348 /* the following condition will occur only for write */ 349 350 if (uio->uio_loffset >= UINT32_MAX) 351 return (EFBIG); 352 353 if (uio->uio_resid == 0) 354 return (0); 355 356 if (limit > UINT32_MAX) 357 limit = UINT32_MAX; 358 359 fsp = VFSTOPCFS(vp->v_vfsp); 360 if (fsp->pcfs_flags & PCFS_IRRECOV) 361 return (EIO); 362 363 do { 364 /* 365 * Assignments to "n" in this block may appear 366 * to overflow in some cases. However, after careful 367 * analysis it was determined that all assignments to 368 * "n" serve only to make "n" smaller. Since "n" 369 * starts out as no larger than MAXBSIZE, "int" is 370 * safe. 371 */ 372 off = uio->uio_loffset & MAXBMASK; 373 mapon = (int)(uio->uio_loffset & MAXBOFFSET); 374 n = MIN(MAXBSIZE - mapon, uio->uio_resid); 375 if (rw == UIO_READ) { 376 offset_t diff; 377 378 diff = pcp->pc_size - uio->uio_loffset; 379 if (diff <= 0) 380 return (0); 381 if (diff < n) 382 n = (int)diff; 383 } 384 /* 385 * Compare limit with the actual offset + n, not the 386 * rounded down offset "off" or we will overflow 387 * the maximum file size after all. 388 */ 389 if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) { 390 if (uio->uio_loffset >= limit) { 391 error = EFBIG; 392 break; 393 } 394 n = (int)(limit - uio->uio_loffset); 395 } 396 397 /* 398 * Touch the page and fault it in if it is not in 399 * core before segmap_getmapflt can lock it. This 400 * is to avoid the deadlock if the buffer is mapped 401 * to the same file through mmap which we want to 402 * write to. 403 */ 404 uio_prefaultpages((long)n, uio); 405 406 base = segmap_getmap(segkmap, vp, (u_offset_t)off); 407 pagecreate = 0; 408 newpage = 0; 409 if (rw == UIO_WRITE) { 410 /* 411 * If PAGESIZE < MAXBSIZE, perhaps we ought to deal 412 * with one page at a time, instead of one MAXBSIZE 413 * at a time, so we can fully explore pagecreate 414 * optimization?? 415 */ 416 if (uio->uio_loffset + n > pcp->pc_size) { 417 uint_t ncl, lcn; 418 419 ncl = (uint_t)howmany((offset_t)pcp->pc_size, 420 fsp->pcfs_clsize); 421 if (uio->uio_loffset > pcp->pc_size && 422 ncl < (uint_t)howmany(uio->uio_loffset, 423 fsp->pcfs_clsize)) { 424 /* 425 * Allocate and zerofill skipped 426 * clusters. This may not be worth the 427 * effort since a small lseek beyond 428 * eof but still within the cluster 429 * will not be zeroed out. 430 */ 431 lcn = pc_lblkno(fsp, uio->uio_loffset); 432 error = pc_balloc(pcp, (daddr_t)lcn, 433 1, &bn); 434 ncl = lcn + 1; 435 } 436 if (!error && 437 ncl < (uint_t)howmany(uio->uio_loffset + n, 438 fsp->pcfs_clsize)) 439 /* 440 * allocate clusters w/o zerofill 441 */ 442 error = pc_balloc(pcp, 443 (daddr_t)pc_lblkno(fsp, 444 uio->uio_loffset + n - 1), 445 0, &bn); 446 447 pcp->pc_flags |= PC_CHG; 448 449 if (error) { 450 pc_cluster32_t ncl; 451 int nerror; 452 453 /* 454 * figure out new file size from 455 * cluster chain length. If this 456 * is detected to loop, the chain 457 * is corrupted and we'd better 458 * keep our fingers off that file. 459 */ 460 nerror = pc_fileclsize(fsp, 461 pcp->pc_scluster, &ncl); 462 if (nerror) { 463 PC_DPRINTF1(2, 464 "cluster chain " 465 "corruption, " 466 "scluster=%d\n", 467 pcp->pc_scluster); 468 pcp->pc_size = 0; 469 pcp->pc_flags |= PC_INVAL; 470 error = nerror; 471 (void) segmap_release(segkmap, 472 base, 0); 473 break; 474 } 475 pcp->pc_size = fsp->pcfs_clsize * ncl; 476 477 if (error == ENOSPC && 478 (pcp->pc_size - uio->uio_loffset) 479 > 0) { 480 PC_DPRINTF3(2, "rwpcp ENOSPC " 481 "off=%lld n=%d size=%d\n", 482 uio->uio_loffset, 483 n, pcp->pc_size); 484 n = (int)(pcp->pc_size - 485 uio->uio_loffset); 486 } else { 487 PC_DPRINTF1(1, 488 "rwpcp error1=%d\n", error); 489 (void) segmap_release(segkmap, 490 base, 0); 491 break; 492 } 493 } else { 494 pcp->pc_size = 495 (uint_t)(uio->uio_loffset + n); 496 } 497 if (mapon == 0) { 498 newpage = segmap_pagecreate(segkmap, 499 base, (size_t)n, 0); 500 pagecreate = 1; 501 } 502 } else if (n == MAXBSIZE) { 503 newpage = segmap_pagecreate(segkmap, base, 504 (size_t)n, 0); 505 pagecreate = 1; 506 } 507 } 508 error = uiomove(base + mapon, (size_t)n, rw, uio); 509 510 if (pagecreate && uio->uio_loffset < 511 roundup(off + mapon + n, PAGESIZE)) { 512 offset_t nzero, nmoved; 513 514 nmoved = uio->uio_loffset - (off + mapon); 515 nzero = roundup(mapon + n, PAGESIZE) - nmoved; 516 (void) kzero(base + mapon + nmoved, (size_t)nzero); 517 } 518 519 /* 520 * Unlock the pages which have been allocated by 521 * page_create_va() in segmap_pagecreate(). 522 */ 523 if (newpage) { 524 segmap_pageunlock(segkmap, base, (size_t)n, 525 rw == UIO_WRITE ? S_WRITE : S_READ); 526 } 527 528 if (error) { 529 PC_DPRINTF1(1, "rwpcp error2=%d\n", error); 530 /* 531 * If we failed on a write, we may have already 532 * allocated file blocks as well as pages. It's hard 533 * to undo the block allocation, but we must be sure 534 * to invalidate any pages that may have been 535 * allocated. 536 */ 537 if (rw == UIO_WRITE) 538 (void) segmap_release(segkmap, base, SM_INVAL); 539 else 540 (void) segmap_release(segkmap, base, 0); 541 } else { 542 uint_t flags = 0; 543 544 if (rw == UIO_READ) { 545 if (n + mapon == MAXBSIZE || 546 uio->uio_loffset == pcp->pc_size) 547 flags = SM_DONTNEED; 548 } else if (ioflag & (FSYNC|FDSYNC)) { 549 flags = SM_WRITE; 550 } else if (n + mapon == MAXBSIZE) { 551 flags = SM_WRITE|SM_ASYNC|SM_DONTNEED; 552 } 553 error = segmap_release(segkmap, base, flags); 554 } 555 556 } while (error == 0 && uio->uio_resid > 0 && n != 0); 557 558 if (oresid != uio->uio_resid) 559 error = 0; 560 return (error); 561 } 562 563 /*ARGSUSED*/ 564 static int 565 pcfs_getattr( 566 struct vnode *vp, 567 struct vattr *vap, 568 int flags, 569 struct cred *cr, 570 caller_context_t *ct) 571 { 572 struct pcnode *pcp; 573 struct pcfs *fsp; 574 int error; 575 char attr; 576 struct pctime atime; 577 int64_t unixtime; 578 579 PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp); 580 581 fsp = VFSTOPCFS(vp->v_vfsp); 582 error = pc_lockfs(fsp, 0, 0); 583 if (error) 584 return (error); 585 586 /* 587 * Note that we don't check for "invalid node" (PC_INVAL) here 588 * only in order to make stat() succeed. We allow no I/O on such 589 * a node, but do allow to check for its existence. 590 */ 591 if ((pcp = VTOPC(vp)) == NULL) { 592 pc_unlockfs(fsp); 593 return (EIO); 594 } 595 /* 596 * Copy from pcnode. 597 */ 598 vap->va_type = vp->v_type; 599 attr = pcp->pc_entry.pcd_attr; 600 if (PCA_IS_HIDDEN(fsp, attr)) 601 vap->va_mode = 0; 602 else if (attr & PCA_LABEL) 603 vap->va_mode = 0444; 604 else if (attr & PCA_RDONLY) 605 vap->va_mode = 0555; 606 else if (fsp->pcfs_flags & PCFS_BOOTPART) { 607 vap->va_mode = 0755; 608 } else { 609 vap->va_mode = 0777; 610 } 611 612 if (attr & PCA_DIR) 613 vap->va_mode |= S_IFDIR; 614 else 615 vap->va_mode |= S_IFREG; 616 if (fsp->pcfs_flags & PCFS_BOOTPART) { 617 vap->va_uid = 0; 618 vap->va_gid = 0; 619 } else { 620 vap->va_uid = crgetuid(cr); 621 vap->va_gid = crgetgid(cr); 622 } 623 vap->va_fsid = vp->v_vfsp->vfs_dev; 624 vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno, 625 pcp->pc_eoffset, pcp->pc_entry.pcd_attr, 626 pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp)); 627 vap->va_nlink = 1; 628 vap->va_size = (u_offset_t)pcp->pc_size; 629 vap->va_rdev = 0; 630 vap->va_nblocks = 631 (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE); 632 vap->va_blksize = fsp->pcfs_clsize; 633 634 /* 635 * FAT root directories have no timestamps. In order not to return 636 * "time zero" (1/1/1970), we record the time of the mount and give 637 * that. This breaks less expectations. 638 */ 639 if (vp->v_flag & VROOT) { 640 vap->va_mtime = fsp->pcfs_mounttime; 641 vap->va_atime = fsp->pcfs_mounttime; 642 vap->va_ctime = fsp->pcfs_mounttime; 643 pc_unlockfs(fsp); 644 return (0); 645 } 646 647 pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime); 648 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 649 if (unixtime > INT32_MAX) 650 DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime); 651 unixtime = MIN(unixtime, INT32_MAX); 652 } else if (unixtime > INT32_MAX && 653 get_udatamodel() == DATAMODEL_ILP32) { 654 pc_unlockfs(fsp); 655 DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime); 656 return (EOVERFLOW); 657 } 658 659 vap->va_mtime.tv_sec = (time_t)unixtime; 660 vap->va_mtime.tv_nsec = 0; 661 662 /* 663 * FAT doesn't know about POSIX ctime. 664 * Best approximation is to always set it to mtime. 665 */ 666 vap->va_ctime = vap->va_mtime; 667 668 /* 669 * FAT only stores "last access date". If that's the 670 * same as the date of last modification then the time 671 * of last access is known. Otherwise, use midnight. 672 */ 673 atime.pct_date = pcp->pc_entry.pcd_ladate; 674 if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date) 675 atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time; 676 else 677 atime.pct_time = 0; 678 pc_pcttotv(&atime, &unixtime); 679 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 680 if (unixtime > INT32_MAX) 681 DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime); 682 unixtime = MIN(unixtime, INT32_MAX); 683 } else if (unixtime > INT32_MAX && 684 get_udatamodel() == DATAMODEL_ILP32) { 685 pc_unlockfs(fsp); 686 DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime); 687 return (EOVERFLOW); 688 } 689 690 vap->va_atime.tv_sec = (time_t)unixtime; 691 vap->va_atime.tv_nsec = 0; 692 693 pc_unlockfs(fsp); 694 return (0); 695 } 696 697 698 /*ARGSUSED*/ 699 static int 700 pcfs_setattr( 701 struct vnode *vp, 702 struct vattr *vap, 703 int flags, 704 struct cred *cr, 705 caller_context_t *ct) 706 { 707 struct pcnode *pcp; 708 mode_t mask = vap->va_mask; 709 int error; 710 struct pcfs *fsp; 711 timestruc_t now, *timep; 712 713 PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask); 714 /* 715 * cannot set these attributes 716 */ 717 if (mask & (AT_NOSET | AT_UID | AT_GID)) { 718 return (EINVAL); 719 } 720 /* 721 * pcfs_setattr is now allowed on directories to avoid silly warnings 722 * from 'tar' when it tries to set times on a directory, and console 723 * printf's on the NFS server when it gets EINVAL back on such a 724 * request. One possible problem with that since a directory entry 725 * identifies a file, '.' and all the '..' entries in subdirectories 726 * may get out of sync when the directory is updated since they're 727 * treated like separate files. We could fix that by looking for 728 * '.' and giving it the same attributes, and then looking for 729 * all the subdirectories and updating '..', but that's pretty 730 * expensive for something that doesn't seem likely to matter. 731 */ 732 /* can't do some ops on directories anyway */ 733 if ((vp->v_type == VDIR) && 734 (mask & AT_SIZE)) { 735 return (EINVAL); 736 } 737 738 fsp = VFSTOPCFS(vp->v_vfsp); 739 error = pc_lockfs(fsp, 0, 0); 740 if (error) 741 return (error); 742 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 743 pc_unlockfs(fsp); 744 return (EIO); 745 } 746 747 if (fsp->pcfs_flags & PCFS_BOOTPART) { 748 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 749 pc_unlockfs(fsp); 750 return (EACCES); 751 } 752 } 753 754 /* 755 * Change file access modes. 756 * If nobody has write permission, file is marked readonly. 757 * Otherwise file is writable by anyone. 758 */ 759 if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) { 760 if ((vap->va_mode & 0222) == 0) 761 pcp->pc_entry.pcd_attr |= PCA_RDONLY; 762 else 763 pcp->pc_entry.pcd_attr &= ~PCA_RDONLY; 764 pcp->pc_flags |= PC_CHG; 765 } 766 /* 767 * Truncate file. Must have write permission. 768 */ 769 if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) { 770 if (pcp->pc_entry.pcd_attr & PCA_RDONLY) { 771 error = EACCES; 772 goto out; 773 } 774 if (vap->va_size > UINT32_MAX) { 775 error = EFBIG; 776 goto out; 777 } 778 error = pc_truncate(pcp, (uint_t)vap->va_size); 779 780 if (error) 781 goto out; 782 783 if (vap->va_size == 0) 784 vnevent_truncate(vp, ct); 785 } 786 /* 787 * Change file modified times. 788 */ 789 if (mask & (AT_MTIME | AT_CTIME)) { 790 /* 791 * If SysV-compatible option to set access and 792 * modified times if privileged, owner, or write access, 793 * use current time rather than va_mtime. 794 * 795 * XXX - va_mtime.tv_sec == -1 flags this. 796 */ 797 timep = &vap->va_mtime; 798 if (vap->va_mtime.tv_sec == -1) { 799 gethrestime(&now); 800 timep = &now; 801 } 802 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 803 timep->tv_sec > INT32_MAX) { 804 error = EOVERFLOW; 805 goto out; 806 } 807 error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime); 808 if (error) 809 goto out; 810 pcp->pc_flags |= PC_CHG; 811 } 812 /* 813 * Change file access times. 814 */ 815 if (mask & AT_ATIME) { 816 /* 817 * If SysV-compatible option to set access and 818 * modified times if privileged, owner, or write access, 819 * use current time rather than va_mtime. 820 * 821 * XXX - va_atime.tv_sec == -1 flags this. 822 */ 823 struct pctime atime; 824 825 timep = &vap->va_atime; 826 if (vap->va_atime.tv_sec == -1) { 827 gethrestime(&now); 828 timep = &now; 829 } 830 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 831 timep->tv_sec > INT32_MAX) { 832 error = EOVERFLOW; 833 goto out; 834 } 835 error = pc_tvtopct(timep, &atime); 836 if (error) 837 goto out; 838 pcp->pc_entry.pcd_ladate = atime.pct_date; 839 pcp->pc_flags |= PC_CHG; 840 } 841 out: 842 pc_unlockfs(fsp); 843 return (error); 844 } 845 846 847 /*ARGSUSED*/ 848 static int 849 pcfs_access( 850 struct vnode *vp, 851 int mode, 852 int flags, 853 struct cred *cr, 854 caller_context_t *ct) 855 { 856 struct pcnode *pcp; 857 struct pcfs *fsp; 858 859 860 fsp = VFSTOPCFS(vp->v_vfsp); 861 862 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 863 return (EIO); 864 if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY)) 865 return (EACCES); 866 867 /* 868 * If this is a boot partition, privileged users have full access while 869 * others have read-only access. 870 */ 871 if (fsp->pcfs_flags & PCFS_BOOTPART) { 872 if ((mode & VWRITE) && 873 secpolicy_pcfs_modify_bootpartition(cr) != 0) 874 return (EACCES); 875 } 876 return (0); 877 } 878 879 880 /*ARGSUSED*/ 881 static int 882 pcfs_fsync( 883 struct vnode *vp, 884 int syncflag, 885 struct cred *cr, 886 caller_context_t *ct) 887 { 888 struct pcfs *fsp; 889 struct pcnode *pcp; 890 int error; 891 892 fsp = VFSTOPCFS(vp->v_vfsp); 893 if (error = pc_verify(fsp)) 894 return (error); 895 error = pc_lockfs(fsp, 0, 0); 896 if (error) 897 return (error); 898 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 899 pc_unlockfs(fsp); 900 return (EIO); 901 } 902 rw_enter(&pcnodes_lock, RW_WRITER); 903 error = pc_nodesync(pcp); 904 rw_exit(&pcnodes_lock); 905 pc_unlockfs(fsp); 906 return (error); 907 } 908 909 910 /*ARGSUSED*/ 911 static void 912 pcfs_inactive( 913 struct vnode *vp, 914 struct cred *cr, 915 caller_context_t *ct) 916 { 917 struct pcnode *pcp; 918 struct pcfs *fsp; 919 int error; 920 921 fsp = VFSTOPCFS(vp->v_vfsp); 922 error = pc_lockfs(fsp, 0, 1); 923 924 /* 925 * If the filesystem was umounted by force, all dirty 926 * pages associated with this vnode are invalidated 927 * and then the vnode will be freed. 928 */ 929 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 930 pcp = VTOPC(vp); 931 if (vn_has_cached_data(vp)) { 932 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 933 pcfs_putapage, B_INVAL, (struct cred *)NULL); 934 } 935 remque(pcp); 936 if (error == 0) 937 pc_unlockfs(fsp); 938 vn_free(vp); 939 kmem_free(pcp, sizeof (struct pcnode)); 940 VFS_RELE(PCFSTOVFS(fsp)); 941 return; 942 } 943 944 mutex_enter(&vp->v_lock); 945 ASSERT(vp->v_count >= 1); 946 if (vp->v_count > 1) { 947 vp->v_count--; /* release our hold from vn_rele */ 948 mutex_exit(&vp->v_lock); 949 pc_unlockfs(fsp); 950 return; 951 } 952 mutex_exit(&vp->v_lock); 953 954 /* 955 * Check again to confirm that no intervening I/O error 956 * with a subsequent pc_diskchanged() call has released 957 * the pcnode. If it has then release the vnode as above. 958 */ 959 pcp = VTOPC(vp); 960 if (pcp == NULL || pcp->pc_flags & PC_INVAL) { 961 if (vn_has_cached_data(vp)) 962 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 963 pcfs_putapage, B_INVAL | B_TRUNC, 964 (struct cred *)NULL); 965 } 966 967 if (pcp == NULL) { 968 vn_free(vp); 969 } else { 970 pc_rele(pcp); 971 } 972 973 if (!error) 974 pc_unlockfs(fsp); 975 } 976 977 /*ARGSUSED*/ 978 static int 979 pcfs_lookup( 980 struct vnode *dvp, 981 char *nm, 982 struct vnode **vpp, 983 struct pathname *pnp, 984 int flags, 985 struct vnode *rdir, 986 struct cred *cr, 987 caller_context_t *ct, 988 int *direntflags, 989 pathname_t *realpnp) 990 { 991 struct pcfs *fsp; 992 struct pcnode *pcp; 993 int error; 994 995 /* 996 * If the filesystem was umounted by force, return immediately. 997 */ 998 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 999 return (EIO); 1000 1001 /* 1002 * verify that the dvp is still valid on the disk 1003 */ 1004 fsp = VFSTOPCFS(dvp->v_vfsp); 1005 if (error = pc_verify(fsp)) 1006 return (error); 1007 error = pc_lockfs(fsp, 0, 0); 1008 if (error) 1009 return (error); 1010 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 1011 pc_unlockfs(fsp); 1012 return (EIO); 1013 } 1014 /* 1015 * Null component name is a synonym for directory being searched. 1016 */ 1017 if (*nm == '\0') { 1018 VN_HOLD(dvp); 1019 *vpp = dvp; 1020 pc_unlockfs(fsp); 1021 return (0); 1022 } 1023 1024 error = pc_dirlook(VTOPC(dvp), nm, &pcp); 1025 if (!error) { 1026 *vpp = PCTOV(pcp); 1027 pcp->pc_flags |= PC_EXTERNAL; 1028 } 1029 pc_unlockfs(fsp); 1030 return (error); 1031 } 1032 1033 1034 /*ARGSUSED*/ 1035 static int 1036 pcfs_create( 1037 struct vnode *dvp, 1038 char *nm, 1039 struct vattr *vap, 1040 enum vcexcl exclusive, 1041 int mode, 1042 struct vnode **vpp, 1043 struct cred *cr, 1044 int flag, 1045 caller_context_t *ct, 1046 vsecattr_t *vsecp) 1047 { 1048 int error; 1049 struct pcnode *pcp; 1050 struct vnode *vp; 1051 struct pcfs *fsp; 1052 1053 /* 1054 * can't create directories. use pcfs_mkdir. 1055 * can't create anything other than files. 1056 */ 1057 if (vap->va_type == VDIR) 1058 return (EISDIR); 1059 else if (vap->va_type != VREG) 1060 return (EINVAL); 1061 1062 pcp = NULL; 1063 fsp = VFSTOPCFS(dvp->v_vfsp); 1064 error = pc_lockfs(fsp, 0, 0); 1065 if (error) 1066 return (error); 1067 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 1068 pc_unlockfs(fsp); 1069 return (EIO); 1070 } 1071 1072 if (fsp->pcfs_flags & PCFS_BOOTPART) { 1073 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1074 pc_unlockfs(fsp); 1075 return (EACCES); 1076 } 1077 } 1078 1079 if (*nm == '\0') { 1080 /* 1081 * Null component name refers to the directory itself. 1082 */ 1083 VN_HOLD(dvp); 1084 pcp = VTOPC(dvp); 1085 error = EEXIST; 1086 } else { 1087 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 1088 } 1089 /* 1090 * if file exists and this is a nonexclusive create, 1091 * check for access permissions 1092 */ 1093 if (error == EEXIST) { 1094 vp = PCTOV(pcp); 1095 if (exclusive == NONEXCL) { 1096 if (vp->v_type == VDIR) { 1097 error = EISDIR; 1098 } else if (mode) { 1099 error = pcfs_access(PCTOV(pcp), mode, 0, 1100 cr, ct); 1101 } else { 1102 error = 0; 1103 } 1104 } 1105 if (error) { 1106 VN_RELE(PCTOV(pcp)); 1107 } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 1108 (vap->va_size == 0)) { 1109 error = pc_truncate(pcp, 0L); 1110 if (error) { 1111 VN_RELE(PCTOV(pcp)); 1112 } else { 1113 vnevent_create(PCTOV(pcp), ct); 1114 } 1115 } 1116 } 1117 if (error) { 1118 pc_unlockfs(fsp); 1119 return (error); 1120 } 1121 *vpp = PCTOV(pcp); 1122 pcp->pc_flags |= PC_EXTERNAL; 1123 pc_unlockfs(fsp); 1124 return (error); 1125 } 1126 1127 /*ARGSUSED*/ 1128 static int 1129 pcfs_remove( 1130 struct vnode *vp, 1131 char *nm, 1132 struct cred *cr, 1133 caller_context_t *ct, 1134 int flags) 1135 { 1136 struct pcfs *fsp; 1137 struct pcnode *pcp; 1138 int error; 1139 1140 fsp = VFSTOPCFS(vp->v_vfsp); 1141 if (error = pc_verify(fsp)) 1142 return (error); 1143 error = pc_lockfs(fsp, 0, 0); 1144 if (error) 1145 return (error); 1146 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 1147 pc_unlockfs(fsp); 1148 return (EIO); 1149 } 1150 if (fsp->pcfs_flags & PCFS_BOOTPART) { 1151 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1152 pc_unlockfs(fsp); 1153 return (EACCES); 1154 } 1155 } 1156 error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct); 1157 pc_unlockfs(fsp); 1158 return (error); 1159 } 1160 1161 /* 1162 * Rename a file or directory 1163 * This rename is restricted to only rename files within a directory. 1164 * XX should make rename more general 1165 */ 1166 /*ARGSUSED*/ 1167 static int 1168 pcfs_rename( 1169 struct vnode *sdvp, /* old (source) parent vnode */ 1170 char *snm, /* old (source) entry name */ 1171 struct vnode *tdvp, /* new (target) parent vnode */ 1172 char *tnm, /* new (target) entry name */ 1173 struct cred *cr, 1174 caller_context_t *ct, 1175 int flags) 1176 { 1177 struct pcfs *fsp; 1178 struct pcnode *dp; /* parent pcnode */ 1179 struct pcnode *tdp; 1180 int error; 1181 1182 fsp = VFSTOPCFS(sdvp->v_vfsp); 1183 if (error = pc_verify(fsp)) 1184 return (error); 1185 1186 /* 1187 * make sure we can muck with this directory. 1188 */ 1189 error = pcfs_access(sdvp, VWRITE, 0, cr, ct); 1190 if (error) { 1191 return (error); 1192 } 1193 error = pc_lockfs(fsp, 0, 0); 1194 if (error) 1195 return (error); 1196 if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) || 1197 (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) { 1198 pc_unlockfs(fsp); 1199 return (EIO); 1200 } 1201 error = pc_rename(dp, tdp, snm, tnm, ct); 1202 pc_unlockfs(fsp); 1203 return (error); 1204 } 1205 1206 /*ARGSUSED*/ 1207 static int 1208 pcfs_mkdir( 1209 struct vnode *dvp, 1210 char *nm, 1211 struct vattr *vap, 1212 struct vnode **vpp, 1213 struct cred *cr, 1214 caller_context_t *ct, 1215 int flags, 1216 vsecattr_t *vsecp) 1217 { 1218 struct pcfs *fsp; 1219 struct pcnode *pcp; 1220 int error; 1221 1222 fsp = VFSTOPCFS(dvp->v_vfsp); 1223 if (error = pc_verify(fsp)) 1224 return (error); 1225 error = pc_lockfs(fsp, 0, 0); 1226 if (error) 1227 return (error); 1228 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 1229 pc_unlockfs(fsp); 1230 return (EIO); 1231 } 1232 1233 if (fsp->pcfs_flags & PCFS_BOOTPART) { 1234 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1235 pc_unlockfs(fsp); 1236 return (EACCES); 1237 } 1238 } 1239 1240 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 1241 1242 if (!error) { 1243 pcp -> pc_flags |= PC_EXTERNAL; 1244 *vpp = PCTOV(pcp); 1245 } else if (error == EEXIST) { 1246 VN_RELE(PCTOV(pcp)); 1247 } 1248 pc_unlockfs(fsp); 1249 return (error); 1250 } 1251 1252 /*ARGSUSED*/ 1253 static int 1254 pcfs_rmdir( 1255 struct vnode *dvp, 1256 char *nm, 1257 struct vnode *cdir, 1258 struct cred *cr, 1259 caller_context_t *ct, 1260 int flags) 1261 { 1262 struct pcfs *fsp; 1263 struct pcnode *pcp; 1264 int error; 1265 1266 fsp = VFSTOPCFS(dvp -> v_vfsp); 1267 if (error = pc_verify(fsp)) 1268 return (error); 1269 if (error = pc_lockfs(fsp, 0, 0)) 1270 return (error); 1271 1272 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 1273 pc_unlockfs(fsp); 1274 return (EIO); 1275 } 1276 1277 if (fsp->pcfs_flags & PCFS_BOOTPART) { 1278 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1279 pc_unlockfs(fsp); 1280 return (EACCES); 1281 } 1282 } 1283 1284 error = pc_dirremove(pcp, nm, cdir, VDIR, ct); 1285 pc_unlockfs(fsp); 1286 return (error); 1287 } 1288 1289 /* 1290 * read entries in a directory. 1291 * we must convert pc format to unix format 1292 */ 1293 1294 /*ARGSUSED*/ 1295 static int 1296 pcfs_readdir( 1297 struct vnode *dvp, 1298 struct uio *uiop, 1299 struct cred *cr, 1300 int *eofp, 1301 caller_context_t *ct, 1302 int flags) 1303 { 1304 struct pcnode *pcp; 1305 struct pcfs *fsp; 1306 struct pcdir *ep; 1307 struct buf *bp = NULL; 1308 offset_t offset; 1309 int boff; 1310 struct pc_dirent lbp; 1311 struct pc_dirent *ld = &lbp; 1312 int error; 1313 1314 /* 1315 * If the filesystem was umounted by force, return immediately. 1316 */ 1317 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1318 return (EIO); 1319 1320 if ((uiop->uio_iovcnt != 1) || 1321 (uiop->uio_loffset % sizeof (struct pcdir)) != 0) { 1322 return (EINVAL); 1323 } 1324 fsp = VFSTOPCFS(dvp->v_vfsp); 1325 /* 1326 * verify that the dp is still valid on the disk 1327 */ 1328 if (error = pc_verify(fsp)) { 1329 return (error); 1330 } 1331 error = pc_lockfs(fsp, 0, 0); 1332 if (error) 1333 return (error); 1334 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 1335 pc_unlockfs(fsp); 1336 return (EIO); 1337 } 1338 1339 bzero(ld, sizeof (*ld)); 1340 1341 if (eofp != NULL) 1342 *eofp = 0; 1343 offset = uiop->uio_loffset; 1344 1345 if (dvp->v_flag & VROOT) { 1346 /* 1347 * kludge up entries for "." and ".." in the root. 1348 */ 1349 if (offset == 0) { 1350 (void) strcpy(ld->d_name, "."); 1351 ld->d_reclen = DIRENT64_RECLEN(1); 1352 ld->d_off = (off64_t)sizeof (struct pcdir); 1353 ld->d_ino = (ino64_t)UINT_MAX; 1354 if (ld->d_reclen > uiop->uio_resid) { 1355 pc_unlockfs(fsp); 1356 return (ENOSPC); 1357 } 1358 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 1359 uiop->uio_loffset = ld->d_off; 1360 offset = uiop->uio_loffset; 1361 } 1362 if (offset == sizeof (struct pcdir)) { 1363 (void) strcpy(ld->d_name, ".."); 1364 ld->d_reclen = DIRENT64_RECLEN(2); 1365 if (ld->d_reclen > uiop->uio_resid) { 1366 pc_unlockfs(fsp); 1367 return (ENOSPC); 1368 } 1369 ld->d_off = (off64_t)(uiop->uio_loffset + 1370 sizeof (struct pcdir)); 1371 ld->d_ino = (ino64_t)UINT_MAX; 1372 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 1373 uiop->uio_loffset = ld->d_off; 1374 offset = uiop->uio_loffset; 1375 } 1376 offset -= 2 * sizeof (struct pcdir); 1377 /* offset now has the real offset value into directory file */ 1378 } 1379 1380 for (;;) { 1381 boff = pc_blkoff(fsp, offset); 1382 if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 1383 if (bp != NULL) { 1384 brelse(bp); 1385 bp = NULL; 1386 } 1387 error = pc_blkatoff(pcp, offset, &bp, &ep); 1388 if (error) { 1389 if (error == ENOENT) { 1390 error = 0; 1391 if (eofp) 1392 *eofp = 1; 1393 } 1394 break; 1395 } 1396 } 1397 if (ep->pcd_filename[0] == PCD_UNUSED) { 1398 if (eofp) 1399 *eofp = 1; 1400 break; 1401 } 1402 /* 1403 * Don't display label because it may contain funny characters. 1404 */ 1405 if (ep->pcd_filename[0] == PCD_ERASED) { 1406 uiop->uio_loffset += sizeof (struct pcdir); 1407 offset += sizeof (struct pcdir); 1408 ep++; 1409 continue; 1410 } 1411 if (PCDL_IS_LFN(ep)) { 1412 if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) != 1413 0) 1414 break; 1415 continue; 1416 } 1417 1418 if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0) 1419 break; 1420 } 1421 if (bp) 1422 brelse(bp); 1423 pc_unlockfs(fsp); 1424 return (error); 1425 } 1426 1427 1428 /* 1429 * Called from pvn_getpages or pcfs_getpage to get a particular page. 1430 * When we are called the pcfs is already locked. 1431 */ 1432 /*ARGSUSED*/ 1433 static int 1434 pcfs_getapage( 1435 struct vnode *vp, 1436 u_offset_t off, 1437 size_t len, 1438 uint_t *protp, 1439 page_t *pl[], /* NULL if async IO is requested */ 1440 size_t plsz, 1441 struct seg *seg, 1442 caddr_t addr, 1443 enum seg_rw rw, 1444 struct cred *cr) 1445 { 1446 struct pcnode *pcp; 1447 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1448 struct vnode *devvp; 1449 page_t *pp; 1450 page_t *pagefound; 1451 int err; 1452 1453 /* 1454 * If the filesystem was umounted by force, return immediately. 1455 */ 1456 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1457 return (EIO); 1458 1459 PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n", 1460 (void *)vp, off, len); 1461 1462 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 1463 return (EIO); 1464 devvp = fsp->pcfs_devvp; 1465 1466 /* pcfs doesn't do readaheads */ 1467 if (pl == NULL) 1468 return (0); 1469 1470 pl[0] = NULL; 1471 err = 0; 1472 /* 1473 * If the accessed time on the pcnode has not already been 1474 * set elsewhere (e.g. for read/setattr) we set the time now. 1475 * This gives us approximate modified times for mmap'ed files 1476 * which are accessed via loads in the user address space. 1477 */ 1478 if ((pcp->pc_flags & PC_ACC) == 0 && 1479 ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) { 1480 pc_mark_acc(fsp, pcp); 1481 } 1482 reread: 1483 if ((pagefound = page_exists(vp, off)) == NULL) { 1484 /* 1485 * Need to really do disk IO to get the page(s). 1486 */ 1487 struct buf *bp; 1488 daddr_t lbn, bn; 1489 u_offset_t io_off; 1490 size_t io_len; 1491 u_offset_t lbnoff, xferoffset; 1492 u_offset_t pgoff; 1493 uint_t xfersize; 1494 int err1; 1495 1496 lbn = pc_lblkno(fsp, off); 1497 lbnoff = off & ~(fsp->pcfs_clsize - 1); 1498 xferoffset = off & ~(fsp->pcfs_secsize - 1); 1499 1500 pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, 1501 off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0); 1502 if (pp == NULL) 1503 /* 1504 * XXX - If pcfs is made MT-hot, this should go 1505 * back to reread. 1506 */ 1507 panic("pcfs_getapage pvn_read_kluster"); 1508 1509 for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size; 1510 pgoff += xfersize, 1511 lbn += howmany(xfersize, fsp->pcfs_clsize), 1512 lbnoff += xfersize, xferoffset += xfersize) { 1513 /* 1514 * read as many contiguous blocks as possible to 1515 * fill this page 1516 */ 1517 xfersize = PAGESIZE - pgoff; 1518 err1 = pc_bmap(pcp, lbn, &bn, &xfersize); 1519 if (err1) { 1520 PC_DPRINTF1(1, "pc_getapage err=%d", err1); 1521 err = err1; 1522 goto out; 1523 } 1524 bp = pageio_setup(pp, xfersize, devvp, B_READ); 1525 bp->b_edev = devvp->v_rdev; 1526 bp->b_dev = cmpdev(devvp->v_rdev); 1527 bp->b_blkno = bn + btodt(xferoffset - lbnoff); 1528 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 1529 bp->b_file = vp; 1530 bp->b_offset = (offset_t)(off + pgoff); 1531 1532 (void) bdev_strategy(bp); 1533 1534 lwp_stat_update(LWP_STAT_INBLK, 1); 1535 1536 if (err == 0) 1537 err = biowait(bp); 1538 else 1539 (void) biowait(bp); 1540 pageio_done(bp); 1541 if (err) 1542 goto out; 1543 } 1544 if (pgoff < PAGESIZE) { 1545 pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff); 1546 } 1547 pvn_plist_init(pp, pl, plsz, off, io_len, rw); 1548 } 1549 out: 1550 if (err) { 1551 if (pp != NULL) 1552 pvn_read_done(pp, B_ERROR); 1553 return (err); 1554 } 1555 1556 if (pagefound) { 1557 /* 1558 * Page exists in the cache, acquire the "shared" 1559 * lock. If this fails, go back to reread. 1560 */ 1561 if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) { 1562 goto reread; 1563 } 1564 pl[0] = pp; 1565 pl[1] = NULL; 1566 } 1567 return (err); 1568 } 1569 1570 /* 1571 * Return all the pages from [off..off+len] in given file 1572 */ 1573 /* ARGSUSED */ 1574 static int 1575 pcfs_getpage( 1576 struct vnode *vp, 1577 offset_t off, 1578 size_t len, 1579 uint_t *protp, 1580 page_t *pl[], 1581 size_t plsz, 1582 struct seg *seg, 1583 caddr_t addr, 1584 enum seg_rw rw, 1585 struct cred *cr, 1586 caller_context_t *ct) 1587 { 1588 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1589 int err; 1590 1591 PC_DPRINTF0(6, "pcfs_getpage\n"); 1592 if (err = pc_verify(fsp)) 1593 return (err); 1594 if (vp->v_flag & VNOMAP) 1595 return (ENOSYS); 1596 ASSERT(off <= UINT32_MAX); 1597 err = pc_lockfs(fsp, 0, 0); 1598 if (err) 1599 return (err); 1600 if (protp != NULL) 1601 *protp = PROT_ALL; 1602 1603 ASSERT((off & PAGEOFFSET) == 0); 1604 if (len <= PAGESIZE) { 1605 err = pcfs_getapage(vp, off, len, protp, pl, 1606 plsz, seg, addr, rw, cr); 1607 } else { 1608 err = pvn_getpages(pcfs_getapage, vp, off, 1609 len, protp, pl, plsz, seg, addr, rw, cr); 1610 } 1611 pc_unlockfs(fsp); 1612 return (err); 1613 } 1614 1615 1616 /* 1617 * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} 1618 * If len == 0, do from off to EOF. 1619 * 1620 * The normal cases should be len == 0 & off == 0 (entire vp list), 1621 * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE 1622 * (from pageout). 1623 * 1624 */ 1625 /*ARGSUSED*/ 1626 static int 1627 pcfs_putpage( 1628 struct vnode *vp, 1629 offset_t off, 1630 size_t len, 1631 int flags, 1632 struct cred *cr, 1633 caller_context_t *ct) 1634 { 1635 struct pcnode *pcp; 1636 page_t *pp; 1637 struct pcfs *fsp; 1638 u_offset_t io_off; 1639 size_t io_len; 1640 offset_t eoff; 1641 int err; 1642 1643 /* 1644 * If the filesystem was umounted by force, return immediately. 1645 */ 1646 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1647 return (EIO); 1648 1649 PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp); 1650 if (vp->v_flag & VNOMAP) 1651 return (ENOSYS); 1652 1653 fsp = VFSTOPCFS(vp->v_vfsp); 1654 1655 if (err = pc_verify(fsp)) 1656 return (err); 1657 if ((pcp = VTOPC(vp)) == NULL) { 1658 PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp); 1659 return (EIO); 1660 } 1661 if (pcp->pc_flags & PC_INVAL) 1662 return (EIO); 1663 1664 if (curproc == proc_pageout) { 1665 /* 1666 * XXX - This is a quick hack to avoid blocking 1667 * pageout. Also to avoid pcfs_getapage deadlocking 1668 * with putpage when memory is running out, 1669 * since we only have one global lock and we don't 1670 * support async putpage. 1671 * It should be fixed someday. 1672 * 1673 * Interestingly, this used to be a test of NOMEMWAIT(). 1674 * We only ever got here once pcfs started supporting 1675 * NFS sharing, and then only because the NFS server 1676 * threads seem to do writes in sched's process context. 1677 * Since everyone else seems to just care about pageout, 1678 * the test was changed to look for pageout directly. 1679 */ 1680 return (ENOMEM); 1681 } 1682 1683 ASSERT(off <= UINT32_MAX); 1684 1685 flags &= ~B_ASYNC; /* XXX should fix this later */ 1686 1687 err = pc_lockfs(fsp, 0, 0); 1688 if (err) 1689 return (err); 1690 if (!vn_has_cached_data(vp) || off >= pcp->pc_size) { 1691 pc_unlockfs(fsp); 1692 return (0); 1693 } 1694 1695 if (len == 0) { 1696 /* 1697 * Search the entire vp list for pages >= off 1698 */ 1699 err = pvn_vplist_dirty(vp, off, 1700 pcfs_putapage, flags, cr); 1701 } else { 1702 eoff = off + len; 1703 1704 for (io_off = off; io_off < eoff && 1705 io_off < pcp->pc_size; io_off += io_len) { 1706 /* 1707 * If we are not invalidating, synchronously 1708 * freeing or writing pages use the routine 1709 * page_lookup_nowait() to prevent reclaiming 1710 * them from the free list. 1711 */ 1712 if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { 1713 pp = page_lookup(vp, io_off, 1714 (flags & (B_INVAL | B_FREE)) ? 1715 SE_EXCL : SE_SHARED); 1716 } else { 1717 pp = page_lookup_nowait(vp, io_off, 1718 (flags & B_FREE) ? SE_EXCL : SE_SHARED); 1719 } 1720 1721 if (pp == NULL || pvn_getdirty(pp, flags) == 0) 1722 io_len = PAGESIZE; 1723 else { 1724 err = pcfs_putapage(vp, pp, &io_off, &io_len, 1725 flags, cr); 1726 if (err != 0) 1727 break; 1728 /* 1729 * "io_off" and "io_len" are returned as 1730 * the range of pages we actually wrote. 1731 * This allows us to skip ahead more quickly 1732 * since several pages may've been dealt 1733 * with by this iteration of the loop. 1734 */ 1735 } 1736 } 1737 } 1738 if (err == 0 && (flags & B_INVAL) && 1739 off == 0 && len == 0 && vn_has_cached_data(vp)) { 1740 /* 1741 * If doing "invalidation", make sure that 1742 * all pages on the vnode list are actually 1743 * gone. 1744 */ 1745 cmn_err(CE_PANIC, 1746 "pcfs_putpage: B_INVAL, pages not gone"); 1747 } else if (err) { 1748 PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err); 1749 } 1750 pc_unlockfs(fsp); 1751 return (err); 1752 } 1753 1754 /* 1755 * Write out a single page, possibly klustering adjacent dirty pages. 1756 */ 1757 /*ARGSUSED*/ 1758 int 1759 pcfs_putapage( 1760 struct vnode *vp, 1761 page_t *pp, 1762 u_offset_t *offp, 1763 size_t *lenp, 1764 int flags, 1765 struct cred *cr) 1766 { 1767 struct pcnode *pcp; 1768 struct pcfs *fsp; 1769 struct vnode *devvp; 1770 size_t io_len; 1771 daddr_t bn; 1772 u_offset_t lbn, lbnoff, xferoffset; 1773 uint_t pgoff, xfersize; 1774 int err = 0; 1775 u_offset_t io_off; 1776 1777 pcp = VTOPC(vp); 1778 fsp = VFSTOPCFS(vp->v_vfsp); 1779 devvp = fsp->pcfs_devvp; 1780 1781 /* 1782 * If the modified time on the inode has not already been 1783 * set elsewhere (e.g. for write/setattr) and this is not 1784 * a call from msync (B_FORCE) we set the time now. 1785 * This gives us approximate modified times for mmap'ed files 1786 * which are modified via stores in the user address space. 1787 */ 1788 if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) { 1789 pcp->pc_flags |= PC_MOD; 1790 pc_mark_mod(fsp, pcp); 1791 } 1792 pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset, 1793 PAGESIZE, flags); 1794 1795 if (fsp->pcfs_flags & PCFS_IRRECOV) { 1796 goto out; 1797 } 1798 1799 PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off); 1800 1801 lbn = pc_lblkno(fsp, io_off); 1802 lbnoff = io_off & ~(fsp->pcfs_clsize - 1); 1803 xferoffset = io_off & ~(fsp->pcfs_secsize - 1); 1804 1805 for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size; 1806 pgoff += xfersize, 1807 lbn += howmany(xfersize, fsp->pcfs_clsize), 1808 lbnoff += xfersize, xferoffset += xfersize) { 1809 1810 struct buf *bp; 1811 int err1; 1812 1813 /* 1814 * write as many contiguous blocks as possible from this page 1815 */ 1816 xfersize = io_len - pgoff; 1817 err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize); 1818 if (err1) { 1819 err = err1; 1820 goto out; 1821 } 1822 bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags); 1823 bp->b_edev = devvp->v_rdev; 1824 bp->b_dev = cmpdev(devvp->v_rdev); 1825 bp->b_blkno = bn + btodt(xferoffset - lbnoff); 1826 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 1827 bp->b_file = vp; 1828 bp->b_offset = (offset_t)(io_off + pgoff); 1829 1830 (void) bdev_strategy(bp); 1831 1832 lwp_stat_update(LWP_STAT_OUBLK, 1); 1833 1834 if (err == 0) 1835 err = biowait(bp); 1836 else 1837 (void) biowait(bp); 1838 pageio_done(bp); 1839 } 1840 pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags); 1841 pp = NULL; 1842 1843 out: 1844 if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) { 1845 pvn_write_done(pp, B_WRITE | flags); 1846 } else if (err != 0 && pp != NULL) { 1847 pvn_write_done(pp, B_ERROR | B_WRITE | flags); 1848 } 1849 1850 if (offp) 1851 *offp = io_off; 1852 if (lenp) 1853 *lenp = io_len; 1854 PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n", 1855 (void *)vp, (void *)pp, io_off, io_len); 1856 if (err) { 1857 PC_DPRINTF1(1, "pcfs_putapage err=%d", err); 1858 } 1859 return (err); 1860 } 1861 1862 /*ARGSUSED*/ 1863 static int 1864 pcfs_map( 1865 struct vnode *vp, 1866 offset_t off, 1867 struct as *as, 1868 caddr_t *addrp, 1869 size_t len, 1870 uchar_t prot, 1871 uchar_t maxprot, 1872 uint_t flags, 1873 struct cred *cr, 1874 caller_context_t *ct) 1875 { 1876 struct segvn_crargs vn_a; 1877 int error; 1878 1879 PC_DPRINTF0(6, "pcfs_map\n"); 1880 if (vp->v_flag & VNOMAP) 1881 return (ENOSYS); 1882 1883 if (off > UINT32_MAX || off + len > UINT32_MAX) 1884 return (ENXIO); 1885 1886 as_rangelock(as); 1887 error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags); 1888 if (error != 0) { 1889 as_rangeunlock(as); 1890 return (error); 1891 } 1892 1893 vn_a.vp = vp; 1894 vn_a.offset = off; 1895 vn_a.type = flags & MAP_TYPE; 1896 vn_a.prot = prot; 1897 vn_a.maxprot = maxprot; 1898 vn_a.flags = flags & ~MAP_TYPE; 1899 vn_a.cred = cr; 1900 vn_a.amp = NULL; 1901 vn_a.szc = 0; 1902 vn_a.lgrp_mem_policy_flags = 0; 1903 1904 error = as_map(as, *addrp, len, segvn_create, &vn_a); 1905 as_rangeunlock(as); 1906 return (error); 1907 } 1908 1909 /* ARGSUSED */ 1910 static int 1911 pcfs_seek( 1912 struct vnode *vp, 1913 offset_t ooff, 1914 offset_t *noffp, 1915 caller_context_t *ct) 1916 { 1917 if (*noffp < 0) 1918 return (EINVAL); 1919 else if (*noffp > MAXOFFSET_T) 1920 return (EINVAL); 1921 else 1922 return (0); 1923 } 1924 1925 /* ARGSUSED */ 1926 static int 1927 pcfs_addmap( 1928 struct vnode *vp, 1929 offset_t off, 1930 struct as *as, 1931 caddr_t addr, 1932 size_t len, 1933 uchar_t prot, 1934 uchar_t maxprot, 1935 uint_t flags, 1936 struct cred *cr, 1937 caller_context_t *ct) 1938 { 1939 if (vp->v_flag & VNOMAP) 1940 return (ENOSYS); 1941 return (0); 1942 } 1943 1944 /*ARGSUSED*/ 1945 static int 1946 pcfs_delmap( 1947 struct vnode *vp, 1948 offset_t off, 1949 struct as *as, 1950 caddr_t addr, 1951 size_t len, 1952 uint_t prot, 1953 uint_t maxprot, 1954 uint_t flags, 1955 struct cred *cr, 1956 caller_context_t *ct) 1957 { 1958 if (vp->v_flag & VNOMAP) 1959 return (ENOSYS); 1960 return (0); 1961 } 1962 1963 /* 1964 * POSIX pathconf() support. 1965 */ 1966 /* ARGSUSED */ 1967 static int 1968 pcfs_pathconf( 1969 struct vnode *vp, 1970 int cmd, 1971 ulong_t *valp, 1972 struct cred *cr, 1973 caller_context_t *ct) 1974 { 1975 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1976 1977 switch (cmd) { 1978 case _PC_LINK_MAX: 1979 *valp = 1; 1980 return (0); 1981 1982 case _PC_CASE_BEHAVIOR: 1983 return (EINVAL); 1984 1985 case _PC_FILESIZEBITS: 1986 /* 1987 * Both FAT16 and FAT32 support 4GB - 1 byte for file size. 1988 * FAT12 can only go up to the maximum filesystem capacity 1989 * which is ~509MB. 1990 */ 1991 *valp = IS_FAT12(fsp) ? 30 : 33; 1992 return (0); 1993 1994 case _PC_TIMESTAMP_RESOLUTION: 1995 /* 1996 * PCFS keeps track of modification times, it its own 1997 * internal format, to a resolution of 2 seconds. 1998 * Since 2000 million is representable in an int32_t 1999 * without overflow (or becoming negative), we allow 2000 * this value to be returned. 2001 */ 2002 *valp = 2000000000L; 2003 return (0); 2004 2005 default: 2006 return (fs_pathconf(vp, cmd, valp, cr, ct)); 2007 } 2008 2009 } 2010 2011 /* ARGSUSED */ 2012 static int 2013 pcfs_space( 2014 struct vnode *vp, 2015 int cmd, 2016 struct flock64 *bfp, 2017 int flag, 2018 offset_t offset, 2019 cred_t *cr, 2020 caller_context_t *ct) 2021 { 2022 struct vattr vattr; 2023 int error; 2024 2025 if (cmd != F_FREESP) 2026 return (EINVAL); 2027 2028 if ((error = convoff(vp, bfp, 0, offset)) == 0) { 2029 if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX)) 2030 return (EFBIG); 2031 /* 2032 * we only support the special case of l_len == 0, 2033 * meaning free to end of file at this moment. 2034 */ 2035 if (bfp->l_len != 0) 2036 return (EINVAL); 2037 vattr.va_mask = AT_SIZE; 2038 vattr.va_size = bfp->l_start; 2039 error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct); 2040 } 2041 return (error); 2042 } 2043 2044 /* 2045 * Break up 'len' chars from 'buf' into a long file name chunk. 2046 * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy. 2047 */ 2048 void 2049 set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len) 2050 { 2051 int i; 2052 2053 ASSERT(buf != NULL); 2054 2055 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) { 2056 if (len > 0) { 2057 ep->pcdl_firstfilename[i] = *buf++; 2058 ep->pcdl_firstfilename[i + 1] = *buf++; 2059 len -= 2; 2060 } else { 2061 ep->pcdl_firstfilename[i] = (uchar_t)0xff; 2062 ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff; 2063 } 2064 } 2065 2066 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) { 2067 if (len > 0) { 2068 ep->pcdl_secondfilename[i] = *buf++; 2069 ep->pcdl_secondfilename[i + 1] = *buf++; 2070 len -= 2; 2071 } else { 2072 ep->pcdl_secondfilename[i] = (uchar_t)0xff; 2073 ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff; 2074 } 2075 } 2076 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) { 2077 if (len > 0) { 2078 ep->pcdl_thirdfilename[i] = *buf++; 2079 ep->pcdl_thirdfilename[i + 1] = *buf++; 2080 len -= 2; 2081 } else { 2082 ep->pcdl_thirdfilename[i] = (uchar_t)0xff; 2083 ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff; 2084 } 2085 } 2086 } 2087 2088 /* 2089 * Extract the characters from the long filename chunk into 'buf'. 2090 * Return the number of characters extracted. 2091 */ 2092 static int 2093 get_long_fn_chunk(struct pcdir_lfn *ep, char *buf) 2094 { 2095 char *tmp = buf; 2096 int i; 2097 2098 /* Copy all the names, no filtering now */ 2099 2100 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) { 2101 *tmp = ep->pcdl_firstfilename[i]; 2102 *(tmp + 1) = ep->pcdl_firstfilename[i + 1]; 2103 2104 if ((*tmp == '\0') && (*(tmp+1) == '\0')) 2105 return (tmp - buf); 2106 } 2107 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) { 2108 *tmp = ep->pcdl_secondfilename[i]; 2109 *(tmp + 1) = ep->pcdl_secondfilename[i + 1]; 2110 2111 if ((*tmp == '\0') && (*(tmp+1) == '\0')) 2112 return (tmp - buf); 2113 } 2114 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) { 2115 *tmp = ep->pcdl_thirdfilename[i]; 2116 *(tmp + 1) = ep->pcdl_thirdfilename[i + 1]; 2117 2118 if ((*tmp == '\0') && (*(tmp+1) == '\0')) 2119 return (tmp - buf); 2120 } 2121 return (tmp - buf); 2122 } 2123 2124 2125 /* 2126 * Checksum the passed in short filename. 2127 * This is used to validate each component of the long name to make 2128 * sure the long name is valid (it hasn't been "detached" from the 2129 * short filename). This algorithm was found in FreeBSD. 2130 * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank) 2131 */ 2132 2133 uchar_t 2134 pc_checksum_long_fn(char *name, char *ext) 2135 { 2136 uchar_t c; 2137 char b[11]; 2138 2139 bcopy(name, b, 8); 2140 bcopy(ext, b+8, 3); 2141 2142 c = b[0]; 2143 c = ((c << 7) | (c >> 1)) + b[1]; 2144 c = ((c << 7) | (c >> 1)) + b[2]; 2145 c = ((c << 7) | (c >> 1)) + b[3]; 2146 c = ((c << 7) | (c >> 1)) + b[4]; 2147 c = ((c << 7) | (c >> 1)) + b[5]; 2148 c = ((c << 7) | (c >> 1)) + b[6]; 2149 c = ((c << 7) | (c >> 1)) + b[7]; 2150 c = ((c << 7) | (c >> 1)) + b[8]; 2151 c = ((c << 7) | (c >> 1)) + b[9]; 2152 c = ((c << 7) | (c >> 1)) + b[10]; 2153 2154 return (c); 2155 } 2156 2157 /* 2158 * Read a chunk of long filename entries into 'namep'. 2159 * Return with offset pointing to short entry (on success), or next 2160 * entry to read (if this wasn't a valid lfn really). 2161 * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for 2162 * a long filename. 2163 * 2164 * Can also be called with a NULL namep, in which case it just returns 2165 * whether this was really a valid long filename and consumes it 2166 * (used by pc_dirempty()). 2167 */ 2168 int 2169 pc_extract_long_fn(struct pcnode *pcp, char *namep, 2170 struct pcdir **epp, offset_t *offset, struct buf **bp) 2171 { 2172 struct pcdir *ep = *epp; 2173 struct pcdir_lfn *lep = (struct pcdir_lfn *)ep; 2174 struct vnode *dvp = PCTOV(pcp); 2175 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2176 char *lfn; 2177 char *lfn_base; 2178 int boff; 2179 int i, cs; 2180 char *buf; 2181 uchar_t cksum; 2182 int detached = 0; 2183 int error = 0; 2184 int foldcase; 2185 int count = 0; 2186 size_t u16l = 0, u8l = 0; 2187 char *outbuf; 2188 size_t ret, inlen, outlen; 2189 2190 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 2191 lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 2192 lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t); 2193 *lfn = '\0'; 2194 *(lfn + 1) = '\0'; 2195 cksum = lep->pcdl_checksum; 2196 2197 buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 2198 for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) { 2199 /* read next block if necessary */ 2200 boff = pc_blkoff(fsp, *offset); 2201 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 2202 if (*bp != NULL) { 2203 brelse(*bp); 2204 *bp = NULL; 2205 } 2206 error = pc_blkatoff(pcp, *offset, bp, &ep); 2207 if (error) { 2208 kmem_free(lfn_base, PCMAXNAM_UTF16); 2209 kmem_free(buf, PCMAXNAM_UTF16); 2210 return (error); 2211 } 2212 lep = (struct pcdir_lfn *)ep; 2213 } 2214 /* can this happen? Bad fs? */ 2215 if (!PCDL_IS_LFN((struct pcdir *)lep)) { 2216 detached = 1; 2217 break; 2218 } 2219 if (cksum != lep->pcdl_checksum) 2220 detached = 1; 2221 /* process current entry */ 2222 cs = get_long_fn_chunk(lep, buf); 2223 count += cs; 2224 for (; cs > 0; cs--) { 2225 /* see if we underflow */ 2226 if (lfn >= lfn_base) 2227 *--lfn = buf[cs - 1]; 2228 else 2229 detached = 1; 2230 } 2231 lep++; 2232 *offset += sizeof (struct pcdir); 2233 } 2234 kmem_free(buf, PCMAXNAM_UTF16); 2235 /* read next block if necessary */ 2236 boff = pc_blkoff(fsp, *offset); 2237 ep = (struct pcdir *)lep; 2238 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 2239 if (*bp != NULL) { 2240 brelse(*bp); 2241 *bp = NULL; 2242 } 2243 error = pc_blkatoff(pcp, *offset, bp, &ep); 2244 if (error) { 2245 kmem_free(lfn_base, PCMAXNAM_UTF16); 2246 return (error); 2247 } 2248 } 2249 /* should be on the short one */ 2250 if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) || 2251 (ep->pcd_filename[0] == PCD_ERASED))) { 2252 detached = 1; 2253 } 2254 if (detached || 2255 (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) || 2256 !pc_valid_long_fn(lfn, 0)) { 2257 /* 2258 * process current entry again. This may end up another lfn 2259 * or a short name. 2260 */ 2261 *epp = ep; 2262 kmem_free(lfn_base, PCMAXNAM_UTF16); 2263 return (EINVAL); 2264 } 2265 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 2266 /* 2267 * Don't display label because it may contain 2268 * funny characters. 2269 */ 2270 *offset += sizeof (struct pcdir); 2271 ep++; 2272 *epp = ep; 2273 kmem_free(lfn_base, PCMAXNAM_UTF16); 2274 return (EINVAL); 2275 } 2276 if (namep) { 2277 u16l = count / 2; 2278 u8l = PCMAXNAMLEN; 2279 error = uconv_u16tou8((const uint16_t *)lfn, &u16l, 2280 (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN); 2281 /* 2282 * uconv_u16tou8() will catch conversion errors including 2283 * the case where there is not enough room to write the 2284 * converted result and the u8l will never go over the given 2285 * PCMAXNAMLEN. 2286 */ 2287 if (error != 0) { 2288 kmem_free(lfn_base, PCMAXNAM_UTF16); 2289 return (EINVAL); 2290 } 2291 namep[u8l] = '\0'; 2292 if (foldcase) { 2293 inlen = strlen(namep); 2294 outlen = PCMAXNAMLEN; 2295 outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP); 2296 ret = u8_textprep_str(namep, &inlen, outbuf, 2297 &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST, 2298 &error); 2299 if (ret == -1) { 2300 kmem_free(outbuf, PCMAXNAMLEN + 1); 2301 kmem_free(lfn_base, PCMAXNAM_UTF16); 2302 return (EINVAL); 2303 } 2304 outbuf[PCMAXNAMLEN - outlen] = '\0'; 2305 (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1); 2306 kmem_free(outbuf, PCMAXNAMLEN + 1); 2307 } 2308 } 2309 kmem_free(lfn_base, PCMAXNAM_UTF16); 2310 *epp = ep; 2311 return (0); 2312 } 2313 /* 2314 * Read a long filename into the pc_dirent structure and copy it out. 2315 */ 2316 int 2317 pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 2318 struct pcdir **epp, offset_t *offset, struct buf **bp) 2319 { 2320 struct pcdir *ep; 2321 struct pcnode *pcp = VTOPC(dvp); 2322 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2323 offset_t uiooffset = uiop->uio_loffset; 2324 int error = 0; 2325 offset_t oldoffset; 2326 2327 oldoffset = *offset; 2328 error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp); 2329 if (error) { 2330 if (error == EINVAL) { 2331 uiop->uio_loffset += *offset - oldoffset; 2332 return (0); 2333 } else 2334 return (error); 2335 } 2336 2337 ep = *epp; 2338 uiop->uio_loffset += *offset - oldoffset; 2339 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 2340 if (ld->d_reclen > uiop->uio_resid) { 2341 uiop->uio_loffset = uiooffset; 2342 return (ENOSPC); 2343 } 2344 ld->d_off = uiop->uio_loffset + sizeof (struct pcdir); 2345 ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 2346 pc_blkoff(fsp, *offset), ep->pcd_attr, 2347 pc_getstartcluster(fsp, ep), pc_direntpersec(fsp)); 2348 (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop); 2349 uiop->uio_loffset = ld->d_off; 2350 *offset += sizeof (struct pcdir); 2351 ep++; 2352 *epp = ep; 2353 return (0); 2354 } 2355 2356 /* 2357 * Read a short filename into the pc_dirent structure and copy it out. 2358 */ 2359 int 2360 pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 2361 struct pcdir **epp, offset_t *offset, struct buf **bp) 2362 { 2363 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2364 int boff = pc_blkoff(fsp, *offset); 2365 struct pcdir *ep = *epp; 2366 offset_t oldoffset = uiop->uio_loffset; 2367 int error; 2368 int foldcase; 2369 2370 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 2371 uiop->uio_loffset += sizeof (struct pcdir); 2372 *offset += sizeof (struct pcdir); 2373 ep++; 2374 *epp = ep; 2375 return (0); 2376 } 2377 ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 2378 boff, ep->pcd_attr, pc_getstartcluster(fsp, ep), 2379 pc_direntpersec(fsp)); 2380 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 2381 error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0], 2382 &ep->pcd_ext[0], foldcase); 2383 if (error == 0) { 2384 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 2385 if (ld->d_reclen > uiop->uio_resid) { 2386 uiop->uio_loffset = oldoffset; 2387 return (ENOSPC); 2388 } 2389 ld->d_off = (off64_t)(uiop->uio_loffset + 2390 sizeof (struct pcdir)); 2391 (void) uiomove((caddr_t)ld, 2392 ld->d_reclen, UIO_READ, uiop); 2393 uiop->uio_loffset = ld->d_off; 2394 } else { 2395 uiop->uio_loffset += sizeof (struct pcdir); 2396 } 2397 *offset += sizeof (struct pcdir); 2398 ep++; 2399 *epp = ep; 2400 return (0); 2401 } 2402 2403 /* ARGSUSED */ 2404 static int 2405 pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct) 2406 { 2407 struct pc_fid *pcfid; 2408 struct pcnode *pcp; 2409 struct pcfs *fsp; 2410 int error; 2411 2412 fsp = VFSTOPCFS(vp->v_vfsp); 2413 if (fsp == NULL) 2414 return (EIO); 2415 error = pc_lockfs(fsp, 0, 0); 2416 if (error) 2417 return (error); 2418 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2419 pc_unlockfs(fsp); 2420 return (EIO); 2421 } 2422 if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) { 2423 fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 2424 pc_unlockfs(fsp); 2425 return (ENOSPC); 2426 } 2427 2428 pcfid = (struct pc_fid *)fidp; 2429 bzero(pcfid, sizeof (struct pc_fid)); 2430 pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 2431 if (vp->v_flag & VROOT) { 2432 pcfid->pcfid_block = 0; 2433 pcfid->pcfid_offset = 0; 2434 pcfid->pcfid_ctime = 0; 2435 } else { 2436 pcfid->pcfid_block = pcp->pc_eblkno; 2437 pcfid->pcfid_offset = pcp->pc_eoffset; 2438 pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time; 2439 } 2440 pc_unlockfs(fsp); 2441 return (0); 2442 } 2443