1 /* $NetBSD: msdosfs_vnops.c,v 1.19 2017/04/13 17:10:12 christos Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 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/cdefs.h> 53 __FBSDID("$FreeBSD$"); 54 55 #include <sys/param.h> 56 #include <sys/clock.h> 57 #include <sys/errno.h> 58 #include <sys/mman.h> 59 #include <sys/time.h> 60 61 #include <fcntl.h> 62 #include <stdbool.h> 63 #include <stdio.h> 64 #include <string.h> 65 #include <time.h> 66 #include <unistd.h> 67 68 #include "ffs/buf.h" 69 #include <fs/msdosfs/bpb.h> 70 #include "msdos/direntry.h" 71 #include <fs/msdosfs/denode.h> 72 #include <fs/msdosfs/fat.h> 73 #include <fs/msdosfs/msdosfsmount.h> 74 75 #include "makefs.h" 76 #include "msdos.h" 77 78 /* 79 * Some general notes: 80 * 81 * In the ufs filesystem the inodes, superblocks, and indirect blocks are 82 * read/written using the vnode for the filesystem. Blocks that represent 83 * the contents of a file are read/written using the vnode for the file 84 * (including directories when they are read/written as files). This 85 * presents problems for the dos filesystem because data that should be in 86 * an inode (if dos had them) resides in the directory itself. Since we 87 * must update directory entries without the benefit of having the vnode 88 * for the directory we must use the vnode for the filesystem. This means 89 * that when a directory is actually read/written (via read, write, or 90 * readdir, or seek) we must use the vnode for the filesystem instead of 91 * the vnode for the directory as would happen in ufs. This is to insure we 92 * retrieve the correct block from the buffer cache since the hash value is 93 * based upon the vnode address and the desired block number. 94 */ 95 96 static int msdosfs_wfile(const char *, struct denode *, fsnode *); 97 static void unix2fattime(const struct timespec *tsp, uint16_t *ddp, 98 uint16_t *dtp); 99 100 static void 101 msdosfs_times(struct denode *dep, const struct stat *st) 102 { 103 if (stampst.st_ino) 104 st = &stampst; 105 106 unix2fattime(&st->st_birthtim, &dep->de_CDate, &dep->de_CTime); 107 unix2fattime(&st->st_atim, &dep->de_ADate, NULL); 108 unix2fattime(&st->st_mtim, &dep->de_MDate, &dep->de_MTime); 109 } 110 111 static void 112 unix2fattime(const struct timespec *tsp, uint16_t *ddp, uint16_t *dtp) 113 { 114 time_t t1; 115 struct tm lt = {0}; 116 117 t1 = tsp->tv_sec; 118 localtime_r(&t1, <); 119 120 unsigned long fat_time = ((lt.tm_year - 80) << 25) | 121 ((lt.tm_mon + 1) << 21) | 122 (lt.tm_mday << 16) | 123 (lt.tm_hour << 11) | 124 (lt.tm_min << 5) | 125 (lt.tm_sec >> 1); 126 127 if (ddp != NULL) 128 *ddp = (uint16_t)(fat_time >> 16); 129 if (dtp != NULL) 130 *dtp = (uint16_t)fat_time; 131 } 132 133 /* 134 * When we search a directory the blocks containing directory entries are 135 * read and examined. The directory entries contain information that would 136 * normally be in the inode of a unix filesystem. This means that some of 137 * a directory's contents may also be in memory resident denodes (sort of 138 * an inode). This can cause problems if we are searching while some other 139 * process is modifying a directory. To prevent one process from accessing 140 * incompletely modified directory information we depend upon being the 141 * sole owner of a directory block. bread/brelse provide this service. 142 * This being the case, when a process modifies a directory it must first 143 * acquire the disk block that contains the directory entry to be modified. 144 * Then update the disk block and the denode, and then write the disk block 145 * out to disk. This way disk blocks containing directory entries and in 146 * memory denode's will be in synch. 147 */ 148 static int 149 msdosfs_findslot(struct denode *dp, struct componentname *cnp) 150 { 151 daddr_t bn; 152 int error; 153 int slotcount; 154 int slotoffset = 0; 155 int frcn; 156 u_long cluster; 157 int blkoff; 158 u_int diroff; 159 int blsize; 160 struct msdosfsmount *pmp; 161 struct buf *bp = 0; 162 struct direntry *dep; 163 u_char dosfilename[12]; 164 int wincnt = 1; 165 int chksum = -1, chksum_ok; 166 int olddos = 1; 167 168 pmp = dp->de_pmp; 169 170 switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 171 cnp->cn_namelen, 0)) { 172 case 0: 173 return (EINVAL); 174 case 1: 175 break; 176 case 2: 177 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 178 cnp->cn_namelen) + 1; 179 break; 180 case 3: 181 olddos = 0; 182 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 183 cnp->cn_namelen) + 1; 184 break; 185 } 186 187 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 188 wincnt = 1; 189 190 /* 191 * Suppress search for slots unless creating 192 * file and at end of pathname, in which case 193 * we watch for a place to put the new file in 194 * case it doesn't already exist. 195 */ 196 slotcount = 0; 197 MSDOSFS_DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename)); 198 /* 199 * Search the directory pointed at by vdp for the name pointed at 200 * by cnp->cn_nameptr. 201 */ 202 /* 203 * The outer loop ranges over the clusters that make up the 204 * directory. Note that the root directory is different from all 205 * other directories. It has a fixed number of blocks that are not 206 * part of the pool of allocatable clusters. So, we treat it a 207 * little differently. The root directory starts at "cluster" 0. 208 */ 209 diroff = 0; 210 for (frcn = 0; diroff < dp->de_FileSize; frcn++) { 211 if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { 212 if (error == E2BIG) 213 break; 214 return (error); 215 } 216 error = bread(pmp->pm_devvp, bn, blsize, 0, &bp); 217 if (error) { 218 return (error); 219 } 220 for (blkoff = 0; blkoff < blsize; 221 blkoff += sizeof(struct direntry), 222 diroff += sizeof(struct direntry)) { 223 dep = (struct direntry *)(bp->b_data + blkoff); 224 /* 225 * If the slot is empty and we are still looking 226 * for an empty then remember this one. If the 227 * slot is not empty then check to see if it 228 * matches what we are looking for. If the slot 229 * has never been filled with anything, then the 230 * remainder of the directory has never been used, 231 * so there is no point in searching it. 232 */ 233 if (dep->deName[0] == SLOT_EMPTY || 234 dep->deName[0] == SLOT_DELETED) { 235 /* 236 * Drop memory of previous long matches 237 */ 238 chksum = -1; 239 240 if (slotcount < wincnt) { 241 slotcount++; 242 slotoffset = diroff; 243 } 244 if (dep->deName[0] == SLOT_EMPTY) { 245 brelse(bp); 246 goto notfound; 247 } 248 } else { 249 /* 250 * If there wasn't enough space for our 251 * winentries, forget about the empty space 252 */ 253 if (slotcount < wincnt) 254 slotcount = 0; 255 256 /* 257 * Check for Win95 long filename entry 258 */ 259 if (dep->deAttributes == ATTR_WIN95) { 260 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 261 continue; 262 263 chksum = winChkName( 264 (const u_char *)cnp->cn_nameptr, 265 cnp->cn_namelen, 266 (struct winentry *)dep, chksum); 267 continue; 268 } 269 270 /* 271 * Ignore volume labels (anywhere, not just 272 * the root directory). 273 */ 274 if (dep->deAttributes & ATTR_VOLUME) { 275 chksum = -1; 276 continue; 277 } 278 279 /* 280 * Check for a checksum or name match 281 */ 282 chksum_ok = (chksum == winChksum(dep->deName)); 283 if (!chksum_ok 284 && (!olddos || memcmp(dosfilename, dep->deName, 11))) { 285 chksum = -1; 286 continue; 287 } 288 MSDOSFS_DPRINTF(("%s(): match blkoff %d, diroff %u\n", 289 __func__, blkoff, diroff)); 290 /* 291 * Remember where this directory 292 * entry came from for whoever did 293 * this lookup. 294 */ 295 dp->de_fndoffset = diroff; 296 dp->de_fndcnt = 0; 297 298 return EEXIST; 299 } 300 } /* for (blkoff = 0; .... */ 301 /* 302 * Release the buffer holding the directory cluster just 303 * searched. 304 */ 305 brelse(bp); 306 } /* for (frcn = 0; ; frcn++) */ 307 308 notfound: 309 /* 310 * We hold no disk buffers at this point. 311 */ 312 313 /* 314 * If we get here we didn't find the entry we were looking for. But 315 * that's ok if we are creating or renaming and are at the end of 316 * the pathname and the directory hasn't been removed. 317 */ 318 MSDOSFS_DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n", 319 __func__, dp->de_refcnt, slotcount, slotoffset)); 320 /* 321 * Fixup the slot description to point to the place where 322 * we might put the new DOS direntry (putting the Win95 323 * long name entries before that) 324 */ 325 if (!slotcount) { 326 slotcount = 1; 327 slotoffset = diroff; 328 } 329 if (wincnt > slotcount) { 330 slotoffset += sizeof(struct direntry) * (wincnt - slotcount); 331 } 332 333 /* 334 * Return an indication of where the new directory 335 * entry should be put. 336 */ 337 dp->de_fndoffset = slotoffset; 338 dp->de_fndcnt = wincnt - 1; 339 340 /* 341 * We return with the directory locked, so that 342 * the parameters we set up above will still be 343 * valid if we actually decide to do a direnter(). 344 * We return ni_vp == NULL to indicate that the entry 345 * does not currently exist; we leave a pointer to 346 * the (locked) directory inode in ndp->ni_dvp. 347 * 348 * NB - if the directory is unlocked, then this 349 * information cannot be used. 350 */ 351 return 0; 352 } 353 354 /* 355 * Create a regular file. On entry the directory to contain the file being 356 * created is locked. We must release before we return. 357 */ 358 struct denode * 359 msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node) 360 { 361 struct componentname cn; 362 struct denode ndirent; 363 struct denode *dep; 364 int error; 365 struct stat *st = &node->inode->st; 366 367 cn.cn_nameptr = node->name; 368 cn.cn_namelen = strlen(node->name); 369 370 MSDOSFS_DPRINTF(("%s(name %s, mode 0%o size %zu)\n", 371 __func__, node->name, st->st_mode, (size_t)st->st_size)); 372 373 /* 374 * If this is the root directory and there is no space left we 375 * can't do anything. This is because the root directory can not 376 * change size. 377 */ 378 if (pdep->de_StartCluster == MSDOSFSROOT 379 && pdep->de_fndoffset >= pdep->de_FileSize) { 380 error = ENOSPC; 381 goto bad; 382 } 383 384 /* 385 * Create a directory entry for the file, then call createde() to 386 * have it installed. NOTE: DOS files are always executable. We 387 * use the absence of the owner write bit to make the file 388 * readonly. 389 */ 390 memset(&ndirent, 0, sizeof(ndirent)); 391 if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0) 392 goto bad; 393 394 ndirent.de_Attributes = (st->st_mode & S_IWUSR) ? 395 ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY; 396 ndirent.de_StartCluster = 0; 397 ndirent.de_FileSize = 0; 398 ndirent.de_pmp = pdep->de_pmp; 399 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; 400 msdosfs_times(&ndirent, &node->inode->st); 401 402 if ((error = msdosfs_findslot(pdep, &cn)) != 0) 403 goto bad; 404 if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) 405 goto bad; 406 if ((error = msdosfs_wfile(path, dep, node)) != 0) 407 goto bad; 408 return dep; 409 410 bad: 411 errno = error; 412 return NULL; 413 } 414 static int 415 msdosfs_updatede(struct denode *dep) 416 { 417 struct buf *bp; 418 struct direntry *dirp; 419 int error; 420 421 dep->de_flag &= ~DE_MODIFIED; 422 error = readde(dep, &bp, &dirp); 423 if (error) 424 return error; 425 DE_EXTERNALIZE(dirp, dep); 426 error = bwrite(bp); 427 return error; 428 } 429 430 /* 431 * Write data to a file or directory. 432 */ 433 static int 434 msdosfs_wfile(const char *path, struct denode *dep, fsnode *node) 435 { 436 int error, fd; 437 size_t osize = dep->de_FileSize; 438 struct stat *st = &node->inode->st; 439 size_t nsize, offs; 440 struct msdosfsmount *pmp = dep->de_pmp; 441 struct buf *bp; 442 char *dat; 443 u_long cn = 0; 444 445 error = 0; /* XXX: gcc/vax */ 446 MSDOSFS_DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", 447 __func__, dep->de_diroffset, dep->de_dirclust, 448 dep->de_StartCluster)); 449 if (st->st_size == 0) 450 return 0; 451 452 /* Don't bother to try to write files larger than the fs limit */ 453 if (st->st_size > MSDOSFS_FILESIZE_MAX) 454 return EFBIG; 455 456 nsize = st->st_size; 457 MSDOSFS_DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize)); 458 if (nsize > osize) { 459 if ((error = deextend(dep, nsize, NULL)) != 0) 460 return error; 461 if ((error = msdosfs_updatede(dep)) != 0) 462 return error; 463 } 464 465 if ((fd = open(path, O_RDONLY)) == -1) { 466 error = errno; 467 MSDOSFS_DPRINTF(("open %s: %s", path, strerror(error))); 468 return error; 469 } 470 471 if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) 472 == MAP_FAILED) { 473 error = errno; 474 MSDOSFS_DPRINTF(("%s: mmap %s: %s", __func__, node->name, 475 strerror(error))); 476 close(fd); 477 goto out; 478 } 479 close(fd); 480 481 for (offs = 0; offs < nsize;) { 482 int blsize, cpsize; 483 daddr_t bn; 484 u_long on = offs & pmp->pm_crbomask; 485 486 if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) { 487 MSDOSFS_DPRINTF(("%s: pcbmap %lu", 488 __func__, (unsigned long)bn)); 489 goto out; 490 } 491 492 MSDOSFS_DPRINTF(("%s(cn=%lu, bn=%llu, blsize=%d)\n", 493 __func__, cn, (unsigned long long)bn, blsize)); 494 if ((error = bread(pmp->pm_devvp, bn, blsize, 0, &bp)) != 0) { 495 MSDOSFS_DPRINTF(("bread %d\n", error)); 496 goto out; 497 } 498 cpsize = MIN((nsize - offs), blsize - on); 499 memcpy(bp->b_data + on, dat + offs, cpsize); 500 bwrite(bp); 501 offs += cpsize; 502 } 503 504 munmap(dat, nsize); 505 return 0; 506 out: 507 munmap(dat, nsize); 508 return error; 509 } 510 511 static const struct { 512 struct direntry dot; 513 struct direntry dotdot; 514 } dosdirtemplate = { 515 { ". ", /* the . entry */ 516 ATTR_DIRECTORY, /* file attribute */ 517 0, /* reserved */ 518 0, { 0, 0 }, { 0, 0 }, /* create time & date */ 519 { 0, 0 }, /* access date */ 520 { 0, 0 }, /* high bits of start cluster */ 521 { 210, 4 }, { 210, 4 }, /* modify time & date */ 522 { 0, 0 }, /* startcluster */ 523 { 0, 0, 0, 0 } /* filesize */ 524 }, 525 { ".. ", /* the .. entry */ 526 ATTR_DIRECTORY, /* file attribute */ 527 0, /* reserved */ 528 0, { 0, 0 }, { 0, 0 }, /* create time & date */ 529 { 0, 0 }, /* access date */ 530 { 0, 0 }, /* high bits of start cluster */ 531 { 210, 4 }, { 210, 4 }, /* modify time & date */ 532 { 0, 0 }, /* startcluster */ 533 { 0, 0, 0, 0 } /* filesize */ 534 } 535 }; 536 537 struct denode * 538 msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) { 539 struct denode ndirent; 540 struct denode *dep; 541 struct componentname cn; 542 struct msdosfsmount *pmp = pdep->de_pmp; 543 int error; 544 u_long newcluster, pcl, bn; 545 struct direntry *denp; 546 struct buf *bp; 547 548 cn.cn_nameptr = node->name; 549 cn.cn_namelen = strlen(node->name); 550 /* 551 * If this is the root directory and there is no space left we 552 * can't do anything. This is because the root directory can not 553 * change size. 554 */ 555 if (pdep->de_StartCluster == MSDOSFSROOT 556 && pdep->de_fndoffset >= pdep->de_FileSize) { 557 error = ENOSPC; 558 goto bad2; 559 } 560 561 /* 562 * Allocate a cluster to hold the about to be created directory. 563 */ 564 error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL); 565 if (error) 566 goto bad2; 567 568 memset(&ndirent, 0, sizeof(ndirent)); 569 ndirent.de_pmp = pmp; 570 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; 571 msdosfs_times(&ndirent, &node->inode->st); 572 573 /* 574 * Now fill the cluster with the "." and ".." entries. And write 575 * the cluster to disk. This way it is there for the parent 576 * directory to be pointing at if there were a crash. 577 */ 578 bn = cntobn(pmp, newcluster); 579 MSDOSFS_DPRINTF(("%s(newcluster %lu, bn=%lu)\n", 580 __func__, newcluster, bn)); 581 /* always succeeds */ 582 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0); 583 memset(bp->b_data, 0, pmp->pm_bpcluster); 584 memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); 585 denp = (struct direntry *)bp->b_data; 586 putushort(denp[0].deStartCluster, newcluster); 587 putushort(denp[0].deCDate, ndirent.de_CDate); 588 putushort(denp[0].deCTime, ndirent.de_CTime); 589 denp[0].deCHundredth = ndirent.de_CHun; 590 putushort(denp[0].deADate, ndirent.de_ADate); 591 putushort(denp[0].deMDate, ndirent.de_MDate); 592 putushort(denp[0].deMTime, ndirent.de_MTime); 593 pcl = pdep->de_StartCluster; 594 MSDOSFS_DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl, 595 pmp->pm_rootdirblk)); 596 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) 597 pcl = 0; 598 putushort(denp[1].deStartCluster, pcl); 599 putushort(denp[1].deCDate, ndirent.de_CDate); 600 putushort(denp[1].deCTime, ndirent.de_CTime); 601 denp[1].deCHundredth = ndirent.de_CHun; 602 putushort(denp[1].deADate, ndirent.de_ADate); 603 putushort(denp[1].deMDate, ndirent.de_MDate); 604 putushort(denp[1].deMTime, ndirent.de_MTime); 605 if (FAT32(pmp)) { 606 putushort(denp[0].deHighClust, newcluster >> 16); 607 putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); 608 } else { 609 putushort(denp[0].deHighClust, 0); 610 putushort(denp[1].deHighClust, 0); 611 } 612 613 if ((error = bwrite(bp)) != 0) 614 goto bad; 615 616 /* 617 * Now build up a directory entry pointing to the newly allocated 618 * cluster. This will be written to an empty slot in the parent 619 * directory. 620 */ 621 if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0) 622 goto bad; 623 624 ndirent.de_Attributes = ATTR_DIRECTORY; 625 ndirent.de_StartCluster = newcluster; 626 ndirent.de_FileSize = 0; 627 ndirent.de_pmp = pdep->de_pmp; 628 if ((error = msdosfs_findslot(pdep, &cn)) != 0) 629 goto bad; 630 if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) 631 goto bad; 632 if ((error = msdosfs_updatede(dep)) != 0) 633 goto bad; 634 return dep; 635 636 bad: 637 clusterfree(pmp, newcluster, NULL); 638 bad2: 639 errno = error; 640 return NULL; 641 } 642