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