1*0a6a1f1dSLionel Sambuc /* $NetBSD: msdosfs_vnops.c,v 1.16 2015/03/29 05:52:59 agc Exp $ */
29f988b79SJean-Baptiste Boric
39f988b79SJean-Baptiste Boric /*-
49f988b79SJean-Baptiste Boric * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
59f988b79SJean-Baptiste Boric * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
69f988b79SJean-Baptiste Boric * All rights reserved.
79f988b79SJean-Baptiste Boric * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
89f988b79SJean-Baptiste Boric *
99f988b79SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
109f988b79SJean-Baptiste Boric * modification, are permitted provided that the following conditions
119f988b79SJean-Baptiste Boric * are met:
129f988b79SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
139f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
149f988b79SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
159f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in the
169f988b79SJean-Baptiste Boric * documentation and/or other materials provided with the distribution.
179f988b79SJean-Baptiste Boric * 3. All advertising materials mentioning features or use of this software
189f988b79SJean-Baptiste Boric * must display the following acknowledgement:
199f988b79SJean-Baptiste Boric * This product includes software developed by TooLs GmbH.
209f988b79SJean-Baptiste Boric * 4. The name of TooLs GmbH may not be used to endorse or promote products
219f988b79SJean-Baptiste Boric * derived from this software without specific prior written permission.
229f988b79SJean-Baptiste Boric *
239f988b79SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
249f988b79SJean-Baptiste Boric * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
259f988b79SJean-Baptiste Boric * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
269f988b79SJean-Baptiste Boric * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
279f988b79SJean-Baptiste Boric * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
289f988b79SJean-Baptiste Boric * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
299f988b79SJean-Baptiste Boric * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
309f988b79SJean-Baptiste Boric * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
319f988b79SJean-Baptiste Boric * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
329f988b79SJean-Baptiste Boric * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
339f988b79SJean-Baptiste Boric */
349f988b79SJean-Baptiste Boric /*
359f988b79SJean-Baptiste Boric * Written by Paul Popelka (paulp@uts.amdahl.com)
369f988b79SJean-Baptiste Boric *
379f988b79SJean-Baptiste Boric * You can do anything you want with this software, just don't say you wrote
389f988b79SJean-Baptiste Boric * it, and don't remove this notice.
399f988b79SJean-Baptiste Boric *
409f988b79SJean-Baptiste Boric * This software is provided "as is".
419f988b79SJean-Baptiste Boric *
429f988b79SJean-Baptiste Boric * The author supplies this software to be publicly redistributed on the
439f988b79SJean-Baptiste Boric * understanding that the author is not responsible for the correct
449f988b79SJean-Baptiste Boric * functioning of this software in any circumstances and is not liable for
459f988b79SJean-Baptiste Boric * any damages caused by this software.
469f988b79SJean-Baptiste Boric *
479f988b79SJean-Baptiste Boric * October 1992
489f988b79SJean-Baptiste Boric */
499f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
509f988b79SJean-Baptiste Boric #include "nbtool_config.h"
519f988b79SJean-Baptiste Boric #endif
529f988b79SJean-Baptiste Boric
539f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
54*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.16 2015/03/29 05:52:59 agc Exp $");
559f988b79SJean-Baptiste Boric
569f988b79SJean-Baptiste Boric #include <sys/param.h>
579f988b79SJean-Baptiste Boric #include <sys/mman.h>
589f988b79SJean-Baptiste Boric #include <fcntl.h>
599f988b79SJean-Baptiste Boric #include <unistd.h>
609f988b79SJean-Baptiste Boric
619f988b79SJean-Baptiste Boric #include <ffs/buf.h>
629f988b79SJean-Baptiste Boric
639f988b79SJean-Baptiste Boric #include <fs/msdosfs/bpb.h>
649f988b79SJean-Baptiste Boric #include <fs/msdosfs/direntry.h>
659f988b79SJean-Baptiste Boric #include <fs/msdosfs/denode.h>
669f988b79SJean-Baptiste Boric #include <fs/msdosfs/msdosfsmount.h>
679f988b79SJean-Baptiste Boric #include <fs/msdosfs/fat.h>
689f988b79SJean-Baptiste Boric
699f988b79SJean-Baptiste Boric #include "makefs.h"
709f988b79SJean-Baptiste Boric #include "msdos.h"
719f988b79SJean-Baptiste Boric
729f988b79SJean-Baptiste Boric #ifdef MSDOSFS_DEBUG
739f988b79SJean-Baptiste Boric #define DPRINTF(a) printf a
749f988b79SJean-Baptiste Boric #else
759f988b79SJean-Baptiste Boric #define DPRINTF(a)
769f988b79SJean-Baptiste Boric #endif
779f988b79SJean-Baptiste Boric /*
789f988b79SJean-Baptiste Boric * Some general notes:
799f988b79SJean-Baptiste Boric *
809f988b79SJean-Baptiste Boric * In the ufs filesystem the inodes, superblocks, and indirect blocks are
819f988b79SJean-Baptiste Boric * read/written using the vnode for the filesystem. Blocks that represent
829f988b79SJean-Baptiste Boric * the contents of a file are read/written using the vnode for the file
839f988b79SJean-Baptiste Boric * (including directories when they are read/written as files). This
849f988b79SJean-Baptiste Boric * presents problems for the dos filesystem because data that should be in
859f988b79SJean-Baptiste Boric * an inode (if dos had them) resides in the directory itself. Since we
869f988b79SJean-Baptiste Boric * must update directory entries without the benefit of having the vnode
879f988b79SJean-Baptiste Boric * for the directory we must use the vnode for the filesystem. This means
889f988b79SJean-Baptiste Boric * that when a directory is actually read/written (via read, write, or
899f988b79SJean-Baptiste Boric * readdir, or seek) we must use the vnode for the filesystem instead of
909f988b79SJean-Baptiste Boric * the vnode for the directory as would happen in ufs. This is to insure we
919f988b79SJean-Baptiste Boric * retrieve the correct block from the buffer cache since the hash value is
929f988b79SJean-Baptiste Boric * based upon the vnode address and the desired block number.
939f988b79SJean-Baptiste Boric */
949f988b79SJean-Baptiste Boric
959f988b79SJean-Baptiste Boric static int msdosfs_wfile(const char *, struct denode *, fsnode *);
969f988b79SJean-Baptiste Boric
979f988b79SJean-Baptiste Boric static void
msdosfs_times(struct msdosfsmount * pmp,struct denode * dep,const struct stat * st)989f988b79SJean-Baptiste Boric msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
999f988b79SJean-Baptiste Boric const struct stat *st)
1009f988b79SJean-Baptiste Boric {
1019f988b79SJean-Baptiste Boric #ifndef HAVE_NBTOOL_CONFIG_H
1029f988b79SJean-Baptiste Boric struct timespec at = st->st_atimespec;
1039f988b79SJean-Baptiste Boric struct timespec mt = st->st_mtimespec;
1049f988b79SJean-Baptiste Boric #else
1059f988b79SJean-Baptiste Boric struct timespec at = { st->st_atime, 0 };
1069f988b79SJean-Baptiste Boric struct timespec mt = { st->st_mtime, 0 };
1079f988b79SJean-Baptiste Boric #endif
1089f988b79SJean-Baptiste Boric unix2dostime(&at, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL);
1099f988b79SJean-Baptiste Boric unix2dostime(&mt, pmp->pm_gmtoff, &dep->de_MDate, &dep->de_MTime, NULL);
1109f988b79SJean-Baptiste Boric }
1119f988b79SJean-Baptiste Boric
1129f988b79SJean-Baptiste Boric /*
1139f988b79SJean-Baptiste Boric * When we search a directory the blocks containing directory entries are
1149f988b79SJean-Baptiste Boric * read and examined. The directory entries contain information that would
1159f988b79SJean-Baptiste Boric * normally be in the inode of a unix filesystem. This means that some of
1169f988b79SJean-Baptiste Boric * a directory's contents may also be in memory resident denodes (sort of
1179f988b79SJean-Baptiste Boric * an inode). This can cause problems if we are searching while some other
1189f988b79SJean-Baptiste Boric * process is modifying a directory. To prevent one process from accessing
1199f988b79SJean-Baptiste Boric * incompletely modified directory information we depend upon being the
1209f988b79SJean-Baptiste Boric * sole owner of a directory block. bread/brelse provide this service.
1219f988b79SJean-Baptiste Boric * This being the case, when a process modifies a directory it must first
1229f988b79SJean-Baptiste Boric * acquire the disk block that contains the directory entry to be modified.
1239f988b79SJean-Baptiste Boric * Then update the disk block and the denode, and then write the disk block
1249f988b79SJean-Baptiste Boric * out to disk. This way disk blocks containing directory entries and in
1259f988b79SJean-Baptiste Boric * memory denode's will be in synch.
1269f988b79SJean-Baptiste Boric */
1279f988b79SJean-Baptiste Boric static int
msdosfs_findslot(struct denode * dp,struct componentname * cnp)1289f988b79SJean-Baptiste Boric msdosfs_findslot(struct denode *dp, struct componentname *cnp)
1299f988b79SJean-Baptiste Boric {
1309f988b79SJean-Baptiste Boric daddr_t bn;
1319f988b79SJean-Baptiste Boric int error;
1329f988b79SJean-Baptiste Boric int slotcount;
1339f988b79SJean-Baptiste Boric int slotoffset = 0;
1349f988b79SJean-Baptiste Boric int frcn;
1359f988b79SJean-Baptiste Boric u_long cluster;
1369f988b79SJean-Baptiste Boric int blkoff;
1379f988b79SJean-Baptiste Boric u_int diroff;
1389f988b79SJean-Baptiste Boric int blsize;
1399f988b79SJean-Baptiste Boric struct msdosfsmount *pmp;
1409f988b79SJean-Baptiste Boric struct buf *bp = 0;
1419f988b79SJean-Baptiste Boric struct direntry *dep;
1429f988b79SJean-Baptiste Boric u_char dosfilename[12];
1439f988b79SJean-Baptiste Boric int wincnt = 1;
1449f988b79SJean-Baptiste Boric int chksum = -1, chksum_ok;
1459f988b79SJean-Baptiste Boric int olddos = 1;
1469f988b79SJean-Baptiste Boric
1479f988b79SJean-Baptiste Boric pmp = dp->de_pmp;
1489f988b79SJean-Baptiste Boric
1499f988b79SJean-Baptiste Boric switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
1509f988b79SJean-Baptiste Boric cnp->cn_namelen, 0)) {
1519f988b79SJean-Baptiste Boric case 0:
1529f988b79SJean-Baptiste Boric return (EINVAL);
1539f988b79SJean-Baptiste Boric case 1:
1549f988b79SJean-Baptiste Boric break;
1559f988b79SJean-Baptiste Boric case 2:
1569f988b79SJean-Baptiste Boric wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
1579f988b79SJean-Baptiste Boric cnp->cn_namelen) + 1;
1589f988b79SJean-Baptiste Boric break;
1599f988b79SJean-Baptiste Boric case 3:
1609f988b79SJean-Baptiste Boric olddos = 0;
1619f988b79SJean-Baptiste Boric wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
1629f988b79SJean-Baptiste Boric cnp->cn_namelen) + 1;
1639f988b79SJean-Baptiste Boric break;
1649f988b79SJean-Baptiste Boric }
1659f988b79SJean-Baptiste Boric
1669f988b79SJean-Baptiste Boric if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
1679f988b79SJean-Baptiste Boric wincnt = 1;
1689f988b79SJean-Baptiste Boric
1699f988b79SJean-Baptiste Boric /*
1709f988b79SJean-Baptiste Boric * Suppress search for slots unless creating
1719f988b79SJean-Baptiste Boric * file and at end of pathname, in which case
1729f988b79SJean-Baptiste Boric * we watch for a place to put the new file in
1739f988b79SJean-Baptiste Boric * case it doesn't already exist.
1749f988b79SJean-Baptiste Boric */
1759f988b79SJean-Baptiste Boric slotcount = 0;
1769f988b79SJean-Baptiste Boric DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename));
1779f988b79SJean-Baptiste Boric /*
1789f988b79SJean-Baptiste Boric * Search the directory pointed at by vdp for the name pointed at
1799f988b79SJean-Baptiste Boric * by cnp->cn_nameptr.
1809f988b79SJean-Baptiste Boric */
1819f988b79SJean-Baptiste Boric /*
1829f988b79SJean-Baptiste Boric * The outer loop ranges over the clusters that make up the
1839f988b79SJean-Baptiste Boric * directory. Note that the root directory is different from all
1849f988b79SJean-Baptiste Boric * other directories. It has a fixed number of blocks that are not
1859f988b79SJean-Baptiste Boric * part of the pool of allocatable clusters. So, we treat it a
1869f988b79SJean-Baptiste Boric * little differently. The root directory starts at "cluster" 0.
1879f988b79SJean-Baptiste Boric */
1889f988b79SJean-Baptiste Boric diroff = 0;
1899f988b79SJean-Baptiste Boric for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
1909f988b79SJean-Baptiste Boric if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
1919f988b79SJean-Baptiste Boric if (error == E2BIG)
1929f988b79SJean-Baptiste Boric break;
1939f988b79SJean-Baptiste Boric return (error);
1949f988b79SJean-Baptiste Boric }
195*0a6a1f1dSLionel Sambuc error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
1969f988b79SJean-Baptiste Boric 0, &bp);
1979f988b79SJean-Baptiste Boric if (error) {
1989f988b79SJean-Baptiste Boric return (error);
1999f988b79SJean-Baptiste Boric }
2009f988b79SJean-Baptiste Boric for (blkoff = 0; blkoff < blsize;
2019f988b79SJean-Baptiste Boric blkoff += sizeof(struct direntry),
2029f988b79SJean-Baptiste Boric diroff += sizeof(struct direntry)) {
2039f988b79SJean-Baptiste Boric dep = (struct direntry *)((char *)bp->b_data + blkoff);
2049f988b79SJean-Baptiste Boric /*
2059f988b79SJean-Baptiste Boric * If the slot is empty and we are still looking
2069f988b79SJean-Baptiste Boric * for an empty then remember this one. If the
2079f988b79SJean-Baptiste Boric * slot is not empty then check to see if it
2089f988b79SJean-Baptiste Boric * matches what we are looking for. If the slot
2099f988b79SJean-Baptiste Boric * has never been filled with anything, then the
2109f988b79SJean-Baptiste Boric * remainder of the directory has never been used,
2119f988b79SJean-Baptiste Boric * so there is no point in searching it.
2129f988b79SJean-Baptiste Boric */
2139f988b79SJean-Baptiste Boric if (dep->deName[0] == SLOT_EMPTY ||
2149f988b79SJean-Baptiste Boric dep->deName[0] == SLOT_DELETED) {
2159f988b79SJean-Baptiste Boric /*
2169f988b79SJean-Baptiste Boric * Drop memory of previous long matches
2179f988b79SJean-Baptiste Boric */
2189f988b79SJean-Baptiste Boric chksum = -1;
2199f988b79SJean-Baptiste Boric
2209f988b79SJean-Baptiste Boric if (slotcount < wincnt) {
2219f988b79SJean-Baptiste Boric slotcount++;
2229f988b79SJean-Baptiste Boric slotoffset = diroff;
2239f988b79SJean-Baptiste Boric }
2249f988b79SJean-Baptiste Boric if (dep->deName[0] == SLOT_EMPTY) {
2259f988b79SJean-Baptiste Boric brelse(bp, 0);
2269f988b79SJean-Baptiste Boric goto notfound;
2279f988b79SJean-Baptiste Boric }
2289f988b79SJean-Baptiste Boric } else {
2299f988b79SJean-Baptiste Boric /*
2309f988b79SJean-Baptiste Boric * If there wasn't enough space for our
2319f988b79SJean-Baptiste Boric * winentries, forget about the empty space
2329f988b79SJean-Baptiste Boric */
2339f988b79SJean-Baptiste Boric if (slotcount < wincnt)
2349f988b79SJean-Baptiste Boric slotcount = 0;
2359f988b79SJean-Baptiste Boric
2369f988b79SJean-Baptiste Boric /*
2379f988b79SJean-Baptiste Boric * Check for Win95 long filename entry
2389f988b79SJean-Baptiste Boric */
2399f988b79SJean-Baptiste Boric if (dep->deAttributes == ATTR_WIN95) {
2409f988b79SJean-Baptiste Boric if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
2419f988b79SJean-Baptiste Boric continue;
2429f988b79SJean-Baptiste Boric
2439f988b79SJean-Baptiste Boric chksum = winChkName((const u_char *)cnp->cn_nameptr,
2449f988b79SJean-Baptiste Boric cnp->cn_namelen,
2459f988b79SJean-Baptiste Boric (struct winentry *)dep,
2469f988b79SJean-Baptiste Boric chksum);
2479f988b79SJean-Baptiste Boric continue;
2489f988b79SJean-Baptiste Boric }
2499f988b79SJean-Baptiste Boric
2509f988b79SJean-Baptiste Boric /*
2519f988b79SJean-Baptiste Boric * Ignore volume labels (anywhere, not just
2529f988b79SJean-Baptiste Boric * the root directory).
2539f988b79SJean-Baptiste Boric */
2549f988b79SJean-Baptiste Boric if (dep->deAttributes & ATTR_VOLUME) {
2559f988b79SJean-Baptiste Boric chksum = -1;
2569f988b79SJean-Baptiste Boric continue;
2579f988b79SJean-Baptiste Boric }
2589f988b79SJean-Baptiste Boric
2599f988b79SJean-Baptiste Boric /*
2609f988b79SJean-Baptiste Boric * Check for a checksum or name match
2619f988b79SJean-Baptiste Boric */
2629f988b79SJean-Baptiste Boric chksum_ok = (chksum == winChksum(dep->deName));
2639f988b79SJean-Baptiste Boric if (!chksum_ok
2649f988b79SJean-Baptiste Boric && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
2659f988b79SJean-Baptiste Boric chksum = -1;
2669f988b79SJean-Baptiste Boric continue;
2679f988b79SJean-Baptiste Boric }
2689f988b79SJean-Baptiste Boric DPRINTF(("%s(): match blkoff %d, diroff %d\n",
2699f988b79SJean-Baptiste Boric __func__, blkoff, diroff));
2709f988b79SJean-Baptiste Boric /*
2719f988b79SJean-Baptiste Boric * Remember where this directory
2729f988b79SJean-Baptiste Boric * entry came from for whoever did
2739f988b79SJean-Baptiste Boric * this lookup.
2749f988b79SJean-Baptiste Boric */
2759f988b79SJean-Baptiste Boric dp->de_fndoffset = diroff;
2769f988b79SJean-Baptiste Boric dp->de_fndcnt = 0;
2779f988b79SJean-Baptiste Boric
2789f988b79SJean-Baptiste Boric return EEXIST;
2799f988b79SJean-Baptiste Boric }
2809f988b79SJean-Baptiste Boric } /* for (blkoff = 0; .... */
2819f988b79SJean-Baptiste Boric /*
2829f988b79SJean-Baptiste Boric * Release the buffer holding the directory cluster just
2839f988b79SJean-Baptiste Boric * searched.
2849f988b79SJean-Baptiste Boric */
2859f988b79SJean-Baptiste Boric brelse(bp, 0);
2869f988b79SJean-Baptiste Boric } /* for (frcn = 0; ; frcn++) */
2879f988b79SJean-Baptiste Boric
2889f988b79SJean-Baptiste Boric notfound:
2899f988b79SJean-Baptiste Boric /*
2909f988b79SJean-Baptiste Boric * We hold no disk buffers at this point.
2919f988b79SJean-Baptiste Boric */
2929f988b79SJean-Baptiste Boric
2939f988b79SJean-Baptiste Boric /*
2949f988b79SJean-Baptiste Boric * If we get here we didn't find the entry we were looking for. But
2959f988b79SJean-Baptiste Boric * that's ok if we are creating or renaming and are at the end of
2969f988b79SJean-Baptiste Boric * the pathname and the directory hasn't been removed.
2979f988b79SJean-Baptiste Boric */
2989f988b79SJean-Baptiste Boric DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n",
2999f988b79SJean-Baptiste Boric __func__, dp->de_refcnt, slotcount, slotoffset));
3009f988b79SJean-Baptiste Boric /*
3019f988b79SJean-Baptiste Boric * Fixup the slot description to point to the place where
3029f988b79SJean-Baptiste Boric * we might put the new DOS direntry (putting the Win95
3039f988b79SJean-Baptiste Boric * long name entries before that)
3049f988b79SJean-Baptiste Boric */
3059f988b79SJean-Baptiste Boric if (!slotcount) {
3069f988b79SJean-Baptiste Boric slotcount = 1;
3079f988b79SJean-Baptiste Boric slotoffset = diroff;
3089f988b79SJean-Baptiste Boric }
3099f988b79SJean-Baptiste Boric if (wincnt > slotcount) {
3109f988b79SJean-Baptiste Boric slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
3119f988b79SJean-Baptiste Boric }
3129f988b79SJean-Baptiste Boric
3139f988b79SJean-Baptiste Boric /*
3149f988b79SJean-Baptiste Boric * Return an indication of where the new directory
3159f988b79SJean-Baptiste Boric * entry should be put.
3169f988b79SJean-Baptiste Boric */
3179f988b79SJean-Baptiste Boric dp->de_fndoffset = slotoffset;
3189f988b79SJean-Baptiste Boric dp->de_fndcnt = wincnt - 1;
3199f988b79SJean-Baptiste Boric
3209f988b79SJean-Baptiste Boric /*
3219f988b79SJean-Baptiste Boric * We return with the directory locked, so that
3229f988b79SJean-Baptiste Boric * the parameters we set up above will still be
3239f988b79SJean-Baptiste Boric * valid if we actually decide to do a direnter().
3249f988b79SJean-Baptiste Boric * We return ni_vp == NULL to indicate that the entry
3259f988b79SJean-Baptiste Boric * does not currently exist; we leave a pointer to
3269f988b79SJean-Baptiste Boric * the (locked) directory inode in ndp->ni_dvp.
3279f988b79SJean-Baptiste Boric *
3289f988b79SJean-Baptiste Boric * NB - if the directory is unlocked, then this
3299f988b79SJean-Baptiste Boric * information cannot be used.
3309f988b79SJean-Baptiste Boric */
3319f988b79SJean-Baptiste Boric return 0;
3329f988b79SJean-Baptiste Boric }
3339f988b79SJean-Baptiste Boric
3349f988b79SJean-Baptiste Boric /*
3359f988b79SJean-Baptiste Boric * Create a regular file. On entry the directory to contain the file being
3369f988b79SJean-Baptiste Boric * created is locked. We must release before we return.
3379f988b79SJean-Baptiste Boric */
3389f988b79SJean-Baptiste Boric struct denode *
msdosfs_mkfile(const char * path,struct denode * pdep,fsnode * node)3399f988b79SJean-Baptiste Boric msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
3409f988b79SJean-Baptiste Boric {
3419f988b79SJean-Baptiste Boric struct componentname cn;
3429f988b79SJean-Baptiste Boric struct denode ndirent;
3439f988b79SJean-Baptiste Boric struct denode *dep;
3449f988b79SJean-Baptiste Boric int error;
3459f988b79SJean-Baptiste Boric struct stat *st = &node->inode->st;
3469f988b79SJean-Baptiste Boric struct msdosfsmount *pmp = pdep->de_pmp;
3479f988b79SJean-Baptiste Boric
3489f988b79SJean-Baptiste Boric cn.cn_nameptr = node->name;
3499f988b79SJean-Baptiste Boric cn.cn_namelen = strlen(node->name);
3509f988b79SJean-Baptiste Boric
3519f988b79SJean-Baptiste Boric DPRINTF(("%s(name %s, mode 0%o size %zu)\n", __func__, node->name,
3529f988b79SJean-Baptiste Boric st->st_mode, (size_t)st->st_size));
3539f988b79SJean-Baptiste Boric
3549f988b79SJean-Baptiste Boric /*
3559f988b79SJean-Baptiste Boric * If this is the root directory and there is no space left we
3569f988b79SJean-Baptiste Boric * can't do anything. This is because the root directory can not
3579f988b79SJean-Baptiste Boric * change size.
3589f988b79SJean-Baptiste Boric */
3599f988b79SJean-Baptiste Boric if (pdep->de_StartCluster == MSDOSFSROOT
3609f988b79SJean-Baptiste Boric && pdep->de_fndoffset >= pdep->de_FileSize) {
3619f988b79SJean-Baptiste Boric error = ENOSPC;
3629f988b79SJean-Baptiste Boric goto bad;
3639f988b79SJean-Baptiste Boric }
3649f988b79SJean-Baptiste Boric
3659f988b79SJean-Baptiste Boric /*
3669f988b79SJean-Baptiste Boric * Create a directory entry for the file, then call createde() to
3679f988b79SJean-Baptiste Boric * have it installed. NOTE: DOS files are always executable. We
3689f988b79SJean-Baptiste Boric * use the absence of the owner write bit to make the file
3699f988b79SJean-Baptiste Boric * readonly.
3709f988b79SJean-Baptiste Boric */
3719f988b79SJean-Baptiste Boric memset(&ndirent, 0, sizeof(ndirent));
3729f988b79SJean-Baptiste Boric if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
3739f988b79SJean-Baptiste Boric goto bad;
3749f988b79SJean-Baptiste Boric
3759f988b79SJean-Baptiste Boric ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
3769f988b79SJean-Baptiste Boric ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
3779f988b79SJean-Baptiste Boric ndirent.de_StartCluster = 0;
3789f988b79SJean-Baptiste Boric ndirent.de_FileSize = 0;
3799f988b79SJean-Baptiste Boric ndirent.de_dev = pdep->de_dev;
3809f988b79SJean-Baptiste Boric ndirent.de_devvp = pdep->de_devvp;
3819f988b79SJean-Baptiste Boric ndirent.de_pmp = pdep->de_pmp;
3829f988b79SJean-Baptiste Boric ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
3839f988b79SJean-Baptiste Boric msdosfs_times(pmp, &ndirent, st);
3849f988b79SJean-Baptiste Boric if ((error = msdosfs_findslot(pdep, &cn)) != 0)
3859f988b79SJean-Baptiste Boric goto bad;
3869f988b79SJean-Baptiste Boric if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
3879f988b79SJean-Baptiste Boric goto bad;
3889f988b79SJean-Baptiste Boric if ((error = msdosfs_wfile(path, dep, node)) != 0)
3899f988b79SJean-Baptiste Boric goto bad;
3909f988b79SJean-Baptiste Boric return dep;
3919f988b79SJean-Baptiste Boric
3929f988b79SJean-Baptiste Boric bad:
3939f988b79SJean-Baptiste Boric errno = error;
3949f988b79SJean-Baptiste Boric return NULL;
3959f988b79SJean-Baptiste Boric }
3969f988b79SJean-Baptiste Boric static int
msdosfs_updatede(struct denode * dep)3979f988b79SJean-Baptiste Boric msdosfs_updatede(struct denode *dep)
3989f988b79SJean-Baptiste Boric {
3999f988b79SJean-Baptiste Boric struct buf *bp;
4009f988b79SJean-Baptiste Boric struct direntry *dirp;
4019f988b79SJean-Baptiste Boric int error;
4029f988b79SJean-Baptiste Boric
4039f988b79SJean-Baptiste Boric dep->de_flag &= ~DE_MODIFIED;
4049f988b79SJean-Baptiste Boric error = readde(dep, &bp, &dirp);
4059f988b79SJean-Baptiste Boric if (error)
4069f988b79SJean-Baptiste Boric return error;
4079f988b79SJean-Baptiste Boric DE_EXTERNALIZE(dirp, dep);
4089f988b79SJean-Baptiste Boric error = bwrite(bp);
4099f988b79SJean-Baptiste Boric return error;
4109f988b79SJean-Baptiste Boric }
4119f988b79SJean-Baptiste Boric
4129f988b79SJean-Baptiste Boric /*
4139f988b79SJean-Baptiste Boric * Write data to a file or directory.
4149f988b79SJean-Baptiste Boric */
4159f988b79SJean-Baptiste Boric static int
msdosfs_wfile(const char * path,struct denode * dep,fsnode * node)4169f988b79SJean-Baptiste Boric msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
4179f988b79SJean-Baptiste Boric {
4189f988b79SJean-Baptiste Boric int error, fd;
4199f988b79SJean-Baptiste Boric size_t osize = dep->de_FileSize;
4209f988b79SJean-Baptiste Boric struct stat *st = &node->inode->st;
4219f988b79SJean-Baptiste Boric size_t nsize, offs;
4229f988b79SJean-Baptiste Boric struct msdosfsmount *pmp = dep->de_pmp;
4239f988b79SJean-Baptiste Boric struct buf *bp;
4249f988b79SJean-Baptiste Boric char *dat;
4259f988b79SJean-Baptiste Boric u_long cn = 0;
4269f988b79SJean-Baptiste Boric
4279f988b79SJean-Baptiste Boric error = 0; /* XXX: gcc/vax */
4289f988b79SJean-Baptiste Boric DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__,
4299f988b79SJean-Baptiste Boric dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster));
4309f988b79SJean-Baptiste Boric if (st->st_size == 0)
4319f988b79SJean-Baptiste Boric return 0;
4329f988b79SJean-Baptiste Boric
4339f988b79SJean-Baptiste Boric /* Don't bother to try to write files larger than the fs limit */
4349f988b79SJean-Baptiste Boric if (st->st_size > MSDOSFS_FILESIZE_MAX) {
4359f988b79SJean-Baptiste Boric errno = EFBIG;
4369f988b79SJean-Baptiste Boric return -1;
4379f988b79SJean-Baptiste Boric }
4389f988b79SJean-Baptiste Boric
4399f988b79SJean-Baptiste Boric nsize = st->st_size;
4409f988b79SJean-Baptiste Boric DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize));
4419f988b79SJean-Baptiste Boric if (nsize > osize) {
4429f988b79SJean-Baptiste Boric if ((error = deextend(dep, nsize, NULL)) != 0) {
4439f988b79SJean-Baptiste Boric errno = error;
4449f988b79SJean-Baptiste Boric return -1;
4459f988b79SJean-Baptiste Boric }
4469f988b79SJean-Baptiste Boric if ((error = msdosfs_updatede(dep)) != 0) {
4479f988b79SJean-Baptiste Boric errno = error;
4489f988b79SJean-Baptiste Boric return -1;
4499f988b79SJean-Baptiste Boric }
4509f988b79SJean-Baptiste Boric }
4519f988b79SJean-Baptiste Boric
4529f988b79SJean-Baptiste Boric if ((fd = open(path, O_RDONLY)) == -1)
4539f988b79SJean-Baptiste Boric err(1, "open %s", path);
4549f988b79SJean-Baptiste Boric
4559f988b79SJean-Baptiste Boric if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0))
4569f988b79SJean-Baptiste Boric == MAP_FAILED) {
4579f988b79SJean-Baptiste Boric DPRINTF(("%s: mmap %s %s", __func__, node->name,
4589f988b79SJean-Baptiste Boric strerror(errno)));
4599f988b79SJean-Baptiste Boric close(fd);
4609f988b79SJean-Baptiste Boric goto out;
4619f988b79SJean-Baptiste Boric }
4629f988b79SJean-Baptiste Boric close(fd);
4639f988b79SJean-Baptiste Boric
4649f988b79SJean-Baptiste Boric for (offs = 0; offs < nsize;) {
4659f988b79SJean-Baptiste Boric int blsize, cpsize;
4669f988b79SJean-Baptiste Boric daddr_t bn;
4679f988b79SJean-Baptiste Boric u_long on = offs & pmp->pm_crbomask;
4689f988b79SJean-Baptiste Boric #ifdef HACK
4699f988b79SJean-Baptiste Boric cn = dep->de_StartCluster;
4709f988b79SJean-Baptiste Boric if (cn == MSDOSFSROOT) {
4719f988b79SJean-Baptiste Boric DPRINTF(("%s: bad lbn %lu", __func__, cn));
4729f988b79SJean-Baptiste Boric goto out;
4739f988b79SJean-Baptiste Boric }
4749f988b79SJean-Baptiste Boric bn = cntobn(pmp, cn);
4759f988b79SJean-Baptiste Boric blsize = pmp->pm_bpcluster;
4769f988b79SJean-Baptiste Boric #else
4779f988b79SJean-Baptiste Boric if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) {
4789f988b79SJean-Baptiste Boric DPRINTF(("%s: pcbmap %lu", __func__, bn));
4799f988b79SJean-Baptiste Boric goto out;
4809f988b79SJean-Baptiste Boric }
4819f988b79SJean-Baptiste Boric #endif
4829f988b79SJean-Baptiste Boric DPRINTF(("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__,
4839f988b79SJean-Baptiste Boric cn, (unsigned long long)bn,
4849f988b79SJean-Baptiste Boric (unsigned long long)de_bn2kb(pmp, bn), blsize));
4859f988b79SJean-Baptiste Boric if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
486*0a6a1f1dSLionel Sambuc 0, &bp)) != 0) {
4879f988b79SJean-Baptiste Boric DPRINTF(("bread %d\n", error));
4889f988b79SJean-Baptiste Boric goto out;
4899f988b79SJean-Baptiste Boric }
4909f988b79SJean-Baptiste Boric cpsize = MIN((nsize - offs), blsize - on);
4919f988b79SJean-Baptiste Boric memcpy((char *)bp->b_data + on, dat + offs, cpsize);
4929f988b79SJean-Baptiste Boric bwrite(bp);
4939f988b79SJean-Baptiste Boric offs += cpsize;
4949f988b79SJean-Baptiste Boric }
4959f988b79SJean-Baptiste Boric
4969f988b79SJean-Baptiste Boric munmap(dat, nsize);
4979f988b79SJean-Baptiste Boric return 0;
4989f988b79SJean-Baptiste Boric out:
4999f988b79SJean-Baptiste Boric munmap(dat, nsize);
5009f988b79SJean-Baptiste Boric return error;
5019f988b79SJean-Baptiste Boric }
5029f988b79SJean-Baptiste Boric
5039f988b79SJean-Baptiste Boric
5049f988b79SJean-Baptiste Boric static const struct {
5059f988b79SJean-Baptiste Boric struct direntry dot;
5069f988b79SJean-Baptiste Boric struct direntry dotdot;
5079f988b79SJean-Baptiste Boric } dosdirtemplate = {
5089f988b79SJean-Baptiste Boric { ". ", " ", /* the . entry */
5099f988b79SJean-Baptiste Boric ATTR_DIRECTORY, /* file attribute */
5109f988b79SJean-Baptiste Boric 0, /* reserved */
5119f988b79SJean-Baptiste Boric 0, { 0, 0 }, { 0, 0 }, /* create time & date */
5129f988b79SJean-Baptiste Boric { 0, 0 }, /* access date */
5139f988b79SJean-Baptiste Boric { 0, 0 }, /* high bits of start cluster */
5149f988b79SJean-Baptiste Boric { 210, 4 }, { 210, 4 }, /* modify time & date */
5159f988b79SJean-Baptiste Boric { 0, 0 }, /* startcluster */
5169f988b79SJean-Baptiste Boric { 0, 0, 0, 0 } /* filesize */
5179f988b79SJean-Baptiste Boric },
5189f988b79SJean-Baptiste Boric { ".. ", " ", /* the .. entry */
5199f988b79SJean-Baptiste Boric ATTR_DIRECTORY, /* file attribute */
5209f988b79SJean-Baptiste Boric 0, /* reserved */
5219f988b79SJean-Baptiste Boric 0, { 0, 0 }, { 0, 0 }, /* create time & date */
5229f988b79SJean-Baptiste Boric { 0, 0 }, /* access date */
5239f988b79SJean-Baptiste Boric { 0, 0 }, /* high bits of start cluster */
5249f988b79SJean-Baptiste Boric { 210, 4 }, { 210, 4 }, /* modify time & date */
5259f988b79SJean-Baptiste Boric { 0, 0 }, /* startcluster */
5269f988b79SJean-Baptiste Boric { 0, 0, 0, 0 } /* filesize */
5279f988b79SJean-Baptiste Boric }
5289f988b79SJean-Baptiste Boric };
5299f988b79SJean-Baptiste Boric
5309f988b79SJean-Baptiste Boric struct denode *
msdosfs_mkdire(const char * path,struct denode * pdep,fsnode * node)5319f988b79SJean-Baptiste Boric msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
5329f988b79SJean-Baptiste Boric struct denode ndirent;
5339f988b79SJean-Baptiste Boric struct denode *dep;
5349f988b79SJean-Baptiste Boric struct componentname cn;
5359f988b79SJean-Baptiste Boric struct stat *st = &node->inode->st;
5369f988b79SJean-Baptiste Boric struct msdosfsmount *pmp = pdep->de_pmp;
5379f988b79SJean-Baptiste Boric int error;
5389f988b79SJean-Baptiste Boric u_long newcluster, pcl, bn;
5399f988b79SJean-Baptiste Boric daddr_t lbn;
5409f988b79SJean-Baptiste Boric struct direntry *denp;
5419f988b79SJean-Baptiste Boric struct buf *bp;
5429f988b79SJean-Baptiste Boric
5439f988b79SJean-Baptiste Boric cn.cn_nameptr = node->name;
5449f988b79SJean-Baptiste Boric cn.cn_namelen = strlen(node->name);
5459f988b79SJean-Baptiste Boric /*
5469f988b79SJean-Baptiste Boric * If this is the root directory and there is no space left we
5479f988b79SJean-Baptiste Boric * can't do anything. This is because the root directory can not
5489f988b79SJean-Baptiste Boric * change size.
5499f988b79SJean-Baptiste Boric */
5509f988b79SJean-Baptiste Boric if (pdep->de_StartCluster == MSDOSFSROOT
5519f988b79SJean-Baptiste Boric && pdep->de_fndoffset >= pdep->de_FileSize) {
5529f988b79SJean-Baptiste Boric error = ENOSPC;
5539f988b79SJean-Baptiste Boric goto bad2;
5549f988b79SJean-Baptiste Boric }
5559f988b79SJean-Baptiste Boric
5569f988b79SJean-Baptiste Boric /*
5579f988b79SJean-Baptiste Boric * Allocate a cluster to hold the about to be created directory.
5589f988b79SJean-Baptiste Boric */
5599f988b79SJean-Baptiste Boric error = clusteralloc(pmp, 0, 1, &newcluster, NULL);
5609f988b79SJean-Baptiste Boric if (error)
5619f988b79SJean-Baptiste Boric goto bad2;
5629f988b79SJean-Baptiste Boric
5639f988b79SJean-Baptiste Boric memset(&ndirent, 0, sizeof(ndirent));
5649f988b79SJean-Baptiste Boric ndirent.de_pmp = pmp;
5659f988b79SJean-Baptiste Boric ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
5669f988b79SJean-Baptiste Boric msdosfs_times(pmp, &ndirent, st);
5679f988b79SJean-Baptiste Boric
5689f988b79SJean-Baptiste Boric /*
5699f988b79SJean-Baptiste Boric * Now fill the cluster with the "." and ".." entries. And write
5709f988b79SJean-Baptiste Boric * the cluster to disk. This way it is there for the parent
5719f988b79SJean-Baptiste Boric * directory to be pointing at if there were a crash.
5729f988b79SJean-Baptiste Boric */
5739f988b79SJean-Baptiste Boric bn = cntobn(pmp, newcluster);
5749f988b79SJean-Baptiste Boric lbn = de_bn2kb(pmp, bn);
5759f988b79SJean-Baptiste Boric DPRINTF(("%s(newcluster %lu, bn=%lu, lbn=%lu)\n", __func__, newcluster,
5769f988b79SJean-Baptiste Boric bn, lbn));
5779f988b79SJean-Baptiste Boric /* always succeeds */
5789f988b79SJean-Baptiste Boric bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0);
5799f988b79SJean-Baptiste Boric memset(bp->b_data, 0, pmp->pm_bpcluster);
5809f988b79SJean-Baptiste Boric memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
5819f988b79SJean-Baptiste Boric denp = (struct direntry *)bp->b_data;
5829f988b79SJean-Baptiste Boric putushort(denp[0].deStartCluster, newcluster);
5839f988b79SJean-Baptiste Boric putushort(denp[0].deCDate, ndirent.de_CDate);
5849f988b79SJean-Baptiste Boric putushort(denp[0].deCTime, ndirent.de_CTime);
5859f988b79SJean-Baptiste Boric denp[0].deCHundredth = ndirent.de_CHun;
5869f988b79SJean-Baptiste Boric putushort(denp[0].deADate, ndirent.de_ADate);
5879f988b79SJean-Baptiste Boric putushort(denp[0].deMDate, ndirent.de_MDate);
5889f988b79SJean-Baptiste Boric putushort(denp[0].deMTime, ndirent.de_MTime);
5899f988b79SJean-Baptiste Boric pcl = pdep->de_StartCluster;
5909f988b79SJean-Baptiste Boric DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl,
5919f988b79SJean-Baptiste Boric pmp->pm_rootdirblk));
5929f988b79SJean-Baptiste Boric if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
5939f988b79SJean-Baptiste Boric pcl = 0;
5949f988b79SJean-Baptiste Boric putushort(denp[1].deStartCluster, pcl);
5959f988b79SJean-Baptiste Boric putushort(denp[1].deCDate, ndirent.de_CDate);
5969f988b79SJean-Baptiste Boric putushort(denp[1].deCTime, ndirent.de_CTime);
5979f988b79SJean-Baptiste Boric denp[1].deCHundredth = ndirent.de_CHun;
5989f988b79SJean-Baptiste Boric putushort(denp[1].deADate, ndirent.de_ADate);
5999f988b79SJean-Baptiste Boric putushort(denp[1].deMDate, ndirent.de_MDate);
6009f988b79SJean-Baptiste Boric putushort(denp[1].deMTime, ndirent.de_MTime);
6019f988b79SJean-Baptiste Boric if (FAT32(pmp)) {
6029f988b79SJean-Baptiste Boric putushort(denp[0].deHighClust, newcluster >> 16);
6039f988b79SJean-Baptiste Boric putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
6049f988b79SJean-Baptiste Boric } else {
6059f988b79SJean-Baptiste Boric putushort(denp[0].deHighClust, 0);
6069f988b79SJean-Baptiste Boric putushort(denp[1].deHighClust, 0);
6079f988b79SJean-Baptiste Boric }
6089f988b79SJean-Baptiste Boric
6099f988b79SJean-Baptiste Boric if ((error = bwrite(bp)) != 0)
6109f988b79SJean-Baptiste Boric goto bad;
6119f988b79SJean-Baptiste Boric
6129f988b79SJean-Baptiste Boric /*
6139f988b79SJean-Baptiste Boric * Now build up a directory entry pointing to the newly allocated
6149f988b79SJean-Baptiste Boric * cluster. This will be written to an empty slot in the parent
6159f988b79SJean-Baptiste Boric * directory.
6169f988b79SJean-Baptiste Boric */
6179f988b79SJean-Baptiste Boric if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
6189f988b79SJean-Baptiste Boric goto bad;
6199f988b79SJean-Baptiste Boric
6209f988b79SJean-Baptiste Boric ndirent.de_Attributes = ATTR_DIRECTORY;
6219f988b79SJean-Baptiste Boric ndirent.de_StartCluster = newcluster;
6229f988b79SJean-Baptiste Boric ndirent.de_FileSize = 0;
6239f988b79SJean-Baptiste Boric ndirent.de_dev = pdep->de_dev;
6249f988b79SJean-Baptiste Boric ndirent.de_devvp = pdep->de_devvp;
6259f988b79SJean-Baptiste Boric ndirent.de_pmp = pdep->de_pmp;
6269f988b79SJean-Baptiste Boric if ((error = msdosfs_findslot(pdep, &cn)) != 0)
6279f988b79SJean-Baptiste Boric goto bad;
6289f988b79SJean-Baptiste Boric if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
6299f988b79SJean-Baptiste Boric goto bad;
6309f988b79SJean-Baptiste Boric if ((error = msdosfs_updatede(dep)) != 0)
6319f988b79SJean-Baptiste Boric goto bad;
6329f988b79SJean-Baptiste Boric return dep;
6339f988b79SJean-Baptiste Boric
6349f988b79SJean-Baptiste Boric bad:
6359f988b79SJean-Baptiste Boric clusterfree(pmp, newcluster, NULL);
6369f988b79SJean-Baptiste Boric bad2:
6379f988b79SJean-Baptiste Boric errno = error;
6389f988b79SJean-Baptiste Boric return NULL;
6399f988b79SJean-Baptiste Boric }
640