1*98dc8da5SEd Maste /* $FreeBSD$ */ 2*98dc8da5SEd Maste /* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ 3*98dc8da5SEd Maste 4*98dc8da5SEd Maste /*- 5*98dc8da5SEd Maste * SPDX-License-Identifier: BSD-4-Clause 6*98dc8da5SEd Maste * 7*98dc8da5SEd Maste * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 8*98dc8da5SEd Maste * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 9*98dc8da5SEd Maste * All rights reserved. 10*98dc8da5SEd Maste * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 11*98dc8da5SEd Maste * 12*98dc8da5SEd Maste * Redistribution and use in source and binary forms, with or without 13*98dc8da5SEd Maste * modification, are permitted provided that the following conditions 14*98dc8da5SEd Maste * are met: 15*98dc8da5SEd Maste * 1. Redistributions of source code must retain the above copyright 16*98dc8da5SEd Maste * notice, this list of conditions and the following disclaimer. 17*98dc8da5SEd Maste * 2. Redistributions in binary form must reproduce the above copyright 18*98dc8da5SEd Maste * notice, this list of conditions and the following disclaimer in the 19*98dc8da5SEd Maste * documentation and/or other materials provided with the distribution. 20*98dc8da5SEd Maste * 3. All advertising materials mentioning features or use of this software 21*98dc8da5SEd Maste * must display the following acknowledgement: 22*98dc8da5SEd Maste * This product includes software developed by TooLs GmbH. 23*98dc8da5SEd Maste * 4. The name of TooLs GmbH may not be used to endorse or promote products 24*98dc8da5SEd Maste * derived from this software without specific prior written permission. 25*98dc8da5SEd Maste * 26*98dc8da5SEd Maste * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 27*98dc8da5SEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28*98dc8da5SEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29*98dc8da5SEd Maste * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30*98dc8da5SEd Maste * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31*98dc8da5SEd Maste * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 32*98dc8da5SEd Maste * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33*98dc8da5SEd Maste * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34*98dc8da5SEd Maste * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35*98dc8da5SEd Maste * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36*98dc8da5SEd Maste */ 37*98dc8da5SEd Maste /*- 38*98dc8da5SEd Maste * Written by Paul Popelka (paulp@uts.amdahl.com) 39*98dc8da5SEd Maste * 40*98dc8da5SEd Maste * You can do anything you want with this software, just don't say you wrote 41*98dc8da5SEd Maste * it, and don't remove this notice. 42*98dc8da5SEd Maste * 43*98dc8da5SEd Maste * This software is provided "as is". 44*98dc8da5SEd Maste * 45*98dc8da5SEd Maste * The author supplies this software to be publicly redistributed on the 46*98dc8da5SEd Maste * understanding that the author is not responsible for the correct 47*98dc8da5SEd Maste * functioning of this software in any circumstances and is not liable for 48*98dc8da5SEd Maste * any damages caused by this software. 49*98dc8da5SEd Maste * 50*98dc8da5SEd Maste * October 1992 51*98dc8da5SEd Maste */ 52*98dc8da5SEd Maste 53*98dc8da5SEd Maste #include <sys/param.h> 54*98dc8da5SEd Maste #include <sys/errno.h> 55*98dc8da5SEd Maste 56*98dc8da5SEd Maste #include <stdio.h> 57*98dc8da5SEd Maste #include <string.h> 58*98dc8da5SEd Maste 59*98dc8da5SEd Maste #include <fs/msdosfs/bpb.h> 60*98dc8da5SEd Maste 61*98dc8da5SEd Maste #include "ffs/buf.h" 62*98dc8da5SEd Maste 63*98dc8da5SEd Maste #include "msdos/denode.h" 64*98dc8da5SEd Maste #include "msdos/direntry.h" 65*98dc8da5SEd Maste #include "msdos/fat.h" 66*98dc8da5SEd Maste #include "msdos/msdosfsmount.h" 67*98dc8da5SEd Maste 68*98dc8da5SEd Maste #include "makefs.h" 69*98dc8da5SEd Maste #include "msdos.h" 70*98dc8da5SEd Maste 71*98dc8da5SEd Maste /* 72*98dc8da5SEd Maste * dep - directory entry to copy into the directory 73*98dc8da5SEd Maste * ddep - directory to add to 74*98dc8da5SEd Maste * depp - return the address of the denode for the created directory entry 75*98dc8da5SEd Maste * if depp != 0 76*98dc8da5SEd Maste * cnp - componentname needed for Win95 long filenames 77*98dc8da5SEd Maste */ 78*98dc8da5SEd Maste int 79*98dc8da5SEd Maste createde(struct denode *dep, struct denode *ddep, struct denode **depp, 80*98dc8da5SEd Maste struct componentname *cnp) 81*98dc8da5SEd Maste { 82*98dc8da5SEd Maste int error; 83*98dc8da5SEd Maste u_long dirclust, diroffset; 84*98dc8da5SEd Maste struct direntry *ndep; 85*98dc8da5SEd Maste struct msdosfsmount *pmp = ddep->de_pmp; 86*98dc8da5SEd Maste struct buf *bp; 87*98dc8da5SEd Maste daddr_t bn; 88*98dc8da5SEd Maste int blsize; 89*98dc8da5SEd Maste 90*98dc8da5SEd Maste MSDOSFS_DPRINTF(("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 91*98dc8da5SEd Maste dep, ddep, depp, cnp)); 92*98dc8da5SEd Maste 93*98dc8da5SEd Maste /* 94*98dc8da5SEd Maste * If no space left in the directory then allocate another cluster 95*98dc8da5SEd Maste * and chain it onto the end of the file. There is one exception 96*98dc8da5SEd Maste * to this. That is, if the root directory has no more space it 97*98dc8da5SEd Maste * can NOT be expanded. extendfile() checks for and fails attempts 98*98dc8da5SEd Maste * to extend the root directory. We just return an error in that 99*98dc8da5SEd Maste * case. 100*98dc8da5SEd Maste */ 101*98dc8da5SEd Maste if (ddep->de_fndoffset >= ddep->de_FileSize) { 102*98dc8da5SEd Maste diroffset = ddep->de_fndoffset + sizeof(struct direntry) 103*98dc8da5SEd Maste - ddep->de_FileSize; 104*98dc8da5SEd Maste dirclust = de_clcount(pmp, diroffset); 105*98dc8da5SEd Maste error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); 106*98dc8da5SEd Maste if (error) { 107*98dc8da5SEd Maste (void)detrunc(ddep, ddep->de_FileSize, 0); 108*98dc8da5SEd Maste return error; 109*98dc8da5SEd Maste } 110*98dc8da5SEd Maste 111*98dc8da5SEd Maste /* 112*98dc8da5SEd Maste * Update the size of the directory 113*98dc8da5SEd Maste */ 114*98dc8da5SEd Maste ddep->de_FileSize += de_cn2off(pmp, dirclust); 115*98dc8da5SEd Maste } 116*98dc8da5SEd Maste 117*98dc8da5SEd Maste /* 118*98dc8da5SEd Maste * We just read in the cluster with space. Copy the new directory 119*98dc8da5SEd Maste * entry in. Then write it to disk. NOTE: DOS directories 120*98dc8da5SEd Maste * do not get smaller as clusters are emptied. 121*98dc8da5SEd Maste */ 122*98dc8da5SEd Maste error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 123*98dc8da5SEd Maste &bn, &dirclust, &blsize); 124*98dc8da5SEd Maste if (error) 125*98dc8da5SEd Maste return error; 126*98dc8da5SEd Maste diroffset = ddep->de_fndoffset; 127*98dc8da5SEd Maste if (dirclust != MSDOSFSROOT) 128*98dc8da5SEd Maste diroffset &= pmp->pm_crbomask; 129*98dc8da5SEd Maste if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { 130*98dc8da5SEd Maste brelse(bp); 131*98dc8da5SEd Maste return error; 132*98dc8da5SEd Maste } 133*98dc8da5SEd Maste ndep = bptoep(pmp, bp, ddep->de_fndoffset); 134*98dc8da5SEd Maste 135*98dc8da5SEd Maste DE_EXTERNALIZE(ndep, dep); 136*98dc8da5SEd Maste 137*98dc8da5SEd Maste /* 138*98dc8da5SEd Maste * Now write the Win95 long name 139*98dc8da5SEd Maste */ 140*98dc8da5SEd Maste if (ddep->de_fndcnt > 0) { 141*98dc8da5SEd Maste uint8_t chksum = winChksum(ndep->deName); 142*98dc8da5SEd Maste const u_char *un = (const u_char *)cnp->cn_nameptr; 143*98dc8da5SEd Maste int unlen = cnp->cn_namelen; 144*98dc8da5SEd Maste int cnt = 1; 145*98dc8da5SEd Maste 146*98dc8da5SEd Maste while (--ddep->de_fndcnt >= 0) { 147*98dc8da5SEd Maste if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { 148*98dc8da5SEd Maste if ((error = bwrite(bp)) != 0) 149*98dc8da5SEd Maste return error; 150*98dc8da5SEd Maste 151*98dc8da5SEd Maste ddep->de_fndoffset -= sizeof(struct direntry); 152*98dc8da5SEd Maste error = pcbmap(ddep, 153*98dc8da5SEd Maste de_cluster(pmp, 154*98dc8da5SEd Maste ddep->de_fndoffset), 155*98dc8da5SEd Maste &bn, 0, &blsize); 156*98dc8da5SEd Maste if (error) 157*98dc8da5SEd Maste return error; 158*98dc8da5SEd Maste 159*98dc8da5SEd Maste error = bread(pmp->pm_devvp, bn, blsize, 160*98dc8da5SEd Maste NOCRED, &bp); 161*98dc8da5SEd Maste if (error) { 162*98dc8da5SEd Maste brelse(bp); 163*98dc8da5SEd Maste return error; 164*98dc8da5SEd Maste } 165*98dc8da5SEd Maste ndep = bptoep(pmp, bp, ddep->de_fndoffset); 166*98dc8da5SEd Maste } else { 167*98dc8da5SEd Maste ndep--; 168*98dc8da5SEd Maste ddep->de_fndoffset -= sizeof(struct direntry); 169*98dc8da5SEd Maste } 170*98dc8da5SEd Maste if (!unix2winfn(un, unlen, (struct winentry *)ndep, 171*98dc8da5SEd Maste cnt++, chksum)) 172*98dc8da5SEd Maste break; 173*98dc8da5SEd Maste } 174*98dc8da5SEd Maste } 175*98dc8da5SEd Maste 176*98dc8da5SEd Maste if ((error = bwrite(bp)) != 0) 177*98dc8da5SEd Maste return error; 178*98dc8da5SEd Maste 179*98dc8da5SEd Maste /* 180*98dc8da5SEd Maste * If they want us to return with the denode gotten. 181*98dc8da5SEd Maste */ 182*98dc8da5SEd Maste if (depp) { 183*98dc8da5SEd Maste if (dep->de_Attributes & ATTR_DIRECTORY) { 184*98dc8da5SEd Maste dirclust = dep->de_StartCluster; 185*98dc8da5SEd Maste if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 186*98dc8da5SEd Maste dirclust = MSDOSFSROOT; 187*98dc8da5SEd Maste if (dirclust == MSDOSFSROOT) 188*98dc8da5SEd Maste diroffset = MSDOSFSROOT_OFS; 189*98dc8da5SEd Maste else 190*98dc8da5SEd Maste diroffset = 0; 191*98dc8da5SEd Maste } 192*98dc8da5SEd Maste return deget(pmp, dirclust, diroffset, depp); 193*98dc8da5SEd Maste } 194*98dc8da5SEd Maste 195*98dc8da5SEd Maste return 0; 196*98dc8da5SEd Maste } 197*98dc8da5SEd Maste 198*98dc8da5SEd Maste /* 199*98dc8da5SEd Maste * Read in the disk block containing the directory entry (dirclu, dirofs) 200*98dc8da5SEd Maste * and return the address of the buf header, and the address of the 201*98dc8da5SEd Maste * directory entry within the block. 202*98dc8da5SEd Maste */ 203*98dc8da5SEd Maste int 204*98dc8da5SEd Maste readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, 205*98dc8da5SEd Maste struct buf **bpp, struct direntry **epp) 206*98dc8da5SEd Maste { 207*98dc8da5SEd Maste int error; 208*98dc8da5SEd Maste daddr_t bn; 209*98dc8da5SEd Maste int blsize; 210*98dc8da5SEd Maste 211*98dc8da5SEd Maste blsize = pmp->pm_bpcluster; 212*98dc8da5SEd Maste if (dirclust == MSDOSFSROOT 213*98dc8da5SEd Maste && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 214*98dc8da5SEd Maste blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 215*98dc8da5SEd Maste bn = detobn(pmp, dirclust, diroffset); 216*98dc8da5SEd Maste if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { 217*98dc8da5SEd Maste brelse(*bpp); 218*98dc8da5SEd Maste *bpp = NULL; 219*98dc8da5SEd Maste return (error); 220*98dc8da5SEd Maste } 221*98dc8da5SEd Maste if (epp) 222*98dc8da5SEd Maste *epp = bptoep(pmp, *bpp, diroffset); 223*98dc8da5SEd Maste return (0); 224*98dc8da5SEd Maste } 225*98dc8da5SEd Maste 226*98dc8da5SEd Maste /* 227*98dc8da5SEd Maste * Read in the disk block containing the directory entry dep came from and 228*98dc8da5SEd Maste * return the address of the buf header, and the address of the directory 229*98dc8da5SEd Maste * entry within the block. 230*98dc8da5SEd Maste */ 231*98dc8da5SEd Maste int 232*98dc8da5SEd Maste readde(struct denode *dep, struct buf **bpp, struct direntry **epp) 233*98dc8da5SEd Maste { 234*98dc8da5SEd Maste 235*98dc8da5SEd Maste return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 236*98dc8da5SEd Maste bpp, epp)); 237*98dc8da5SEd Maste } 238*98dc8da5SEd Maste 239*98dc8da5SEd Maste /* 240*98dc8da5SEd Maste * Create a unique DOS name in dvp 241*98dc8da5SEd Maste */ 242*98dc8da5SEd Maste int 243*98dc8da5SEd Maste uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) 244*98dc8da5SEd Maste { 245*98dc8da5SEd Maste struct msdosfsmount *pmp = dep->de_pmp; 246*98dc8da5SEd Maste struct direntry *dentp; 247*98dc8da5SEd Maste int gen; 248*98dc8da5SEd Maste int blsize; 249*98dc8da5SEd Maste u_long cn; 250*98dc8da5SEd Maste daddr_t bn; 251*98dc8da5SEd Maste struct buf *bp; 252*98dc8da5SEd Maste int error; 253*98dc8da5SEd Maste 254*98dc8da5SEd Maste if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 255*98dc8da5SEd Maste return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 256*98dc8da5SEd Maste cnp->cn_namelen, 0) ? 0 : EINVAL); 257*98dc8da5SEd Maste 258*98dc8da5SEd Maste for (gen = 1;; gen++) { 259*98dc8da5SEd Maste /* 260*98dc8da5SEd Maste * Generate DOS name with generation number 261*98dc8da5SEd Maste */ 262*98dc8da5SEd Maste if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 263*98dc8da5SEd Maste cnp->cn_namelen, gen)) 264*98dc8da5SEd Maste return gen == 1 ? EINVAL : EEXIST; 265*98dc8da5SEd Maste 266*98dc8da5SEd Maste /* 267*98dc8da5SEd Maste * Now look for a dir entry with this exact name 268*98dc8da5SEd Maste */ 269*98dc8da5SEd Maste for (cn = error = 0; !error; cn++) { 270*98dc8da5SEd Maste if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 271*98dc8da5SEd Maste if (error == E2BIG) /* EOF reached and not found */ 272*98dc8da5SEd Maste return 0; 273*98dc8da5SEd Maste return error; 274*98dc8da5SEd Maste } 275*98dc8da5SEd Maste error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 276*98dc8da5SEd Maste if (error) { 277*98dc8da5SEd Maste brelse(bp); 278*98dc8da5SEd Maste return error; 279*98dc8da5SEd Maste } 280*98dc8da5SEd Maste for (dentp = (struct direntry *)bp->b_data; 281*98dc8da5SEd Maste (char *)dentp < (char *)bp->b_data + blsize; 282*98dc8da5SEd Maste dentp++) { 283*98dc8da5SEd Maste if (dentp->deName[0] == SLOT_EMPTY) { 284*98dc8da5SEd Maste /* 285*98dc8da5SEd Maste * Last used entry and not found 286*98dc8da5SEd Maste */ 287*98dc8da5SEd Maste brelse(bp); 288*98dc8da5SEd Maste return 0; 289*98dc8da5SEd Maste } 290*98dc8da5SEd Maste /* 291*98dc8da5SEd Maste * Ignore volume labels and Win95 entries 292*98dc8da5SEd Maste */ 293*98dc8da5SEd Maste if (dentp->deAttributes & ATTR_VOLUME) 294*98dc8da5SEd Maste continue; 295*98dc8da5SEd Maste if (!bcmp(dentp->deName, cp, 11)) { 296*98dc8da5SEd Maste error = EEXIST; 297*98dc8da5SEd Maste break; 298*98dc8da5SEd Maste } 299*98dc8da5SEd Maste } 300*98dc8da5SEd Maste brelse(bp); 301*98dc8da5SEd Maste } 302*98dc8da5SEd Maste } 303*98dc8da5SEd Maste } 304