1 /* $Id$ */ 2 /* $NetBSD: msdosfs_vnops.c,v 1.20 1994/08/21 18:44:13 ws Exp $ */ 3 4 /*- 5 * Copyright (C) 1994 Wolfgang Solfrank. 6 * Copyright (C) 1994 TooLs GmbH. 7 * All rights reserved. 8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /* 36 * Written by Paul Popelka (paulp@uts.amdahl.com) 37 * 38 * You can do anything you want with this software, just don't say you wrote 39 * it, and don't remove this notice. 40 * 41 * This software is provided "as is". 42 * 43 * The author supplies this software to be publicly redistributed on the 44 * understanding that the author is not responsible for the correct 45 * functioning of this software in any circumstances and is not liable for 46 * any damages caused by this software. 47 * 48 * October 1992 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/namei.h> 54 #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ 55 #include <sys/kernel.h> 56 #include <sys/file.h> /* define FWRITE ... */ 57 #include <sys/stat.h> 58 #include <sys/buf.h> 59 #include <sys/proc.h> 60 #include <sys/mount.h> 61 #include <sys/vnode.h> 62 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 63 #include <sys/malloc.h> 64 #include <sys/dir.h> /* defines dirent structure */ 65 66 #include <msdosfs/bpb.h> 67 #include <msdosfs/direntry.h> 68 #include <msdosfs/denode.h> 69 #include <msdosfs/msdosfsmount.h> 70 #include <msdosfs/fat.h> 71 /* 72 * Some general notes: 73 * 74 * In the ufs filesystem the inodes, superblocks, and indirect blocks are 75 * read/written using the vnode for the filesystem. Blocks that represent 76 * the contents of a file are read/written using the vnode for the file 77 * (including directories when they are read/written as files). This 78 * presents problems for the dos filesystem because data that should be in 79 * an inode (if dos had them) resides in the directory itself. Since we 80 * must update directory entries without the benefit of having the vnode 81 * for the directory we must use the vnode for the filesystem. This means 82 * that when a directory is actually read/written (via read, write, or 83 * readdir, or seek) we must use the vnode for the filesystem instead of 84 * the vnode for the directory as would happen in ufs. This is to insure we 85 * retreive the correct block from the buffer cache since the hash value is 86 * based upon the vnode address and the desired block number. 87 */ 88 89 /* 90 * Create a regular file. On entry the directory to contain the file being 91 * created is locked. We must release before we return. We must also free 92 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 93 * only if the SAVESTART bit in cn_flags is clear on success. 94 */ 95 int 96 msdosfs_create(ap) 97 struct vop_create_args /* { 98 struct vnode *a_dvp; 99 struct vnode **a_vpp; 100 struct componentname *a_cnp; 101 struct vattr *a_vap; 102 } */ *ap; 103 { 104 struct componentname *cnp = ap->a_cnp; 105 struct denode ndirent; 106 struct denode *dep; 107 struct denode *pdep = VTODE(ap->a_dvp); 108 struct timespec ts; 109 int error; 110 111 #ifdef MSDOSFS_DEBUG 112 printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap); 113 #endif 114 115 /* 116 * Create a directory entry for the file, then call createde() to 117 * have it installed. NOTE: DOS files are always executable. We 118 * use the absence of the owner write bit to make the file 119 * readonly. 120 */ 121 #ifdef DIAGNOSTIC 122 if ((cnp->cn_flags & SAVENAME) == 0) 123 panic("msdosfs_create: no name"); 124 #endif 125 bzero(&ndirent, sizeof(ndirent)); 126 TIMEVAL_TO_TIMESPEC(&time, &ts); 127 unix2dostime(&ts, &ndirent.de_Date, &ndirent.de_Time); 128 unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen); 129 ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ? 0 : ATTR_READONLY; 130 ndirent.de_StartCluster = 0; 131 ndirent.de_FileSize = 0; 132 ndirent.de_dev = pdep->de_dev; 133 ndirent.de_devvp = pdep->de_devvp; 134 if ((error = createde(&ndirent, pdep, &dep)) == 0) { 135 *ap->a_vpp = DETOV(dep); 136 if ((cnp->cn_flags & SAVESTART) == 0) 137 free(cnp->cn_pnbuf, M_NAMEI); 138 } else { 139 free(cnp->cn_pnbuf, M_NAMEI); 140 } 141 vput(ap->a_dvp); /* release parent dir */ 142 return error; 143 } 144 145 int 146 msdosfs_mknod(ap) 147 struct vop_mknod_args /* { 148 struct vnode *a_dvp; 149 struct vnode **a_vpp; 150 struct componentname *a_cnp; 151 struct vattr *a_vap; 152 } */ *ap; 153 { 154 int error; 155 struct denode *pdep = VTODE(ap->a_dvp); 156 157 switch (ap->a_vap->va_type) { 158 case VDIR: 159 error = msdosfs_mkdir((struct vop_mkdir_args *)ap); 160 break; 161 162 case VREG: 163 error = msdosfs_create((struct vop_create_args *)ap); 164 break; 165 166 default: 167 error = EINVAL; 168 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 169 vput(ap->a_dvp); 170 break; 171 } 172 return error; 173 } 174 175 int 176 msdosfs_open(ap) 177 struct vop_open_args /* { 178 struct vnode *a_vp; 179 int a_mode; 180 struct ucred *a_cred; 181 struct proc *a_p; 182 } */ *ap; 183 { 184 return 0; 185 } 186 187 int 188 msdosfs_close(ap) 189 struct vop_close_args /* { 190 struct vnode *a_vp; 191 int a_fflag; 192 struct ucred *a_cred; 193 struct proc *a_p; 194 } */ *ap; 195 { 196 struct vnode *vp = ap->a_vp; 197 struct denode *dep = VTODE(vp); 198 struct timespec ts; 199 200 if (vp->v_usecount > 1 && !(dep->de_flag & DE_LOCKED)) { 201 TIMEVAL_TO_TIMESPEC(&time, &ts); 202 DE_TIMES(dep, &ts); 203 } 204 return 0; 205 } 206 207 /* 208 * This routine will go into sys/kern/vfs_subr.c one day! 209 * 210 * Do the usual access checking. 211 * file_node, uid and gid are from the vnode in question, 212 * while acc_mode and cred are from the VOP_ACCESS parameter list. 213 */ 214 static int 215 vaccess(file_mode, uid, gid, acc_mode, cred) 216 mode_t file_mode; 217 uid_t uid; 218 gid_t gid; 219 mode_t acc_mode; 220 struct ucred *cred; 221 { 222 mode_t mask; 223 int i; 224 register gid_t *gp; 225 226 /* User id 0 always gets access. */ 227 if (cred->cr_uid == 0) 228 return 0; 229 230 mask = 0; 231 232 /* Otherwise, check the owner. */ 233 if (cred->cr_uid == uid) { 234 if (acc_mode & VEXEC) 235 mask |= S_IXUSR; 236 if (acc_mode & VREAD) 237 mask |= S_IRUSR; 238 if (acc_mode & VWRITE) 239 mask |= S_IWUSR; 240 return (file_mode & mask) == mask ? 0 : EACCES; 241 } 242 243 /* Otherwise, check the groups. */ 244 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) 245 if (gid == *gp) { 246 if (acc_mode & VEXEC) 247 mask |= S_IXGRP; 248 if (acc_mode & VREAD) 249 mask |= S_IRGRP; 250 if (acc_mode & VWRITE) 251 mask |= S_IWGRP; 252 return (file_mode & mask) == mask ? 0 : EACCES; 253 } 254 255 /* Otherwise, check everyone else. */ 256 if (acc_mode & VEXEC) 257 mask |= S_IXOTH; 258 if (acc_mode & VREAD) 259 mask |= S_IROTH; 260 if (acc_mode & VWRITE) 261 mask |= S_IWOTH; 262 return (file_mode & mask) == mask ? 0 : EACCES; 263 } 264 265 int 266 msdosfs_access(ap) 267 struct vop_access_args /* { 268 struct vnode *a_vp; 269 int a_mode; 270 struct ucred *a_cred; 271 struct proc *a_p; 272 } */ *ap; 273 { 274 mode_t dosmode; 275 struct denode *dep = VTODE(ap->a_vp); 276 struct msdosfsmount *pmp = dep->de_pmp; 277 278 dosmode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) | 279 ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH)); 280 dosmode &= pmp->pm_mask; 281 282 return vaccess(dosmode, pmp->pm_uid, pmp->pm_gid, ap->a_mode, ap->a_cred); 283 } 284 285 int 286 msdosfs_getattr(ap) 287 struct vop_getattr_args /* { 288 struct vnode *a_vp; 289 struct vattr *a_vap; 290 struct ucred *a_cred; 291 struct proc *a_p; 292 } */ *ap; 293 { 294 u_int cn; 295 struct denode *dep = VTODE(ap->a_vp); 296 struct vattr *vap = ap->a_vap; 297 struct timespec ts; 298 299 TIMEVAL_TO_TIMESPEC(&time, &ts); 300 DE_TIMES(dep, &ts); 301 vap->va_fsid = dep->de_dev; 302 /* 303 * The following computation of the fileid must be the same as that 304 * used in msdosfs_readdir() to compute d_fileno. If not, pwd 305 * doesn't work. 306 */ 307 if (dep->de_Attributes & ATTR_DIRECTORY) { 308 if ((cn = dep->de_StartCluster) == MSDOSFSROOT) 309 cn = 1; 310 } else { 311 if ((cn = dep->de_dirclust) == MSDOSFSROOT) 312 cn = 1; 313 cn = (cn << 16) | (dep->de_diroffset & 0xffff); 314 } 315 vap->va_fileid = cn; 316 vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) | 317 ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH)); 318 vap->va_mode &= dep->de_pmp->pm_mask; 319 if (dep->de_Attributes & ATTR_DIRECTORY) 320 vap->va_mode |= S_IFDIR; 321 vap->va_nlink = 1; 322 vap->va_gid = dep->de_pmp->pm_gid; 323 vap->va_uid = dep->de_pmp->pm_uid; 324 vap->va_rdev = 0; 325 vap->va_size = dep->de_FileSize; 326 dos2unixtime(dep->de_Date, dep->de_Time, &vap->va_atime); 327 vap->va_mtime = vap->va_atime; 328 #ifndef MSDOSFS_NODIRMOD 329 if (vap->va_mode & S_IFDIR) 330 TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime); 331 #endif 332 vap->va_ctime = vap->va_atime; 333 vap->va_flags = dep->de_flag; 334 vap->va_gen = 0; 335 vap->va_blocksize = dep->de_pmp->pm_bpcluster; 336 vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) & 337 ~(dep->de_pmp->pm_crbomask); 338 vap->va_type = ap->a_vp->v_type; 339 return 0; 340 } 341 342 int 343 msdosfs_setattr(ap) 344 struct vop_setattr_args /* { 345 struct vnode *a_vp; 346 struct vattr *a_vap; 347 struct ucred *a_cred; 348 struct proc *a_p; 349 } */ *ap; 350 { 351 int error = 0; 352 struct denode *dep = VTODE(ap->a_vp); 353 struct vattr *vap = ap->a_vap; 354 struct ucred *cred = ap->a_cred; 355 356 #ifdef MSDOSFS_DEBUG 357 printf("msdosfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n", 358 ap->a_vp, vap, cred, ap->a_p); 359 #endif 360 if ((vap->va_type != VNON) || 361 (vap->va_nlink != VNOVAL) || 362 (vap->va_fsid != VNOVAL) || 363 (vap->va_fileid != VNOVAL) || 364 (vap->va_blocksize != VNOVAL) || 365 (vap->va_rdev != VNOVAL) || 366 (vap->va_bytes != VNOVAL) || 367 (vap->va_gen != VNOVAL) || 368 (vap->va_uid != VNOVAL) || 369 (vap->va_gid != VNOVAL)) { 370 #ifdef MSDOSFS_DEBUG 371 printf("msdosfs_setattr(): returning EINVAL\n"); 372 printf(" va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n", 373 vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid); 374 printf(" va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n", 375 vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen); 376 printf(" va_uid %x, va_gid %x\n", 377 vap->va_uid, vap->va_gid); 378 #endif 379 return EINVAL; 380 } 381 382 if (vap->va_size != VNOVAL) { 383 if (ap->a_vp->v_type == VDIR) 384 return EISDIR; 385 if (error = detrunc(dep, vap->va_size, 0, cred, ap->a_p)) 386 return error; 387 } 388 if (vap->va_mtime.ts_sec != VNOVAL) { 389 dep->de_flag |= DE_UPDATE; 390 if (error = deupdat(dep, &vap->va_mtime, 1)) 391 return error; 392 } 393 394 /* 395 * DOS files only have the ability to have thier writability 396 * attribute set, so we use the owner write bit to set the readonly 397 * attribute. 398 */ 399 if (vap->va_mode != (u_short) VNOVAL) { 400 /* We ignore the read and execute bits */ 401 if (vap->va_mode & VWRITE) 402 dep->de_Attributes &= ~ATTR_READONLY; 403 else 404 dep->de_Attributes |= ATTR_READONLY; 405 dep->de_flag |= DE_UPDATE; 406 } 407 408 if (vap->va_flags != VNOVAL) { 409 if (error = suser(cred, &ap->a_p->p_acflag)) 410 return error; 411 if (cred->cr_uid == 0) 412 dep->de_flag = vap->va_flags; 413 else { 414 dep->de_flag &= 0xffff0000; 415 dep->de_flag |= (vap->va_flags & 0xffff); 416 } 417 dep->de_flag |= DE_UPDATE; 418 } 419 return error; 420 } 421 422 int 423 msdosfs_read(ap) 424 struct vop_read_args /* { 425 struct vnode *a_vp; 426 struct uio *a_uio; 427 int a_ioflag; 428 struct ucred *a_cred; 429 } */ *ap; 430 { 431 int error = 0; 432 int diff; 433 int isadir; 434 long n; 435 long on; 436 daddr_t bn; 437 daddr_t lbn; 438 daddr_t rablock; 439 int rasize; 440 struct buf *bp; 441 struct vnode *vp = ap->a_vp; 442 struct denode *dep = VTODE(vp); 443 struct msdosfsmount *pmp = dep->de_pmp; 444 struct uio *uio = ap->a_uio; 445 446 /* 447 * If they didn't ask for any data, then we are done. 448 */ 449 if (uio->uio_resid == 0) 450 return 0; 451 if (uio->uio_offset < 0) 452 return EINVAL; 453 454 isadir = dep->de_Attributes & ATTR_DIRECTORY; 455 do { 456 lbn = uio->uio_offset >> pmp->pm_cnshift; 457 on = uio->uio_offset & pmp->pm_crbomask; 458 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid); 459 diff = dep->de_FileSize - uio->uio_offset; 460 if (diff <= 0) 461 return 0; 462 /* convert cluster # to block # if a directory */ 463 if (isadir) { 464 error = pcbmap(dep, lbn, &lbn, 0); 465 if (error) 466 return error; 467 } 468 if (diff < n) 469 n = diff; 470 /* 471 * If we are operating on a directory file then be sure to 472 * do i/o with the vnode for the filesystem instead of the 473 * vnode for the directory. 474 */ 475 if (isadir) { 476 error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 477 NOCRED, &bp); 478 } else { 479 rablock = lbn + 1; 480 if (vp->v_lastr + 1 == lbn && 481 rablock * pmp->pm_bpcluster < dep->de_FileSize) { 482 rasize = pmp->pm_bpcluster; 483 error = breadn(vp, lbn, pmp->pm_bpcluster, 484 &rablock, &rasize, 1, 485 NOCRED, &bp); 486 } else { 487 error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED, 488 &bp); 489 } 490 vp->v_lastr = lbn; 491 } 492 n = min(n, pmp->pm_bpcluster - bp->b_resid); 493 if (error) { 494 brelse(bp); 495 return error; 496 } 497 error = uiomove(bp->b_data + on, (int) n, uio); 498 /* 499 * If we have read everything from this block or have read 500 * to end of file then we are done with this block. Mark 501 * it to say the buffer can be reused if need be. 502 */ 503 #if 0 504 if (n + on == pmp->pm_bpcluster || 505 uio->uio_offset == dep->de_FileSize) 506 bp->b_flags |= B_AGE; 507 #endif 508 brelse(bp); 509 } while (error == 0 && uio->uio_resid > 0 && n != 0); 510 return error; 511 } 512 513 /* 514 * Write data to a file or directory. 515 */ 516 int 517 msdosfs_write(ap) 518 struct vop_write_args /* { 519 struct vnode *a_vp; 520 struct uio *a_uio; 521 int a_ioflag; 522 struct ucred *a_cred; 523 } */ *ap; 524 { 525 int n; 526 int isadir; 527 int croffset; 528 int resid; 529 int osize; 530 int error = 0; 531 u_long count; 532 daddr_t bn, lastcn; 533 struct buf *bp; 534 int ioflag = ap->a_ioflag; 535 struct uio *uio = ap->a_uio; 536 struct proc *p = uio->uio_procp; 537 struct vnode *vp = ap->a_vp; 538 struct vnode *thisvp; 539 struct denode *dep = VTODE(vp); 540 struct msdosfsmount *pmp = dep->de_pmp; 541 struct ucred *cred = ap->a_cred; 542 543 #ifdef MSDOSFS_DEBUG 544 printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n", 545 vp, uio, ioflag, cred); 546 printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n", 547 dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster); 548 #endif 549 550 switch (vp->v_type) { 551 case VREG: 552 if (ioflag & IO_APPEND) 553 uio->uio_offset = dep->de_FileSize; 554 isadir = 0; 555 thisvp = vp; 556 break; 557 558 case VDIR: 559 if ((ioflag & IO_SYNC) == 0) 560 panic("msdosfs_write(): non-sync directory update"); 561 isadir = 1; 562 thisvp = pmp->pm_devvp; 563 break; 564 565 default: 566 panic("msdosfs_write(): bad file type"); 567 break; 568 } 569 570 if (uio->uio_offset < 0) 571 return EINVAL; 572 573 if (uio->uio_resid == 0) 574 return 0; 575 576 /* 577 * If they've exceeded their filesize limit, tell them about it. 578 */ 579 if (vp->v_type == VREG && p && 580 ((uio->uio_offset + uio->uio_resid) > 581 p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { 582 psignal(p, SIGXFSZ); 583 return EFBIG; 584 } 585 586 /* 587 * If attempting to write beyond the end of the root directory we 588 * stop that here because the root directory can not grow. 589 */ 590 if ((dep->de_Attributes & ATTR_DIRECTORY) && 591 dep->de_StartCluster == MSDOSFSROOT && 592 (uio->uio_offset + uio->uio_resid) > dep->de_FileSize) 593 return ENOSPC; 594 595 /* 596 * If the offset we are starting the write at is beyond the end of 597 * the file, then they've done a seek. Unix filesystems allow 598 * files with holes in them, DOS doesn't so we must fill the hole 599 * with zeroed blocks. 600 */ 601 if (uio->uio_offset > dep->de_FileSize) { 602 error = deextend(dep, uio->uio_offset, cred); 603 if (error) 604 return error; 605 } 606 607 /* 608 * Remember some values in case the write fails. 609 */ 610 resid = uio->uio_resid; 611 osize = dep->de_FileSize; 612 613 614 /* 615 * If we write beyond the end of the file, extend it to its ultimate 616 * size ahead of the time to hopefully get a contiguous area. 617 */ 618 if (uio->uio_offset + resid > osize) { 619 count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize); 620 if ((error = extendfile(dep, count, NULL, NULL, 0)) 621 && (error != ENOSPC || (ioflag & IO_UNIT))) 622 goto errexit; 623 lastcn = dep->de_fc[FC_LASTFC].fc_frcn; 624 } else 625 lastcn = de_clcount(pmp, osize) - 1; 626 627 do { 628 bn = de_blk(pmp, uio->uio_offset); 629 if (isadir) { 630 if (error = pcbmap(dep, bn, &bn, 0)) 631 break; 632 } else if (bn > lastcn) { 633 error = ENOSPC; 634 break; 635 } 636 637 if ((uio->uio_offset & pmp->pm_crbomask) == 0 638 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset) 639 || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) { 640 /* 641 * If either the whole cluster gets written, 642 * or we write the cluster from its start beyond EOF, 643 * then no need to read data from disk. 644 */ 645 bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0); 646 clrbuf(bp); 647 /* 648 * Do the bmap now, since pcbmap needs buffers 649 * for the fat table. (see msdosfs_strategy) 650 */ 651 if (!isadir) { 652 if (bp->b_blkno == bp->b_lblkno) { 653 if (error = pcbmap(dep, bp->b_lblkno, 654 &bp->b_blkno, 0)) 655 bp->b_blkno = -1; 656 } 657 if (bp->b_blkno == -1) { 658 brelse(bp); 659 if (!error) 660 error = EIO; /* XXX */ 661 break; 662 } 663 } 664 } else { 665 /* 666 * The block we need to write into exists, so read it in. 667 */ 668 if (error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp)) 669 break; 670 } 671 672 croffset = uio->uio_offset & pmp->pm_crbomask; 673 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset); 674 if (uio->uio_offset + n > dep->de_FileSize) { 675 dep->de_FileSize = uio->uio_offset + n; 676 vnode_pager_setsize(vp, dep->de_FileSize); /* why? */ 677 } 678 (void) vnode_pager_uncache(vp); /* why not? */ 679 /* 680 * Should these vnode_pager_* functions be done on dir 681 * files? 682 */ 683 684 /* 685 * Copy the data from user space into the buf header. 686 */ 687 error = uiomove(bp->b_data + croffset, n, uio); 688 689 /* 690 * If they want this synchronous then write it and wait for 691 * it. Otherwise, if on a cluster boundary write it 692 * asynchronously so we can move on to the next block 693 * without delay. Otherwise do a delayed write because we 694 * may want to write somemore into the block later. 695 */ 696 if (ioflag & IO_SYNC) 697 (void) bwrite(bp); 698 else if (n + croffset == pmp->pm_bpcluster) { 699 bp->b_flags |= B_AGE; 700 bawrite(bp); 701 } else 702 bdwrite(bp); 703 dep->de_flag |= DE_UPDATE; 704 } while (error == 0 && uio->uio_resid > 0); 705 706 /* 707 * If the write failed and they want us to, truncate the file back 708 * to the size it was before the write was attempted. 709 */ 710 errexit: 711 if (error) { 712 if (ioflag & IO_UNIT) { 713 detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL); 714 uio->uio_offset -= resid - uio->uio_resid; 715 uio->uio_resid = resid; 716 } else { 717 detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL); 718 if (uio->uio_resid != resid) 719 error = 0; 720 } 721 } else { 722 error = deupdat(dep, &time, 1); 723 } 724 return error; 725 } 726 727 int 728 msdosfs_ioctl(ap) 729 struct vop_ioctl_args /* { 730 struct vnode *a_vp; 731 int a_command; 732 caddr_t a_data; 733 int a_fflag; 734 struct ucred *a_cred; 735 struct proc *a_p; 736 } */ *ap; 737 { 738 return ENOTTY; 739 } 740 741 int 742 msdosfs_select(ap) 743 struct vop_select_args /* { 744 struct vnode *a_vp; 745 int a_which; 746 int a_fflags; 747 struct ucred *a_cred; 748 struct proc *a_p; 749 } */ *ap; 750 { 751 return 1; /* DOS filesystems never block? */ 752 } 753 754 int 755 msdosfs_mmap(ap) 756 struct vop_mmap_args /* { 757 struct vnode *a_vp; 758 int a_fflags; 759 struct ucred *a_cred; 760 struct proc *a_p; 761 } */ *ap; 762 { 763 return EINVAL; 764 } 765 766 /* 767 * Flush the blocks of a file to disk. 768 * 769 * This function is worthless for vnodes that represent directories. Maybe we 770 * could just do a sync if they try an fsync on a directory file. 771 */ 772 int 773 msdosfs_fsync(ap) 774 struct vop_fsync_args /* { 775 struct vnode *a_vp; 776 struct ucred *a_cred; 777 int a_waitfor; 778 struct proc *a_p; 779 } */ *ap; 780 { 781 struct vnode *vp = ap->a_vp; 782 int wait = ap->a_waitfor == MNT_WAIT; 783 int error; 784 785 #if 0 786 /* 787 * Does this call to vflushbuf() do anything? I can find no code 788 * anywhere that sets v_dirtyblkhd in the vnode, which vflushbuf() 789 * seems to depend upon. 790 */ 791 vflushbuf(vp, wait ? B_SYNC : 0); 792 #endif 793 return deupdat(VTODE(vp), &time, wait); 794 } 795 796 /* 797 * Now the whole work of extending a file is done in the write function. 798 * So nothing to do here. 799 */ 800 int 801 msdosfs_seek(ap) 802 struct vop_seek_args /* { 803 struct vnode *a_vp; 804 off_t a_oldoff; 805 off_t a_newoff; 806 struct ucred *a_cred; 807 } */ *ap; 808 { 809 return 0; 810 } 811 812 int 813 msdosfs_remove(ap) 814 struct vop_remove_args /* { 815 struct vnode *a_dvp; 816 struct vnode *a_vp; 817 struct componentname *a_cnp; 818 } */ *ap; 819 { 820 int error; 821 struct denode *dep = VTODE(ap->a_vp); 822 struct denode *ddep = VTODE(ap->a_dvp); 823 824 error = removede(ddep,dep); 825 #ifdef MSDOSFS_DEBUG 826 printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount); 827 #endif 828 if (ddep == dep) 829 vrele(ap->a_vp); 830 else 831 vput(ap->a_vp); /* causes msdosfs_inactive() to be called 832 * via vrele() */ 833 vput(ap->a_dvp); 834 return error; 835 } 836 837 /* 838 * DOS filesystems don't know what links are. But since we already called 839 * msdosfs_lookup() with create and lockparent, the parent is locked so we 840 * have to free it before we return the error. 841 */ 842 int 843 msdosfs_link(ap) 844 struct vop_link_args /* { 845 struct vnode *a_vp; 846 struct vnode *a_tdvp; 847 struct componentname *a_cnp; 848 } */ *ap; 849 { 850 return VOP_ABORTOP(ap->a_vp, ap->a_cnp); 851 } 852 853 /* 854 * Renames on files require moving the denode to a new hash queue since the 855 * denode's location is used to compute which hash queue to put the file 856 * in. Unless it is a rename in place. For example "mv a b". 857 * 858 * What follows is the basic algorithm: 859 * 860 * if (file move) { 861 * if (dest file exists) { 862 * remove dest file 863 * } 864 * if (dest and src in same directory) { 865 * rewrite name in existing directory slot 866 * } else { 867 * write new entry in dest directory 868 * update offset and dirclust in denode 869 * move denode to new hash chain 870 * clear old directory entry 871 * } 872 * } else { 873 * directory move 874 * if (dest directory exists) { 875 * if (dest is not empty) { 876 * return ENOTEMPTY 877 * } 878 * remove dest directory 879 * } 880 * if (dest and src in same directory) { 881 * rewrite name in existing entry 882 * } else { 883 * be sure dest is not a child of src directory 884 * write entry in dest directory 885 * update "." and ".." in moved directory 886 * update offset and dirclust in denode 887 * move denode to new hash chain 888 * clear old directory entry for moved directory 889 * } 890 * } 891 * 892 * On entry: 893 * source's parent directory is unlocked 894 * source file or directory is unlocked 895 * destination's parent directory is locked 896 * destination file or directory is locked if it exists 897 * 898 * On exit: 899 * all denodes should be released 900 * 901 * Notes: 902 * I'm not sure how the memory containing the pathnames pointed at by the 903 * componentname structures is freed, there may be some memory bleeding 904 * for each rename done. 905 */ 906 int 907 msdosfs_rename(ap) 908 struct vop_rename_args /* { 909 struct vnode *a_fdvp; 910 struct vnode *a_fvp; 911 struct componentname *a_fcnp; 912 struct vnode *a_tdvp; 913 struct vnode *a_tvp; 914 struct componentname *a_tcnp; 915 } */ *ap; 916 { 917 u_char toname[11]; 918 int error; 919 int newparent = 0; 920 int sourceisadirectory = 0; 921 u_long to_dirclust; 922 u_long to_diroffset; 923 u_long cn; 924 daddr_t bn; 925 struct vnode *tvp = ap->a_tvp; 926 struct denode *fddep; /* from file's parent directory */ 927 struct denode *fdep; /* from file or directory */ 928 struct denode *tddep; /* to file's parent directory */ 929 struct denode *tdep; /* to file or directory */ 930 struct msdosfsmount *pmp; 931 struct direntry *dotdotp; 932 struct direntry *ep; 933 struct buf *bp; 934 935 fddep = VTODE(ap->a_fdvp); 936 fdep = VTODE(ap->a_fvp); 937 tddep = VTODE(ap->a_tdvp); 938 tdep = tvp ? VTODE(tvp) : NULL; 939 pmp = fddep->de_pmp; 940 941 #ifdef __NetBSD__ 942 /* Check for cross-device rename */ 943 if ((ap->a_fvp->v_mount != ap->a_tdvp->v_mount) || 944 (tvp && (ap->a_fvp->v_mount != tvp->v_mount))) { 945 error = EXDEV; 946 goto bad; 947 } 948 #endif 949 950 /* 951 * Convert the filename in tcnp into a dos filename. We copy this 952 * into the denode and directory entry for the destination 953 * file/directory. 954 */ 955 unix2dosfn((u_char *) ap->a_tcnp->cn_nameptr, 956 toname, ap->a_tcnp->cn_namelen); 957 958 /* 959 * At this point this is the lock state of the denodes: 960 * fddep referenced 961 * fdep referenced 962 * tddep locked 963 * tdep locked if it exists 964 */ 965 966 /* 967 * Be sure we are not renaming ".", "..", or an alias of ".". This 968 * leads to a crippled directory tree. It's pretty tough to do a 969 * "ls" or "pwd" with the "." directory entry missing, and "cd .." 970 * doesn't work if the ".." entry is missing. 971 */ 972 if (fdep->de_Attributes & ATTR_DIRECTORY) { 973 if ((ap->a_fcnp->cn_namelen == 1 974 && ap->a_fcnp->cn_nameptr[0] == '.') 975 || fddep == fdep 976 || (ap->a_fcnp->cn_flags & ISDOTDOT)) { 977 VOP_ABORTOP(ap->a_tdvp, ap->a_tcnp); 978 vput(ap->a_tdvp); 979 if (tvp) 980 vput(tvp); 981 VOP_ABORTOP(ap->a_fdvp, ap->a_fcnp); 982 vrele(ap->a_fdvp); 983 vrele(ap->a_fvp); 984 return EINVAL; 985 } 986 sourceisadirectory = 1; 987 } 988 989 /* 990 * If we are renaming a directory, and the directory is being moved 991 * to another directory, then we must be sure the destination 992 * directory is not in the subtree of the source directory. This 993 * could orphan everything under the source directory. 994 * doscheckpath() unlocks the destination's parent directory so we 995 * must look it up again to relock it. 996 */ 997 if (fddep->de_StartCluster != tddep->de_StartCluster) 998 newparent = 1; 999 if (sourceisadirectory && newparent) { 1000 if (tdep) { 1001 vput(ap->a_tvp); 1002 tdep = NULL; 1003 } 1004 /* doscheckpath() vput()'s tddep */ 1005 error = doscheckpath(fdep, tddep); 1006 tddep = NULL; 1007 if (error) { 1008 goto bad; 1009 } 1010 if ((ap->a_tcnp->cn_flags & SAVESTART) == 0) 1011 panic("msdosfs_rename(): lost to startdir"); 1012 if (error = relookup(ap->a_tdvp, &tvp, ap->a_tcnp)) { 1013 goto bad; 1014 } 1015 tddep = VTODE(ap->a_tdvp); 1016 tdep = tvp ? VTODE(tvp) : NULL; 1017 } 1018 1019 /* 1020 * If the destination exists, then be sure its type (file or dir) 1021 * matches that of the source. And, if it is a directory make sure 1022 * it is empty. Then delete the destination. 1023 */ 1024 if (tdep) { 1025 if (tdep->de_Attributes & ATTR_DIRECTORY) { 1026 if (!sourceisadirectory) { 1027 error = ENOTDIR; 1028 goto bad; 1029 } 1030 if (!dosdirempty(tdep)) { 1031 error = ENOTEMPTY; 1032 goto bad; 1033 } 1034 } else { /* destination is file */ 1035 if (sourceisadirectory) { 1036 error = EISDIR; 1037 goto bad; 1038 } 1039 } 1040 to_dirclust = tdep->de_dirclust; 1041 to_diroffset = tdep->de_diroffset; 1042 if (error = removede(tddep,tdep)) { 1043 goto bad; 1044 } 1045 vput(ap->a_tvp); 1046 tdep = NULL; 1047 1048 /* 1049 * Remember where the slot was for createde(). 1050 */ 1051 tddep->de_fndclust = to_dirclust; 1052 tddep->de_fndoffset = to_diroffset; 1053 } 1054 1055 /* 1056 * If the source and destination are in the same directory then 1057 * just read in the directory entry, change the name in the 1058 * directory entry and write it back to disk. 1059 */ 1060 if (newparent == 0) { 1061 /* tddep and fddep point to the same denode here */ 1062 VOP_LOCK(ap->a_fvp); /* ap->a_fdvp is already locked */ 1063 if (error = readep(fddep->de_pmp, 1064 fdep->de_dirclust, 1065 fdep->de_diroffset, 1066 &bp, &ep)) { 1067 VOP_UNLOCK(ap->a_fvp); 1068 goto bad; 1069 } 1070 bcopy(toname, ep->deName, 11); 1071 if (error = bwrite(bp)) { 1072 VOP_UNLOCK(ap->a_fvp); 1073 goto bad; 1074 } 1075 bcopy(toname, fdep->de_Name, 11); /* update denode */ 1076 /* 1077 * fdep locked fddep and tddep point to the same denode 1078 * which is locked tdep is NULL 1079 */ 1080 } else { 1081 u_long dirsize = 0L; 1082 1083 /* 1084 * If the source and destination are in different 1085 * directories, then mark the entry in the source directory 1086 * as deleted and write a new entry in the destination 1087 * directory. Then move the denode to the correct hash 1088 * chain for its new location in the filesystem. And, if 1089 * we moved a directory, then update its .. entry to point 1090 * to the new parent directory. If we moved a directory 1091 * will also insure that the directory entry on disk has a 1092 * filesize of zero. 1093 */ 1094 VOP_LOCK(ap->a_fvp); 1095 bcopy(toname, fdep->de_Name, 11); /* update denode */ 1096 if (fdep->de_Attributes & ATTR_DIRECTORY) { 1097 dirsize = fdep->de_FileSize; 1098 fdep->de_FileSize = 0; 1099 } 1100 error = createde(fdep, tddep, (struct denode **) 0); 1101 if (fdep->de_Attributes & ATTR_DIRECTORY) { 1102 fdep->de_FileSize = dirsize; 1103 } 1104 if (error) { 1105 /* should put back filename */ 1106 VOP_UNLOCK(ap->a_fvp); 1107 goto bad; 1108 } 1109 VOP_LOCK(ap->a_fdvp); 1110 if (error = readep(fddep->de_pmp, 1111 fddep->de_fndclust, 1112 fddep->de_fndoffset, 1113 &bp, &ep)) { 1114 VOP_UNLOCK(ap->a_fvp); 1115 VOP_UNLOCK(ap->a_fdvp); 1116 goto bad; 1117 } 1118 ep->deName[0] = SLOT_DELETED; 1119 if (error = bwrite(bp)) { 1120 VOP_UNLOCK(ap->a_fvp); 1121 VOP_UNLOCK(ap->a_fdvp); 1122 goto bad; 1123 } 1124 fdep->de_dirclust = tddep->de_fndclust; 1125 fdep->de_diroffset = tddep->de_fndoffset; 1126 reinsert(fdep); 1127 VOP_UNLOCK(ap->a_fdvp); 1128 } 1129 /* fdep is still locked here */ 1130 1131 /* 1132 * If we moved a directory to a new parent directory, then we must 1133 * fixup the ".." entry in the moved directory. 1134 */ 1135 if (sourceisadirectory && newparent) { 1136 cn = fdep->de_StartCluster; 1137 if (cn == MSDOSFSROOT) { 1138 /* this should never happen */ 1139 panic("msdosfs_rename(): updating .. in root directory?\n"); 1140 } else { 1141 bn = cntobn(pmp, cn); 1142 } 1143 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, 1144 NOCRED, &bp); 1145 if (error) { 1146 /* should really panic here, fs is corrupt */ 1147 VOP_UNLOCK(ap->a_fvp); 1148 goto bad; 1149 } 1150 dotdotp = (struct direntry *) bp->b_data + 1; 1151 putushort(dotdotp->deStartCluster, tddep->de_StartCluster); 1152 error = bwrite(bp); 1153 VOP_UNLOCK(ap->a_fvp); 1154 if (error) { 1155 /* should really panic here, fs is corrupt */ 1156 goto bad; 1157 } 1158 } else 1159 VOP_UNLOCK(ap->a_fvp); 1160 bad: ; 1161 vrele(DETOV(fdep)); 1162 vrele(DETOV(fddep)); 1163 if (tdep) 1164 vput(DETOV(tdep)); 1165 if (tddep) 1166 vput(DETOV(tddep)); 1167 return error; 1168 } 1169 1170 struct { 1171 struct direntry dot; 1172 struct direntry dotdot; 1173 } dosdirtemplate = { 1174 1175 ". ", " ", /* the . entry */ 1176 ATTR_DIRECTORY, /* file attribute */ 1177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* resevered */ 1178 210, 4, 210, 4, /* time and date */ 1179 0, 0, /* startcluster */ 1180 0, 0, 0, 0, /* filesize */ 1181 ".. ", " ", /* the .. entry */ 1182 ATTR_DIRECTORY, /* file attribute */ 1183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* resevered */ 1184 210, 4, 210, 4, /* time and date */ 1185 0, 0, /* startcluster */ 1186 0, 0, 0, 0, /* filesize */ 1187 }; 1188 1189 int 1190 msdosfs_mkdir(ap) 1191 struct vop_mkdir_args /* { 1192 struct vnode *a_dvp; 1193 struvt vnode **a_vpp; 1194 struvt componentname *a_cnp; 1195 struct vattr *a_vap; 1196 } */ *ap; 1197 { 1198 int bn; 1199 int error; 1200 u_long newcluster; 1201 struct denode *pdep; 1202 struct denode *ndep; 1203 struct direntry *denp; 1204 struct denode ndirent; 1205 struct msdosfsmount *pmp; 1206 struct buf *bp; 1207 struct timespec ts; 1208 u_short dDate, dTime; 1209 1210 pdep = VTODE(ap->a_dvp); 1211 1212 /* 1213 * If this is the root directory and there is no space left we 1214 * can't do anything. This is because the root directory can not 1215 * change size. 1216 */ 1217 if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndclust == (u_long)-1) { 1218 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 1219 vput(ap->a_dvp); 1220 return ENOSPC; 1221 } 1222 1223 pmp = pdep->de_pmp; 1224 1225 /* 1226 * Allocate a cluster to hold the about to be created directory. 1227 */ 1228 if (error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL)) { 1229 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 1230 vput(ap->a_dvp); 1231 return error; 1232 } 1233 1234 /* 1235 * Now fill the cluster with the "." and ".." entries. And write 1236 * the cluster to disk. This way it is there for the parent 1237 * directory to be pointing at if there were a crash. 1238 */ 1239 bn = cntobn(pmp, newcluster); 1240 /* always succeeds */ 1241 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0); 1242 bzero(bp->b_data, pmp->pm_bpcluster); 1243 bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate); 1244 denp = (struct direntry *) bp->b_data; 1245 putushort(denp->deStartCluster, newcluster); 1246 TIMEVAL_TO_TIMESPEC(&time, &ts); 1247 unix2dostime(&ts, &dDate, &dTime); 1248 putushort(denp->deDate, dDate); 1249 putushort(denp->deTime, dTime); 1250 denp++; 1251 putushort(denp->deStartCluster, pdep->de_StartCluster); 1252 putushort(denp->deDate, dDate); 1253 putushort(denp->deTime, dTime); 1254 if (error = bwrite(bp)) { 1255 clusterfree(pmp, newcluster, NULL); 1256 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 1257 vput(ap->a_dvp); 1258 return error; 1259 } 1260 1261 /* 1262 * Now build up a directory entry pointing to the newly allocated 1263 * cluster. This will be written to an empty slot in the parent 1264 * directory. 1265 */ 1266 ndep = &ndirent; 1267 bzero(ndep, sizeof(*ndep)); 1268 unix2dosfn((u_char *)ap->a_cnp->cn_nameptr, 1269 ndep->de_Name, ap->a_cnp->cn_namelen); 1270 TIMEVAL_TO_TIMESPEC(&time, &ts); 1271 unix2dostime(&ts, &ndep->de_Date, &ndep->de_Time); 1272 ndep->de_StartCluster = newcluster; 1273 ndep->de_Attributes = ATTR_DIRECTORY; 1274 1275 error = createde(ndep, pdep, &ndep); 1276 if (error) { 1277 clusterfree(pmp, newcluster, NULL); 1278 } else { 1279 *ap->a_vpp = DETOV(ndep); 1280 } 1281 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 1282 #ifdef MSDOSFS_DEBUG 1283 printf("msdosfs_mkdir(): vput(%08x)\n", ap->a_dvp); 1284 #endif 1285 vput(ap->a_dvp); 1286 return error; 1287 } 1288 1289 int 1290 msdosfs_rmdir(ap) 1291 struct vop_rmdir_args /* { 1292 struct vnode *a_dvp; 1293 struct vnode *a_vp; 1294 struct componentname *a_cnp; 1295 } */ *ap; 1296 { 1297 struct denode *ddep; 1298 struct denode *dep; 1299 int error = 0; 1300 1301 ddep = VTODE(ap->a_dvp); /* parent dir of dir to delete */ 1302 dep = VTODE(ap->a_vp);/* directory to delete */ 1303 1304 /* 1305 * Don't let "rmdir ." go thru. 1306 */ 1307 if (ddep == dep) { 1308 vrele(ap->a_vp); 1309 vput(ap->a_vp); 1310 return EINVAL; 1311 } 1312 1313 /* 1314 * Be sure the directory being deleted is empty. 1315 */ 1316 if (dosdirempty(dep) == 0) { 1317 error = ENOTEMPTY; 1318 goto out; 1319 } 1320 1321 /* 1322 * Delete the entry from the directory. For dos filesystems this 1323 * gets rid of the directory entry on disk, the in memory copy 1324 * still exists but the de_refcnt is <= 0. This prevents it from 1325 * being found by deget(). When the vput() on dep is done we give 1326 * up access and eventually msdosfs_reclaim() will be called which 1327 * will remove it from the denode cache. 1328 */ 1329 if (error = removede(ddep,dep)) 1330 goto out; 1331 1332 /* 1333 * This is where we decrement the link count in the parent 1334 * directory. Since dos filesystems don't do this we just purge 1335 * the name cache and let go of the parent directory denode. 1336 */ 1337 cache_purge(DETOV(ddep)); 1338 vput(ap->a_dvp); 1339 ap->a_dvp = NULL; 1340 1341 /* 1342 * Truncate the directory that is being deleted. 1343 */ 1344 error = detrunc(dep, (u_long) 0, IO_SYNC); 1345 cache_purge(DETOV(dep)); 1346 1347 out: ; 1348 if (ap->a_dvp) 1349 vput(ap->a_dvp); 1350 vput(ap->a_vp); 1351 return error; 1352 } 1353 1354 /* 1355 * DOS filesystems don't know what symlinks are. 1356 */ 1357 int 1358 msdosfs_symlink(ap) 1359 struct vop_symlink_args /* { 1360 struct vnode *a_dvp; 1361 struct vnode **a_vpp; 1362 struct componentname *a_cnp; 1363 struct vattr *a_vap; 1364 char *a_target; 1365 } */ *ap; 1366 { 1367 struct denode *pdep = VTODE(ap->a_dvp); 1368 1369 free(ap->a_cnp->cn_pnbuf, M_NAMEI); 1370 vput(ap->a_dvp); 1371 return EINVAL; 1372 } 1373 1374 /* 1375 * Dummy dirents to simulate the "." and ".." entries of the root directory 1376 * in a dos filesystem. Dos doesn't provide these. Note that each entry 1377 * must be the same size as a dos directory entry (32 bytes). 1378 */ 1379 struct dos_dirent { 1380 u_long d_fileno; 1381 u_short d_reclen; 1382 u_char d_type; 1383 u_char d_namlen; 1384 u_char d_name[24]; 1385 } rootdots[2] = { 1386 1387 { 1388 1, /* d_fileno */ 1389 sizeof(struct direntry), /* d_reclen */ 1390 DT_DIR, /* d_type */ 1391 1, /* d_namlen */ 1392 "." /* d_name */ 1393 }, 1394 { 1395 1, /* d_fileno */ 1396 sizeof(struct direntry), /* d_reclen */ 1397 DT_DIR, /* d_type */ 1398 2, /* d_namlen */ 1399 ".." /* d_name */ 1400 } 1401 }; 1402 1403 int 1404 msdosfs_readdir(ap) 1405 struct vop_readdir_args /* { 1406 struct vnode *a_vp; 1407 struct uio *a_uio; 1408 struct ucred *a_cred; 1409 int *a_eofflag; 1410 u_int *a_cookies; 1411 int a_ncookies; 1412 } */ *ap; 1413 { 1414 int error = 0; 1415 int diff; 1416 char pushout; 1417 long n; 1418 long on; 1419 long lost; 1420 long count; 1421 u_long cn; 1422 u_long fileno; 1423 long bias = 0; 1424 daddr_t bn; 1425 daddr_t lbn; 1426 struct buf *bp; 1427 struct denode *dep = VTODE(ap->a_vp); 1428 struct msdosfsmount *pmp = dep->de_pmp; 1429 struct direntry *dentp; 1430 struct dirent *prev; 1431 struct dirent *crnt; 1432 u_char dirbuf[512]; /* holds converted dos directories */ 1433 int i = 0; 1434 struct uio *uio = ap->a_uio; 1435 int ncookies = 1; 1436 u_int* cookies = NULL; 1437 1438 #ifdef MSDOSFS_DEBUG 1439 printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n", 1440 ap->a_vp, uio, ap->a_cred, ap->a_eofflag); 1441 #endif 1442 1443 #if 0 1444 if (!ap->a_cookies) 1445 ncookies = 1; 1446 #endif 1447 1448 /* 1449 * msdosfs_readdir() won't operate properly on regular files since 1450 * it does i/o only with the the filesystem vnode, and hence can 1451 * retrieve the wrong block from the buffer cache for a plain file. 1452 * So, fail attempts to readdir() on a plain file. 1453 */ 1454 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) 1455 return ENOTDIR; 1456 1457 /* 1458 * If the user buffer is smaller than the size of one dos directory 1459 * entry or the file offset is not a multiple of the size of a 1460 * directory entry, then we fail the read. 1461 */ 1462 count = uio->uio_resid & ~(sizeof(struct direntry) - 1); 1463 lost = uio->uio_resid - count; 1464 if (count < sizeof(struct direntry) || 1465 (uio->uio_offset & (sizeof(struct direntry) - 1))) 1466 return EINVAL; 1467 uio->uio_resid = count; 1468 uio->uio_iov->iov_len = count; 1469 1470 /* 1471 * If they are reading from the root directory then, we simulate 1472 * the . and .. entries since these don't exist in the root 1473 * directory. We also set the offset bias to make up for having to 1474 * simulate these entries. By this I mean that at file offset 64 we 1475 * read the first entry in the root directory that lives on disk. 1476 */ 1477 if (dep->de_StartCluster == MSDOSFSROOT) { 1478 /* 1479 * printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n", 1480 * uio->uio_offset); 1481 */ 1482 bias = 2 * sizeof(struct direntry); 1483 if (uio->uio_offset < 2 * sizeof(struct direntry)) { 1484 if (uio->uio_offset 1485 && uio->uio_offset != sizeof(struct direntry)) { 1486 error = EINVAL; 1487 goto out; 1488 } 1489 n = 1; 1490 if (!uio->uio_offset) { 1491 n = 2; 1492 if (cookies) { 1493 *cookies++ = sizeof(struct direntry); 1494 ncookies--; 1495 } 1496 } 1497 if (cookies) { 1498 if (ncookies-- <= 0) 1499 n--; 1500 else 1501 *cookies++ = 2 * sizeof(struct direntry); 1502 } 1503 1504 error = uiomove((char *) rootdots + uio->uio_offset, 1505 n * sizeof(struct direntry), uio); 1506 } 1507 } 1508 while (!error && uio->uio_resid > 0 && ncookies > 0) { 1509 lbn = (uio->uio_offset - bias) >> pmp->pm_cnshift; 1510 on = (uio->uio_offset - bias) & pmp->pm_crbomask; 1511 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid); 1512 diff = dep->de_FileSize - (uio->uio_offset - bias); 1513 if (diff <= 0) 1514 return 0; 1515 if (diff < n) 1516 n = diff; 1517 error = pcbmap(dep, lbn, &bn, &cn); 1518 if (error) 1519 break; 1520 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp); 1521 n = min(n, pmp->pm_bpcluster - bp->b_resid); 1522 if (error) { 1523 brelse(bp); 1524 return error; 1525 } 1526 1527 /* 1528 * code to convert from dos directory entries to ufs 1529 * directory entries 1530 */ 1531 pushout = 0; 1532 dentp = (struct direntry *)(bp->b_data + on); 1533 prev = 0; 1534 crnt = (struct dirent *) dirbuf; 1535 while ((char *) dentp < bp->b_data + on + n) { 1536 /* 1537 * printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n", 1538 * dentp, prev, crnt, dentp->deName[0], dentp->deAttributes); 1539 */ 1540 /* 1541 * If we have an empty entry or a slot from a 1542 * deleted file, or a volume label entry just 1543 * concatenate its space onto the end of the 1544 * previous entry or, manufacture an empty entry if 1545 * there is no previous entry. 1546 */ 1547 if (dentp->deName[0] == SLOT_EMPTY || 1548 dentp->deName[0] == SLOT_DELETED || 1549 (dentp->deAttributes & ATTR_VOLUME)) { 1550 if (prev) { 1551 prev->d_reclen += sizeof(struct direntry); 1552 if (cookies) { 1553 ncookies++; 1554 cookies--; 1555 } 1556 } else { 1557 prev = crnt; 1558 prev->d_fileno = 0; 1559 prev->d_reclen = sizeof(struct direntry); 1560 prev->d_type = DT_UNKNOWN; 1561 prev->d_namlen = 0; 1562 prev->d_name[0] = 0; 1563 } 1564 } else { 1565 /* 1566 * this computation of d_fileno must match 1567 * the computation of va_fileid in 1568 * msdosfs_getattr 1569 */ 1570 if (dentp->deAttributes & ATTR_DIRECTORY) { 1571 /* if this is the root directory */ 1572 fileno = getushort(dentp->deStartCluster); 1573 if (fileno == MSDOSFSROOT) 1574 fileno = 1; 1575 } else { 1576 /* 1577 * if the file's dirent lives in 1578 * root dir 1579 */ 1580 if ((fileno = cn) == MSDOSFSROOT) 1581 fileno = 1; 1582 fileno = (fileno << 16) | 1583 ((dentp - (struct direntry *) bp->b_data) & 0xffff); 1584 } 1585 crnt->d_fileno = fileno; 1586 crnt->d_reclen = sizeof(struct direntry); 1587 crnt->d_type = (dentp->deAttributes & ATTR_DIRECTORY) 1588 ? DT_DIR : DT_REG; 1589 crnt->d_namlen = dos2unixfn(dentp->deName, 1590 (u_char *)crnt->d_name); 1591 /* 1592 * printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n", 1593 * crnt->d_name, crnt->d_fileno, dentp->deAttributes, 1594 * dentp->deStartCluster); 1595 */ 1596 prev = crnt; 1597 } 1598 dentp++; 1599 if (cookies) { 1600 *cookies++ = (u_int)((char *)dentp - bp->b_data - on) 1601 + uio->uio_offset; 1602 ncookies--; 1603 } 1604 1605 crnt = (struct dirent *) ((char *) crnt + sizeof(struct direntry)); 1606 pushout = 1; 1607 1608 /* 1609 * If our intermediate buffer is full then copy its 1610 * contents to user space. I would just use the 1611 * buffer the buf header points to but, I'm afraid 1612 * that when we brelse() it someone else might find 1613 * it in the cache and think its contents are 1614 * valid. Maybe there is a way to invalidate the 1615 * buffer before brelse()'ing it. 1616 */ 1617 if ((u_char *) crnt >= &dirbuf[sizeof dirbuf]) { 1618 pushout = 0; 1619 error = uiomove(dirbuf, sizeof(dirbuf), uio); 1620 if (error) 1621 break; 1622 prev = 0; 1623 crnt = (struct dirent *) dirbuf; 1624 } 1625 if (ncookies <= 0) 1626 break; 1627 } 1628 if (pushout) { 1629 pushout = 0; 1630 error = uiomove(dirbuf, (char *) crnt - (char *) dirbuf, 1631 uio); 1632 } 1633 1634 #if 0 1635 /* 1636 * If we have read everything from this block or have read 1637 * to end of file then we are done with this block. Mark 1638 * it to say the buffer can be reused if need be. 1639 */ 1640 if (n + on == pmp->pm_bpcluster || 1641 (uio->uio_offset - bias) == dep->de_FileSize) 1642 bp->b_flags |= B_AGE; 1643 #endif /* if 0 */ 1644 brelse(bp); 1645 if (n == 0) 1646 break; 1647 } 1648 out: ; 1649 uio->uio_resid += lost; 1650 1651 #if 0 1652 /* 1653 * I don't know why we bother setting this eofflag, getdirentries() 1654 * in vfs_syscalls.c doesn't bother to look at it when we return. 1655 * (because NFS uses it in nfs_serv.c -- JMP) 1656 */ 1657 if (dep->de_FileSize - uio->uio_offset - bias <= 0) 1658 *ap->a_eofflag = 1; 1659 else 1660 *ap->a_eofflag = 0; 1661 #endif 1662 1663 return error; 1664 } 1665 1666 /* 1667 * DOS filesystems don't know what symlinks are. 1668 */ 1669 int 1670 msdosfs_readlink(ap) 1671 struct vop_readlink_args /* { 1672 struct vnode *a_vp; 1673 struct uio *a_uio; 1674 struct ucred *a_cred; 1675 } */ *ap; 1676 { 1677 return EINVAL; 1678 } 1679 1680 int 1681 msdosfs_abortop(ap) 1682 struct vop_abortop_args /* { 1683 struct vnode *a_dvp; 1684 struct componentname *a_cnp; 1685 } */ *ap; 1686 { 1687 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 1688 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 1689 return 0; 1690 } 1691 1692 int 1693 msdosfs_lock(ap) 1694 struct vop_lock_args /* { 1695 struct vnode *a_vp; 1696 } */ *ap; 1697 { 1698 struct denode *dep = VTODE(ap->a_vp); 1699 1700 while (dep->de_flag & DE_LOCKED) { 1701 dep->de_flag |= DE_WANTED; 1702 if (dep->de_lockholder == curproc->p_pid) 1703 panic("msdosfs_lock: locking against myself"); 1704 dep->de_lockwaiter = curproc->p_pid; 1705 (void) sleep((caddr_t) dep, PINOD); 1706 } 1707 dep->de_lockwaiter = 0; 1708 dep->de_lockholder = curproc->p_pid; 1709 dep->de_flag |= DE_LOCKED; 1710 return 0; 1711 } 1712 1713 int 1714 msdosfs_unlock(ap) 1715 struct vop_unlock_args /* { 1716 struct vnode *vp; 1717 } */ *ap; 1718 { 1719 struct denode *dep = VTODE(ap->a_vp); 1720 1721 if (!(dep->de_flag & DE_LOCKED)) 1722 panic("msdosfs_unlock: denode not locked"); 1723 dep->de_lockholder = 0; 1724 dep->de_flag &= ~DE_LOCKED; 1725 if (dep->de_flag & DE_WANTED) { 1726 dep->de_flag &= ~DE_WANTED; 1727 wakeup((caddr_t) dep); 1728 } 1729 return 0; 1730 } 1731 1732 int 1733 msdosfs_islocked(ap) 1734 struct vop_islocked_args /* { 1735 struct vnode *a_vp; 1736 } */ *ap; 1737 { 1738 return VTODE(ap->a_vp)->de_flag & DE_LOCKED ? 1 : 0; 1739 } 1740 1741 /* 1742 * vp - address of vnode file the file 1743 * bn - which cluster we are interested in mapping to a filesystem block number. 1744 * vpp - returns the vnode for the block special file holding the filesystem 1745 * containing the file of interest 1746 * bnp - address of where to return the filesystem relative block number 1747 */ 1748 int 1749 msdosfs_bmap(ap) 1750 struct vop_bmap_args /* { 1751 struct vnode *a_vp; 1752 daddr_t a_bn; 1753 struct vnode **a_vpp; 1754 daddr_t *a_bnp; 1755 int *a_runp; 1756 } */ *ap; 1757 { 1758 struct denode *dep = VTODE(ap->a_vp); 1759 struct msdosfsmount *pmp = dep->de_pmp; 1760 1761 if (ap->a_vpp != NULL) 1762 *ap->a_vpp = dep->de_devvp; 1763 if (ap->a_bnp == NULL) 1764 return 0; 1765 if (ap->a_runp) { 1766 /* 1767 * Sequential clusters should be counted here. 1768 */ 1769 *ap->a_runp = 0; 1770 } 1771 return pcbmap(dep, ap->a_bn, ap->a_bnp, 0); 1772 } 1773 1774 int msdosfs_reallocblks(ap) 1775 struct vop_reallocblks_args /* { 1776 struct vnode *a_vp; 1777 struct cluster_save *a_buflist; 1778 } */ *ap; 1779 { 1780 /* Currently no support for clustering */ /* XXX */ 1781 return ENOSPC; 1782 } 1783 1784 int 1785 msdosfs_strategy(ap) 1786 struct vop_strategy_args /* { 1787 struct buf *a_bp; 1788 } */ *ap; 1789 { 1790 struct buf *bp = ap->a_bp; 1791 struct denode *dep = VTODE(bp->b_vp); 1792 struct msdosfsmount *pmp = dep->de_pmp; 1793 struct vnode *vp; 1794 int error = 0; 1795 1796 if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 1797 panic("msdosfs_strategy: spec"); 1798 /* 1799 * If we don't already know the filesystem relative block number 1800 * then get it using pcbmap(). If pcbmap() returns the block 1801 * number as -1 then we've got a hole in the file. DOS filesystems 1802 * don't allow files with holes, so we shouldn't ever see this. 1803 */ 1804 if (bp->b_blkno == bp->b_lblkno) { 1805 if (error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0)) 1806 bp->b_blkno = -1; 1807 if (bp->b_blkno == -1) 1808 clrbuf(bp); 1809 } 1810 if (bp->b_blkno == -1) { 1811 biodone(bp); 1812 return error; 1813 } 1814 #ifdef DIAGNOSTIC 1815 #endif 1816 /* 1817 * Read/write the block from/to the disk that contains the desired 1818 * file block. 1819 */ 1820 vp = dep->de_devvp; 1821 bp->b_dev = vp->v_rdev; 1822 VOCALL(vp->v_op, VOFFSET(vop_strategy), ap); 1823 return 0; 1824 } 1825 1826 int 1827 msdosfs_print(ap) 1828 struct vop_print_args /* { 1829 struct vnode *vp; 1830 } */ *ap; 1831 { 1832 struct denode *dep = VTODE(ap->a_vp); 1833 1834 printf("tag VT_MSDOSFS, startcluster %d, dircluster %d, diroffset %d ", 1835 dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset); 1836 printf(" dev %d, %d, %s\n", 1837 major(dep->de_dev), minor(dep->de_dev), 1838 dep->de_flag & DE_LOCKED ? "(LOCKED)" : ""); 1839 if (dep->de_lockholder) { 1840 printf(" owner pid %d", dep->de_lockholder); 1841 if (dep->de_lockwaiter) 1842 printf(" waiting pid %d", dep->de_lockwaiter); 1843 printf("\n"); 1844 } 1845 return 0; 1846 } 1847 1848 int 1849 msdosfs_advlock(ap) 1850 struct vop_advlock_args /* { 1851 struct vnode *a_vp; 1852 caddr_t a_id; 1853 int a_op; 1854 struct flock *a_fl; 1855 int a_flags; 1856 } */ *ap; 1857 { 1858 return EINVAL; /* we don't do locking yet */ 1859 } 1860 1861 int 1862 msdosfs_pathconf(ap) 1863 struct vop_pathconf_args /* { 1864 struct vnode *a_vp; 1865 int a_name; 1866 int *a_retval; 1867 } */ *ap; 1868 { 1869 switch (ap->a_name) { 1870 case _PC_LINK_MAX: 1871 *ap->a_retval = 1; 1872 return 0; 1873 case _PC_NAME_MAX: 1874 *ap->a_retval = 12; 1875 return 0; 1876 case _PC_PATH_MAX: 1877 *ap->a_retval = PATH_MAX; /* 255? */ 1878 return 0; 1879 case _PC_CHOWN_RESTRICTED: 1880 *ap->a_retval = 1; 1881 return 0; 1882 case _PC_NO_TRUNC: 1883 *ap->a_retval = 0; 1884 return 0; 1885 default: 1886 return EINVAL; 1887 } 1888 } 1889 1890 /* Global vfs data structures for msdosfs */ 1891 int (**msdosfs_vnodeop_p)(); 1892 struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { 1893 { &vop_default_desc, vn_default_error }, 1894 { &vop_lookup_desc, msdosfs_lookup }, /* lookup */ 1895 { &vop_create_desc, msdosfs_create }, /* create */ 1896 { &vop_mknod_desc, msdosfs_mknod }, /* mknod */ 1897 { &vop_open_desc, msdosfs_open }, /* open */ 1898 { &vop_close_desc, msdosfs_close }, /* close */ 1899 { &vop_access_desc, msdosfs_access }, /* access */ 1900 { &vop_getattr_desc, msdosfs_getattr }, /* getattr */ 1901 { &vop_setattr_desc, msdosfs_setattr }, /* setattr */ 1902 { &vop_read_desc, msdosfs_read }, /* read */ 1903 { &vop_write_desc, msdosfs_write }, /* write */ 1904 { &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */ 1905 { &vop_select_desc, msdosfs_select }, /* select */ 1906 { &vop_mmap_desc, msdosfs_mmap }, /* mmap */ 1907 { &vop_fsync_desc, msdosfs_fsync }, /* fsync */ 1908 { &vop_seek_desc, msdosfs_seek }, /* seek */ 1909 { &vop_remove_desc, msdosfs_remove }, /* remove */ 1910 { &vop_link_desc, msdosfs_link }, /* link */ 1911 { &vop_rename_desc, msdosfs_rename }, /* rename */ 1912 { &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */ 1913 { &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */ 1914 { &vop_symlink_desc, msdosfs_symlink }, /* symlink */ 1915 { &vop_readdir_desc, msdosfs_readdir }, /* readdir */ 1916 { &vop_readlink_desc, msdosfs_readlink }, /* readlink */ 1917 { &vop_abortop_desc, msdosfs_abortop }, /* abortop */ 1918 { &vop_inactive_desc, msdosfs_inactive }, /* inactive */ 1919 { &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */ 1920 { &vop_lock_desc, msdosfs_lock }, /* lock */ 1921 { &vop_unlock_desc, msdosfs_unlock }, /* unlock */ 1922 { &vop_bmap_desc, msdosfs_bmap }, /* bmap */ 1923 { &vop_strategy_desc, msdosfs_strategy }, /* strategy */ 1924 { &vop_print_desc, msdosfs_print }, /* print */ 1925 { &vop_islocked_desc, msdosfs_islocked }, /* islocked */ 1926 { &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */ 1927 { &vop_advlock_desc, msdosfs_advlock }, /* advlock */ 1928 { &vop_reallocblks_desc, msdosfs_reallocblks }, /* reallocblks */ 1929 { &vop_bwrite_desc, vn_bwrite }, 1930 { (struct vnodeop_desc *)NULL, (int (*)())NULL } 1931 }; 1932 struct vnodeopv_desc msdosfs_vnodeop_opv_desc = 1933 { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries }; 1934