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