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