Module Name: src Committed By: christos Date: Sun Jan 27 15:35:45 UTC 2013
Modified Files: src/usr.sbin/makefs: msdos.c src/usr.sbin/makefs/msdos: msdosfs_vfsops.c msdosfs_vnops.c Log Message: fixed directory entry allocation. Now the file data remains and is currently broken. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/makefs/msdos.c cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/makefs/msdos/msdosfs_vfsops.c cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/makefs/msdos/msdosfs_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/makefs/msdos.c diff -u src/usr.sbin/makefs/msdos.c:1.6 src/usr.sbin/makefs/msdos.c:1.7 --- src/usr.sbin/makefs/msdos.c:1.6 Fri Jan 25 19:20:40 2013 +++ src/usr.sbin/makefs/msdos.c Sun Jan 27 10:35:45 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: msdos.c,v 1.6 2013/01/26 00:20:40 christos Exp $ */ +/* $NetBSD: msdos.c,v 1.7 2013/01/27 15:35:45 christos Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(__lint) -__RCSID("$NetBSD: msdos.c,v 1.6 2013/01/26 00:20:40 christos Exp $"); +__RCSID("$NetBSD: msdos.c,v 1.7 2013/01/27 15:35:45 christos Exp $"); #endif /* !__lint */ #include <sys/param.h> @@ -62,6 +62,8 @@ __RCSID("$NetBSD: msdos.c,v 1.6 2013/01/ #include "msdos.h" #include "mkfs_msdos.h" +extern int sectorsize; /* XXX: horrid */ + static int msdos_populate_dir(const char *, struct denode *, fsnode *, fsnode *, fsinfo_t *); @@ -149,6 +151,7 @@ msdos_makefs(const char *image, const ch * Is minsize right here? */ msdos_opt->create_size = MAX(msdos_opt->create_size, fsopts->minsize); + msdos_opt->bytes_per_sector = sectorsize = 512; /* create image */ printf("Creating `%s'\n", image); @@ -159,7 +162,7 @@ msdos_makefs(const char *image, const ch vp.fd = open(image, O_RDWR); vp.fs = msdos_opt; - vp.offset = 1; + vp.offset = 0; if ((pmp = msdosfs_mount(&vp, 0)) == NULL) err(1, "msdosfs_mount"); @@ -171,9 +174,6 @@ msdos_makefs(const char *image, const ch printf("msdos_makefs: image %s directory %s root %p\n", image, dir, root); - printf("Calculated size of `%s': %lld bytes, %lld inodes\n", - image, (long long)fsopts->size, (long long)fsopts->inodes); - /* populate image */ printf("Populating `%s'\n", image); TIMER_START(start); Index: src/usr.sbin/makefs/msdos/msdosfs_vfsops.c diff -u src/usr.sbin/makefs/msdos/msdosfs_vfsops.c:1.3 src/usr.sbin/makefs/msdos/msdosfs_vfsops.c:1.4 --- src/usr.sbin/makefs/msdos/msdosfs_vfsops.c:1.3 Sat Jan 26 11:50:46 2013 +++ src/usr.sbin/makefs/msdos/msdosfs_vfsops.c Sun Jan 27 10:35:45 2013 @@ -50,7 +50,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.3 2013/01/26 16:50:46 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.4 2013/01/27 15:35:45 christos Exp $"); #include <sys/param.h> @@ -94,7 +94,8 @@ msdosfs_mount(struct vnode *devvp, int f uint64_t psize = m->create_size; unsigned secsize = 512; - if ((error = bread(devvp, 1, secsize, NULL, 0, &bp)) != 0) + DPRINTF(("%s(bread 0)\n", __func__)); + if ((error = bread(devvp, 0, secsize, NULL, 0, &bp)) != 0) goto error_exit; bsp = (union bootsector *)bp->b_data; @@ -135,6 +136,11 @@ msdosfs_mount(struct vnode *devvp, int f pmp->pm_Heads = getushort(b50->bpbHeads); pmp->pm_Media = b50->bpbMedia; + DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, RootDirEnts=%u, " + "Sectors=%u, FATsecs=%lu, SecPerTrack=%u, Heads=%u, Media=%u)\n", + __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, pmp->pm_FATs, + pmp->pm_RootDirEnts, pmp->pm_Sectors, pmp->pm_FATsecs, + pmp->pm_SecPerTrack, pmp->pm_Heads, pmp->pm_Media)); if (!(flags & MSDOSFSMNT_GEMDOSFS)) { /* XXX - We should probably check more values here */ if (!pmp->pm_BytesPerSec || !SecPerClust @@ -323,6 +329,8 @@ msdosfs_mount(struct vnode *devvp, int f * 2KB or larger sectors, is the fsinfo structure * padded at the end or in the middle? */ + DPRINTF(("%s(bread %lu)\n", __func__, + (unsigned long)de_bn2kb(pmp, pmp->pm_fsinfo))); if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo), pmp->pm_BytesPerSec, NULL, 0, &bp)) != 0) goto error_exit; @@ -352,9 +360,8 @@ msdosfs_mount(struct vnode *devvp, int f * Allocate memory for the bitmap of allocated clusters, and then * fill it in. */ - pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS) - / N_INUSEBITS) - * sizeof(*pmp->pm_inusemap)); + pmp->pm_inusemap = calloc(sizeof(*pmp->pm_inusemap), + ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS)); if (pmp->pm_inusemap == NULL) goto error_exit; Index: src/usr.sbin/makefs/msdos/msdosfs_vnops.c diff -u src/usr.sbin/makefs/msdos/msdosfs_vnops.c:1.6 src/usr.sbin/makefs/msdos/msdosfs_vnops.c:1.7 --- src/usr.sbin/makefs/msdos/msdosfs_vnops.c:1.6 Sun Jan 27 07:25:13 2013 +++ src/usr.sbin/makefs/msdos/msdosfs_vnops.c Sun Jan 27 10:35:45 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_vnops.c,v 1.6 2013/01/27 12:25:13 martin Exp $ */ +/* $NetBSD: msdosfs_vnops.c,v 1.7 2013/01/27 15:35:45 christos Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. @@ -51,7 +51,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.6 2013/01/27 12:25:13 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.7 2013/01/27 15:35:45 christos Exp $"); #include <sys/param.h> #include <sys/mman.h> @@ -78,9 +78,9 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnop * the contents of a file are read/written using the vnode for the file * (including directories when they are read/written as files). This * presents problems for the dos filesystem because data that should be in - * an inode (if dos had them) resides in the directory itself. Since we + * an inode (if dos had them) resides in the directory itself. Since we * must update directory entries without the benefit of having the vnode - * for the directory we must use the vnode for the filesystem. This means + * for the directory we must use the vnode for the filesystem. This means * that when a directory is actually read/written (via read, write, or * readdir, or seek) we must use the vnode for the filesystem instead of * the vnode for the directory as would happen in ufs. This is to insure we @@ -106,6 +106,235 @@ msdosfs_times(struct msdosfsmount *pmp, } /* + * When we search a directory the blocks containing directory entries are + * read and examined. The directory entries contain information that would + * normally be in the inode of a unix filesystem. This means that some of + * a directory's contents may also be in memory resident denodes (sort of + * an inode). This can cause problems if we are searching while some other + * process is modifying a directory. To prevent one process from accessing + * incompletely modified directory information we depend upon being the + * sole owner of a directory block. bread/brelse provide this service. + * This being the case, when a process modifies a directory it must first + * acquire the disk block that contains the directory entry to be modified. + * Then update the disk block and the denode, and then write the disk block + * out to disk. This way disk blocks containing directory entries and in + * memory denode's will be in synch. + */ +static int +msdosfs_findslot(struct denode *dp, struct componentname *cnp) +{ + daddr_t bn; + int error; + int slotcount; + int slotoffset = 0; + int frcn; + u_long cluster; + int blkoff; + u_int diroff; + int blsize; + struct denode *tdp; + struct msdosfsmount *pmp; + struct buf *bp = 0; + struct direntry *dep; + u_char dosfilename[12]; + int wincnt = 1; + int chksum = -1, chksum_ok; + int olddos = 1; + + pmp = dp->de_pmp; + switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, + cnp->cn_namelen, 0)) { + case 0: + return (EINVAL); + case 1: + break; + case 2: + wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, + cnp->cn_namelen) + 1; + break; + case 3: + olddos = 0; + wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, + cnp->cn_namelen) + 1; + break; + } + + if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) + wincnt = 1; + + /* + * Suppress search for slots unless creating + * file and at end of pathname, in which case + * we watch for a place to put the new file in + * case it doesn't already exist. + */ + slotcount = 0; +#ifdef MSDOSFS_DEBUG + printf("%s(): dos filename: %s\n", __func__, dosfilename); +#endif + /* + * Search the directory pointed at by vdp for the name pointed at + * by cnp->cn_nameptr. + */ + tdp = NULL; + /* + * The outer loop ranges over the clusters that make up the + * directory. Note that the root directory is different from all + * other directories. It has a fixed number of blocks that are not + * part of the pool of allocatable clusters. So, we treat it a + * little differently. The root directory starts at "cluster" 0. + */ + diroff = 0; + for (frcn = 0; diroff < dp->de_FileSize; frcn++) { + if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { + if (error == E2BIG) + break; + return (error); + } + error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, + 0, &bp); + if (error) { + return (error); + } + for (blkoff = 0; blkoff < blsize; + blkoff += sizeof(struct direntry), + diroff += sizeof(struct direntry)) { + dep = (struct direntry *)((char *)bp->b_data + blkoff); + /* + * If the slot is empty and we are still looking + * for an empty then remember this one. If the + * slot is not empty then check to see if it + * matches what we are looking for. If the slot + * has never been filled with anything, then the + * remainder of the directory has never been used, + * so there is no point in searching it. + */ + if (dep->deName[0] == SLOT_EMPTY || + dep->deName[0] == SLOT_DELETED) { + /* + * Drop memory of previous long matches + */ + chksum = -1; + + if (slotcount < wincnt) { + slotcount++; + slotoffset = diroff; + } + if (dep->deName[0] == SLOT_EMPTY) { + brelse(bp, 0); + goto notfound; + } + } else { + /* + * If there wasn't enough space for our + * winentries, forget about the empty space + */ + if (slotcount < wincnt) + slotcount = 0; + + /* + * Check for Win95 long filename entry + */ + if (dep->deAttributes == ATTR_WIN95) { + if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) + continue; + + chksum = winChkName((const u_char *)cnp->cn_nameptr, + cnp->cn_namelen, + (struct winentry *)dep, + chksum); + continue; + } + + /* + * Ignore volume labels (anywhere, not just + * the root directory). + */ + if (dep->deAttributes & ATTR_VOLUME) { + chksum = -1; + continue; + } + + /* + * Check for a checksum or name match + */ + chksum_ok = (chksum == winChksum(dep->deName)); + if (!chksum_ok + && (!olddos || memcmp(dosfilename, dep->deName, 11))) { + chksum = -1; + continue; + } +#ifdef MSDOSFS_DEBUG + printf("%s(): match blkoff %d, diroff %d\n", + __func__, blkoff, diroff); +#endif + /* + * Remember where this directory + * entry came from for whoever did + * this lookup. + */ + dp->de_fndoffset = diroff; + dp->de_fndcnt = 0; + + return EEXIST; + } + } /* for (blkoff = 0; .... */ + /* + * Release the buffer holding the directory cluster just + * searched. + */ + brelse(bp, 0); + } /* for (frcn = 0; ; frcn++) */ + +notfound: + /* + * We hold no disk buffers at this point. + */ + + /* + * If we get here we didn't find the entry we were looking for. But + * that's ok if we are creating or renaming and are at the end of + * the pathname and the directory hasn't been removed. + */ +#ifdef MSDOSFS_DEBUG + printf("%s(): refcnt %ld, slotcount %d, slotoffset %d\n", + __func__, dp->de_refcnt, slotcount, slotoffset); +#endif + /* + * Fixup the slot description to point to the place where + * we might put the new DOS direntry (putting the Win95 + * long name entries before that) + */ + if (!slotcount) { + slotcount = 1; + slotoffset = diroff; + } + if (wincnt > slotcount) { + slotoffset += sizeof(struct direntry) * (wincnt - slotcount); + } + + /* + * Return an indication of where the new directory + * entry should be put. + */ + dp->de_fndoffset = slotoffset; + dp->de_fndcnt = wincnt - 1; + + /* + * We return with the directory locked, so that + * the parameters we set up above will still be + * valid if we actually decide to do a direnter(). + * We return ni_vp == NULL to indicate that the entry + * does not currently exist; we leave a pointer to + * the (locked) directory inode in ndp->ni_dvp. + * + * NB - if the directory is unlocked, then this + * information cannot be used. + */ + return 0; +} + +/* * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. */ @@ -157,9 +386,11 @@ msdosfs_mkfile(const char *path, struct ndirent.de_pmp = pdep->de_pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; msdosfs_times(pmp, &ndirent, st); + if ((error = msdosfs_findslot(pdep, &cn)) != 0) + goto bad; if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) goto bad; - if ((error = msdosfs_wfile(path, dep, node)) == -1) + if ((error = msdosfs_wfile(path, dep, node)) != 0) goto bad; return dep; @@ -185,7 +416,7 @@ msdosfs_wfile(const char *path, struct d u_long cn; #ifdef MSDOSFS_DEBUG - printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n", + printf("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__, dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster); #endif if (st->st_size == 0) @@ -208,23 +439,30 @@ msdosfs_wfile(const char *path, struct d if ((fd = open(path, O_RDONLY)) == -1) err(1, "open %s", path); - if ((dat = mmap(0, (size_t)nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) - == MAP_FAILED) - err(1, "mmap %s", node->name); + if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) + == MAP_FAILED) { + fprintf(stderr, "mmap %s", node->name); + goto out; + } close(fd); - for (cn = 0;; cn++) { + for (cn = 0;; cn++) { int blsize, cpsize; daddr_t bn; - if (pcbmap(dep, cn, &bn, 0, &blsize)) { + if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { fprintf(stderr, "pcbmap %ld\n", cn); goto out; } - - if (bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NULL, - 0, &bp)) { - fprintf(stderr, "bread\n"); - } +#ifdef MSDOSFS_DEBUG + printf("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__, cn, + (unsigned long long)bn, + (unsigned long long)de_bn2kb(pmp, bn), blsize); +#endif + if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, + NULL, 0, &bp)) != 0) { + fprintf(stderr, "bread %d\n", error); + goto out; + } cpsize = MIN((int)(nsize - offs), blsize); memcpy(bp->b_data, dat + offs, cpsize); bwrite(bp); @@ -238,7 +476,7 @@ msdosfs_wfile(const char *path, struct d return 0; out: munmap(dat, nsize); - return -1; + return error; } @@ -246,19 +484,19 @@ static const struct { struct direntry dot; struct direntry dotdot; } dosdirtemplate = { - { ". ", " ", /* the . entry */ + { ". ", " ", /* the . entry */ ATTR_DIRECTORY, /* file attribute */ - 0, /* reserved */ + 0, /* reserved */ 0, { 0, 0 }, { 0, 0 }, /* create time & date */ { 0, 0 }, /* access date */ { 0, 0 }, /* high bits of start cluster */ { 210, 4 }, { 210, 4 }, /* modify time & date */ { 0, 0 }, /* startcluster */ - { 0, 0, 0, 0 } /* filesize */ + { 0, 0, 0, 0 } /* filesize */ }, - { ".. ", " ", /* the .. entry */ + { ".. ", " ", /* the .. entry */ ATTR_DIRECTORY, /* file attribute */ - 0, /* reserved */ + 0, /* reserved */ 0, { 0, 0 }, { 0, 0 }, /* create time & date */ { 0, 0 }, /* access date */ { 0, 0 }, /* high bits of start cluster */ @@ -308,7 +546,7 @@ msdosfs_mkdire(const char *path, struct /* * Now fill the cluster with the "." and ".." entries. And write - * the cluster to disk. This way it is there for the parent + * the cluster to disk. This way it is there for the parent * directory to be pointing at if there were a crash. */ bn = cntobn(pmp, newcluster); @@ -359,6 +597,8 @@ msdosfs_mkdire(const char *path, struct ndirent.de_FileSize = 0; ndirent.de_dev = pdep->de_dev; ndirent.de_devvp = pdep->de_devvp; + if ((error = msdosfs_findslot(pdep, &cn)) != 0) + goto bad; if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) goto bad; return dep;