1c3aac50fSPeter Wemm /* $FreeBSD$ */ 2952a6212SJordan K. Hubbard /* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ 327a0bc89SDoug Rabson 427a0bc89SDoug Rabson /*- 5d63027b6SPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 6d63027b6SPedro F. Giffuni * 7952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 8952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 927a0bc89SDoug Rabson * All rights reserved. 1027a0bc89SDoug Rabson * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 1127a0bc89SDoug Rabson * 1227a0bc89SDoug Rabson * Redistribution and use in source and binary forms, with or without 1327a0bc89SDoug Rabson * modification, are permitted provided that the following conditions 1427a0bc89SDoug Rabson * are met: 1527a0bc89SDoug Rabson * 1. Redistributions of source code must retain the above copyright 1627a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer. 1727a0bc89SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1827a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1927a0bc89SDoug Rabson * documentation and/or other materials provided with the distribution. 2027a0bc89SDoug Rabson * 3. All advertising materials mentioning features or use of this software 2127a0bc89SDoug Rabson * must display the following acknowledgement: 2227a0bc89SDoug Rabson * This product includes software developed by TooLs GmbH. 2327a0bc89SDoug Rabson * 4. The name of TooLs GmbH may not be used to endorse or promote products 2427a0bc89SDoug Rabson * derived from this software without specific prior written permission. 2527a0bc89SDoug Rabson * 2627a0bc89SDoug Rabson * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2727a0bc89SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2827a0bc89SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2927a0bc89SDoug Rabson * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3027a0bc89SDoug Rabson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 3127a0bc89SDoug Rabson * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3227a0bc89SDoug Rabson * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3327a0bc89SDoug Rabson * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3427a0bc89SDoug Rabson * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3527a0bc89SDoug Rabson * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3627a0bc89SDoug Rabson */ 37d167cf6fSWarner Losh /*- 3827a0bc89SDoug Rabson * Written by Paul Popelka (paulp@uts.amdahl.com) 3927a0bc89SDoug Rabson * 4027a0bc89SDoug Rabson * You can do anything you want with this software, just don't say you wrote 4127a0bc89SDoug Rabson * it, and don't remove this notice. 4227a0bc89SDoug Rabson * 4327a0bc89SDoug Rabson * This software is provided "as is". 4427a0bc89SDoug Rabson * 4527a0bc89SDoug Rabson * The author supplies this software to be publicly redistributed on the 4627a0bc89SDoug Rabson * understanding that the author is not responsible for the correct 4727a0bc89SDoug Rabson * functioning of this software in any circumstances and is not liable for 4827a0bc89SDoug Rabson * any damages caused by this software. 4927a0bc89SDoug Rabson * 5027a0bc89SDoug Rabson * October 1992 5127a0bc89SDoug Rabson */ 5227a0bc89SDoug Rabson 5327a0bc89SDoug Rabson #include <sys/param.h> 54919d1ea2SPeter Wemm #include <sys/systm.h> 5527a0bc89SDoug Rabson #include <sys/buf.h> 5627a0bc89SDoug Rabson #include <sys/mount.h> 57a878a31cSBruce Evans #include <sys/namei.h> 58a878a31cSBruce Evans #include <sys/vnode.h> 5927a0bc89SDoug Rabson 601166fb51SRuslan Ermilov #include <fs/msdosfs/bpb.h> 611166fb51SRuslan Ermilov #include <fs/msdosfs/direntry.h> 621166fb51SRuslan Ermilov #include <fs/msdosfs/denode.h> 631166fb51SRuslan Ermilov #include <fs/msdosfs/fat.h> 64a878a31cSBruce Evans #include <fs/msdosfs/msdosfsmount.h> 6527a0bc89SDoug Rabson 66*aec97963SKonstantin Belousov static int 67*aec97963SKonstantin Belousov msdosfs_lookup_checker(struct msdosfsmount *pmp, struct vnode *dvp, 68*aec97963SKonstantin Belousov struct denode *tdp, struct vnode **vpp) 69*aec97963SKonstantin Belousov { 70*aec97963SKonstantin Belousov struct vnode *vp; 71*aec97963SKonstantin Belousov 72*aec97963SKonstantin Belousov vp = DETOV(tdp); 73*aec97963SKonstantin Belousov 74*aec97963SKonstantin Belousov /* 75*aec97963SKonstantin Belousov * Lookup assumes that directory cannot be hardlinked. 76*aec97963SKonstantin Belousov * Corrupted msdosfs filesystem could break this assumption. 77*aec97963SKonstantin Belousov */ 78*aec97963SKonstantin Belousov if (vp == dvp) { 79*aec97963SKonstantin Belousov vput(vp); 80*aec97963SKonstantin Belousov *vpp = NULL; 81*aec97963SKonstantin Belousov return (EBADF); 82*aec97963SKonstantin Belousov } 83*aec97963SKonstantin Belousov 84*aec97963SKonstantin Belousov *vpp = vp; 85*aec97963SKonstantin Belousov return (0); 86*aec97963SKonstantin Belousov } 87*aec97963SKonstantin Belousov 88db811dd7SKonstantin Belousov int 89db811dd7SKonstantin Belousov msdosfs_lookup(struct vop_cachedlookup_args *ap) 90db811dd7SKonstantin Belousov { 91db811dd7SKonstantin Belousov 9295d42526SKonstantin Belousov return (msdosfs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL, 9395d42526SKonstantin Belousov NULL)); 94db811dd7SKonstantin Belousov } 95db811dd7SKonstantin Belousov 96a6945216SKonstantin Belousov struct deget_dotdot { 97a6945216SKonstantin Belousov u_long cluster; 98a6945216SKonstantin Belousov int blkoff; 99a6945216SKonstantin Belousov }; 100a6945216SKonstantin Belousov 101a6945216SKonstantin Belousov static int 102a6945216SKonstantin Belousov msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags, 103a6945216SKonstantin Belousov struct vnode **rvp) 104a6945216SKonstantin Belousov { 105a6945216SKonstantin Belousov struct deget_dotdot *dd_arg; 106a6945216SKonstantin Belousov struct denode *rdp; 107a6945216SKonstantin Belousov struct msdosfsmount *pmp; 108a6945216SKonstantin Belousov int error; 109a6945216SKonstantin Belousov 110a6945216SKonstantin Belousov pmp = VFSTOMSDOSFS(mp); 111a6945216SKonstantin Belousov dd_arg = arg; 112ae7e8a02SKonstantin Belousov error = deget(pmp, dd_arg->cluster, dd_arg->blkoff, 113ae7e8a02SKonstantin Belousov LK_EXCLUSIVE, &rdp); 114a6945216SKonstantin Belousov if (error == 0) 115a6945216SKonstantin Belousov *rvp = DETOV(rdp); 116a6945216SKonstantin Belousov return (error); 117a6945216SKonstantin Belousov } 118a6945216SKonstantin Belousov 11927a0bc89SDoug Rabson /* 12027a0bc89SDoug Rabson * When we search a directory the blocks containing directory entries are 12127a0bc89SDoug Rabson * read and examined. The directory entries contain information that would 12227a0bc89SDoug Rabson * normally be in the inode of a unix filesystem. This means that some of 12327a0bc89SDoug Rabson * a directory's contents may also be in memory resident denodes (sort of 12427a0bc89SDoug Rabson * an inode). This can cause problems if we are searching while some other 12527a0bc89SDoug Rabson * process is modifying a directory. To prevent one process from accessing 12627a0bc89SDoug Rabson * incompletely modified directory information we depend upon being the 127b84d2921SPoul-Henning Kamp * sole owner of a directory block. bread/brelse provide this service. 12827a0bc89SDoug Rabson * This being the case, when a process modifies a directory it must first 12927a0bc89SDoug Rabson * acquire the disk block that contains the directory entry to be modified. 13027a0bc89SDoug Rabson * Then update the disk block and the denode, and then write the disk block 13127a0bc89SDoug Rabson * out to disk. This way disk blocks containing directory entries and in 13227a0bc89SDoug Rabson * memory denode's will be in synch. 13327a0bc89SDoug Rabson */ 13492d4e088SKonstantin Belousov int 13595d42526SKonstantin Belousov msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname 13695d42526SKonstantin Belousov *cnp, daddr_t *scnp, u_long *blkoffp) 13727a0bc89SDoug Rabson { 138c2819440SBruce Evans struct mbnambuf nb; 13927a0bc89SDoug Rabson daddr_t bn; 14027a0bc89SDoug Rabson int error; 141952a6212SJordan K. Hubbard int slotcount; 142952a6212SJordan K. Hubbard int slotoffset = 0; 14327a0bc89SDoug Rabson int frcn; 14427a0bc89SDoug Rabson u_long cluster; 14595d42526SKonstantin Belousov u_long blkoff; 14627a0bc89SDoug Rabson int diroff; 147952a6212SJordan K. Hubbard int blsize; 14827a0bc89SDoug Rabson int isadir; /* ~0 if found direntry is a directory */ 14995d42526SKonstantin Belousov daddr_t scn; /* starting cluster number */ 15027a0bc89SDoug Rabson struct vnode *pdp; 15127a0bc89SDoug Rabson struct denode *dp; 15227a0bc89SDoug Rabson struct denode *tdp; 15327a0bc89SDoug Rabson struct msdosfsmount *pmp; 154f7a3729cSKevin Lo struct buf *bp = NULL; 15527a0bc89SDoug Rabson struct direntry *dep = NULL; 156a6945216SKonstantin Belousov struct deget_dotdot dd_arg; 15727a0bc89SDoug Rabson u_char dosfilename[12]; 15827a0bc89SDoug Rabson int flags = cnp->cn_flags; 15927a0bc89SDoug Rabson int nameiop = cnp->cn_nameiop; 16069a36f24SMike Smith int unlen; 16123c53312SEd Maste uint64_t inode1; 16227a0bc89SDoug Rabson 163952a6212SJordan K. Hubbard int wincnt = 1; 1646a5bf04aSTim J. Robbins int chksum = -1, chksum_ok; 165952a6212SJordan K. Hubbard int olddos = 1; 166952a6212SJordan K. Hubbard 16727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 16827a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); 16927a0bc89SDoug Rabson #endif 17027a0bc89SDoug Rabson dp = VTODE(vdp); 17127a0bc89SDoug Rabson pmp = dp->de_pmp; 17227a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 173952a6212SJordan K. Hubbard printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", 17427a0bc89SDoug Rabson vdp, dp, dp->de_Attributes); 17527a0bc89SDoug Rabson #endif 17627a0bc89SDoug Rabson 177db811dd7SKonstantin Belousov restart: 17884caee6bSKonstantin Belousov if (vpp != NULL) 17984caee6bSKonstantin Belousov *vpp = NULL; 18027a0bc89SDoug Rabson /* 18127a0bc89SDoug Rabson * If they are going after the . or .. entry in the root directory, 18227a0bc89SDoug Rabson * they won't find it. DOS filesystems don't have them in the root 18327a0bc89SDoug Rabson * directory. So, we fake it. deget() is in on this scam too. 18427a0bc89SDoug Rabson */ 185e6e370a7SJeff Roberson if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && 18627a0bc89SDoug Rabson (cnp->cn_namelen == 1 || 18727a0bc89SDoug Rabson (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 18827a0bc89SDoug Rabson isadir = ATTR_DIRECTORY; 18927a0bc89SDoug Rabson scn = MSDOSFSROOT; 19027a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 19127a0bc89SDoug Rabson printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 19227a0bc89SDoug Rabson #endif 19327a0bc89SDoug Rabson cluster = MSDOSFSROOT; 194952a6212SJordan K. Hubbard blkoff = MSDOSFSROOT_OFS; 19527a0bc89SDoug Rabson goto foundroot; 19627a0bc89SDoug Rabson } 19727a0bc89SDoug Rabson 198952a6212SJordan K. Hubbard switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 199c4f02a89SMax Khon cnp->cn_namelen, 0, pmp)) { 200952a6212SJordan K. Hubbard case 0: 201952a6212SJordan K. Hubbard return (EINVAL); 202952a6212SJordan K. Hubbard case 1: 203952a6212SJordan K. Hubbard break; 204952a6212SJordan K. Hubbard case 2: 205952a6212SJordan K. Hubbard wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 206c4f02a89SMax Khon cnp->cn_namelen, pmp) + 1; 207952a6212SJordan K. Hubbard break; 208952a6212SJordan K. Hubbard case 3: 209952a6212SJordan K. Hubbard olddos = 0; 210952a6212SJordan K. Hubbard wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 211c4f02a89SMax Khon cnp->cn_namelen, pmp) + 1; 212952a6212SJordan K. Hubbard break; 21327a0bc89SDoug Rabson } 214011cdb57SDmitrij Tejblum if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) { 215952a6212SJordan K. Hubbard wincnt = 1; 216011cdb57SDmitrij Tejblum olddos = 1; 217011cdb57SDmitrij Tejblum } 21869a36f24SMike Smith unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen); 21927a0bc89SDoug Rabson 220952a6212SJordan K. Hubbard /* 221952a6212SJordan K. Hubbard * Suppress search for slots unless creating 222952a6212SJordan K. Hubbard * file and at end of pathname, in which case 223952a6212SJordan K. Hubbard * we watch for a place to put the new file in 224952a6212SJordan K. Hubbard * case it doesn't already exist. 225952a6212SJordan K. Hubbard */ 226952a6212SJordan K. Hubbard slotcount = wincnt; 227952a6212SJordan K. Hubbard if ((nameiop == CREATE || nameiop == RENAME) && 228952a6212SJordan K. Hubbard (flags & ISLASTCN)) 229952a6212SJordan K. Hubbard slotcount = 0; 230952a6212SJordan K. Hubbard 23127a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 232952a6212SJordan K. Hubbard printf("msdosfs_lookup(): dos version of filename %s, length %ld\n", 23327a0bc89SDoug Rabson dosfilename, cnp->cn_namelen); 23427a0bc89SDoug Rabson #endif 23527a0bc89SDoug Rabson /* 23627a0bc89SDoug Rabson * Search the directory pointed at by vdp for the name pointed at 23727a0bc89SDoug Rabson * by cnp->cn_nameptr. 23827a0bc89SDoug Rabson */ 23927a0bc89SDoug Rabson tdp = NULL; 240c2819440SBruce Evans mbnambuf_init(&nb); 24127a0bc89SDoug Rabson /* 24227a0bc89SDoug Rabson * The outer loop ranges over the clusters that make up the 24327a0bc89SDoug Rabson * directory. Note that the root directory is different from all 24427a0bc89SDoug Rabson * other directories. It has a fixed number of blocks that are not 24527a0bc89SDoug Rabson * part of the pool of allocatable clusters. So, we treat it a 24627a0bc89SDoug Rabson * little differently. The root directory starts at "cluster" 0. 24727a0bc89SDoug Rabson */ 248952a6212SJordan K. Hubbard diroff = 0; 24927a0bc89SDoug Rabson for (frcn = 0;; frcn++) { 250952a6212SJordan K. Hubbard error = pcbmap(dp, frcn, &bn, &cluster, &blsize); 251c3c6d51eSPoul-Henning Kamp if (error) { 25227a0bc89SDoug Rabson if (error == E2BIG) 25327a0bc89SDoug Rabson break; 254952a6212SJordan K. Hubbard return (error); 25527a0bc89SDoug Rabson } 256952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 257952a6212SJordan K. Hubbard if (error) { 258952a6212SJordan K. Hubbard return (error); 259952a6212SJordan K. Hubbard } 260952a6212SJordan K. Hubbard for (blkoff = 0; blkoff < blsize; 261952a6212SJordan K. Hubbard blkoff += sizeof(struct direntry), 262952a6212SJordan K. Hubbard diroff += sizeof(struct direntry)) { 263952a6212SJordan K. Hubbard dep = (struct direntry *)(bp->b_data + blkoff); 26427a0bc89SDoug Rabson /* 26527a0bc89SDoug Rabson * If the slot is empty and we are still looking 26627a0bc89SDoug Rabson * for an empty then remember this one. If the 26727a0bc89SDoug Rabson * slot is not empty then check to see if it 26827a0bc89SDoug Rabson * matches what we are looking for. If the slot 26927a0bc89SDoug Rabson * has never been filled with anything, then the 27027a0bc89SDoug Rabson * remainder of the directory has never been used, 27127a0bc89SDoug Rabson * so there is no point in searching it. 27227a0bc89SDoug Rabson */ 27327a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY || 27427a0bc89SDoug Rabson dep->deName[0] == SLOT_DELETED) { 275952a6212SJordan K. Hubbard /* 276952a6212SJordan K. Hubbard * Drop memory of previous long matches 277952a6212SJordan K. Hubbard */ 278952a6212SJordan K. Hubbard chksum = -1; 279c2819440SBruce Evans mbnambuf_init(&nb); 280952a6212SJordan K. Hubbard 281952a6212SJordan K. Hubbard if (slotcount < wincnt) { 282952a6212SJordan K. Hubbard slotcount++; 28327a0bc89SDoug Rabson slotoffset = diroff; 28427a0bc89SDoug Rabson } 28527a0bc89SDoug Rabson if (dep->deName[0] == SLOT_EMPTY) { 28627a0bc89SDoug Rabson brelse(bp); 28727a0bc89SDoug Rabson goto notfound; 28827a0bc89SDoug Rabson } 28927a0bc89SDoug Rabson } else { 29027a0bc89SDoug Rabson /* 291952a6212SJordan K. Hubbard * If there wasn't enough space for our winentries, 292952a6212SJordan K. Hubbard * forget about the empty space 293952a6212SJordan K. Hubbard */ 294952a6212SJordan K. Hubbard if (slotcount < wincnt) 295952a6212SJordan K. Hubbard slotcount = 0; 296952a6212SJordan K. Hubbard 297952a6212SJordan K. Hubbard /* 298952a6212SJordan K. Hubbard * Check for Win95 long filename entry 299952a6212SJordan K. Hubbard */ 300952a6212SJordan K. Hubbard if (dep->deAttributes == ATTR_WIN95) { 301952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 302952a6212SJordan K. Hubbard continue; 303952a6212SJordan K. Hubbard 304c2819440SBruce Evans chksum = win2unixfn(&nb, 305c2819440SBruce Evans (struct winentry *)dep, chksum, 306c4f02a89SMax Khon pmp); 307c4f02a89SMax Khon continue; 308c4f02a89SMax Khon } 309c4f02a89SMax Khon 310c2819440SBruce Evans chksum = winChkName(&nb, 311c2819440SBruce Evans (const u_char *)cnp->cn_nameptr, unlen, 312c2819440SBruce Evans chksum, pmp); 313c4f02a89SMax Khon if (chksum == -2) { 314c4f02a89SMax Khon chksum = -1; 315952a6212SJordan K. Hubbard continue; 316952a6212SJordan K. Hubbard } 317952a6212SJordan K. Hubbard 318952a6212SJordan K. Hubbard /* 31927a0bc89SDoug Rabson * Ignore volume labels (anywhere, not just 32027a0bc89SDoug Rabson * the root directory). 32127a0bc89SDoug Rabson */ 322952a6212SJordan K. Hubbard if (dep->deAttributes & ATTR_VOLUME) { 323952a6212SJordan K. Hubbard chksum = -1; 324952a6212SJordan K. Hubbard continue; 325952a6212SJordan K. Hubbard } 326952a6212SJordan K. Hubbard 327952a6212SJordan K. Hubbard /* 328952a6212SJordan K. Hubbard * Check for a checksum or name match 329952a6212SJordan K. Hubbard */ 33048d1bcf8SKonstantin Belousov chksum_ok = (chksum == winChksum(dep->deName)); 3316a5bf04aSTim J. Robbins if (!chksum_ok 332952a6212SJordan K. Hubbard && (!olddos || bcmp(dosfilename, dep->deName, 11))) { 333952a6212SJordan K. Hubbard chksum = -1; 334952a6212SJordan K. Hubbard continue; 335952a6212SJordan K. Hubbard } 33627a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 337952a6212SJordan K. Hubbard printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", 338952a6212SJordan K. Hubbard blkoff, diroff); 33927a0bc89SDoug Rabson #endif 34027a0bc89SDoug Rabson /* 34127a0bc89SDoug Rabson * Remember where this directory 34227a0bc89SDoug Rabson * entry came from for whoever did 343952a6212SJordan K. Hubbard * this lookup. 34427a0bc89SDoug Rabson */ 34527a0bc89SDoug Rabson dp->de_fndoffset = diroff; 3466a5bf04aSTim J. Robbins if (chksum_ok && nameiop == RENAME) { 3476a5bf04aSTim J. Robbins /* 3486a5bf04aSTim J. Robbins * Target had correct long name 3496a5bf04aSTim J. Robbins * directory entries, reuse them 3506a5bf04aSTim J. Robbins * as needed. 3516a5bf04aSTim J. Robbins */ 352191e6fd0SDmitrij Tejblum dp->de_fndcnt = wincnt - 1; 3536a5bf04aSTim J. Robbins } else { 3546a5bf04aSTim J. Robbins /* 3556a5bf04aSTim J. Robbins * Long name directory entries 3566a5bf04aSTim J. Robbins * not present or corrupt, can only 3576a5bf04aSTim J. Robbins * reuse dos directory entry. 3586a5bf04aSTim J. Robbins */ 3596a5bf04aSTim J. Robbins dp->de_fndcnt = 0; 3606a5bf04aSTim J. Robbins } 361952a6212SJordan K. Hubbard 36227a0bc89SDoug Rabson goto found; 36327a0bc89SDoug Rabson } 364952a6212SJordan K. Hubbard } /* for (blkoff = 0; .... */ 36527a0bc89SDoug Rabson /* 36627a0bc89SDoug Rabson * Release the buffer holding the directory cluster just 36727a0bc89SDoug Rabson * searched. 36827a0bc89SDoug Rabson */ 36927a0bc89SDoug Rabson brelse(bp); 37027a0bc89SDoug Rabson } /* for (frcn = 0; ; frcn++) */ 371952a6212SJordan K. Hubbard 372952a6212SJordan K. Hubbard notfound: 37327a0bc89SDoug Rabson /* 37427a0bc89SDoug Rabson * We hold no disk buffers at this point. 37527a0bc89SDoug Rabson */ 37627a0bc89SDoug Rabson 37727a0bc89SDoug Rabson /* 378952a6212SJordan K. Hubbard * Fixup the slot description to point to the place where 379952a6212SJordan K. Hubbard * we might put the new DOS direntry (putting the Win95 380952a6212SJordan K. Hubbard * long name entries before that) 381952a6212SJordan K. Hubbard */ 382952a6212SJordan K. Hubbard if (!slotcount) { 383952a6212SJordan K. Hubbard slotcount = 1; 384952a6212SJordan K. Hubbard slotoffset = diroff; 385952a6212SJordan K. Hubbard } 386952a6212SJordan K. Hubbard if (wincnt > slotcount) 387952a6212SJordan K. Hubbard slotoffset += sizeof(struct direntry) * (wincnt - slotcount); 388952a6212SJordan K. Hubbard 389952a6212SJordan K. Hubbard /* 39027a0bc89SDoug Rabson * If we get here we didn't find the entry we were looking for. But 39127a0bc89SDoug Rabson * that's ok if we are creating or renaming and are at the end of 39227a0bc89SDoug Rabson * the pathname and the directory hasn't been removed. 39327a0bc89SDoug Rabson */ 39427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 395952a6212SJordan K. Hubbard printf("msdosfs_lookup(): op %d, refcnt %ld\n", 396952a6212SJordan K. Hubbard nameiop, dp->de_refcnt); 397952a6212SJordan K. Hubbard printf(" slotcount %d, slotoffset %d\n", 398952a6212SJordan K. Hubbard slotcount, slotoffset); 39927a0bc89SDoug Rabson #endif 40027a0bc89SDoug Rabson if ((nameiop == CREATE || nameiop == RENAME) && 40127a0bc89SDoug Rabson (flags & ISLASTCN) && dp->de_refcnt != 0) { 402952a6212SJordan K. Hubbard /* 403952a6212SJordan K. Hubbard * Access for write is interpreted as allowing 404952a6212SJordan K. Hubbard * creation of files in the directory. 405952a6212SJordan K. Hubbard */ 406b4a58fbfSMateusz Guzik error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); 407d8762fa6SBruce Evans if (error) 408952a6212SJordan K. Hubbard return (error); 409952a6212SJordan K. Hubbard /* 410952a6212SJordan K. Hubbard * Return an indication of where the new directory 411952a6212SJordan K. Hubbard * entry should be put. 412952a6212SJordan K. Hubbard */ 41327a0bc89SDoug Rabson dp->de_fndoffset = slotoffset; 414952a6212SJordan K. Hubbard dp->de_fndcnt = wincnt - 1; 415952a6212SJordan K. Hubbard 416952a6212SJordan K. Hubbard /* 417952a6212SJordan K. Hubbard * We return with the directory locked, so that 418952a6212SJordan K. Hubbard * the parameters we set up above will still be 419952a6212SJordan K. Hubbard * valid if we actually decide to do a direnter(). 420952a6212SJordan K. Hubbard * We return ni_vp == NULL to indicate that the entry 421952a6212SJordan K. Hubbard * does not currently exist; we leave a pointer to 422952a6212SJordan K. Hubbard * the (locked) directory inode in ndp->ni_dvp. 423952a6212SJordan K. Hubbard * The pathname buffer is saved so that the name 424952a6212SJordan K. Hubbard * can be obtained later. 425952a6212SJordan K. Hubbard * 426952a6212SJordan K. Hubbard * NB - if the directory is unlocked, then this 427952a6212SJordan K. Hubbard * information cannot be used. 428952a6212SJordan K. Hubbard */ 42927a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 430952a6212SJordan K. Hubbard return (EJUSTRETURN); 43127a0bc89SDoug Rabson } 43223e8fcafSDavid Schultz #if 0 43327a0bc89SDoug Rabson /* 434952a6212SJordan K. Hubbard * Insert name into cache (as non-existent) if appropriate. 43523e8fcafSDavid Schultz * 43623e8fcafSDavid Schultz * XXX Negative caching is broken for msdosfs because the name 43723e8fcafSDavid Schultz * cache doesn't understand peculiarities such as case insensitivity 43823e8fcafSDavid Schultz * and 8.3 filenames. Hence, it may not invalidate all negative 43923e8fcafSDavid Schultz * entries if a file with this name is later created. 44027a0bc89SDoug Rabson */ 4416c21f6edSKonstantin Belousov if ((cnp->cn_flags & MAKEENTRY) != 0) 44227a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 44323e8fcafSDavid Schultz #endif 444952a6212SJordan K. Hubbard return (ENOENT); 44527a0bc89SDoug Rabson 446952a6212SJordan K. Hubbard found: 44727a0bc89SDoug Rabson /* 44827a0bc89SDoug Rabson * NOTE: We still have the buffer with matched directory entry at 44927a0bc89SDoug Rabson * this point. 45027a0bc89SDoug Rabson */ 45127a0bc89SDoug Rabson isadir = dep->deAttributes & ATTR_DIRECTORY; 45227a0bc89SDoug Rabson scn = getushort(dep->deStartCluster); 453952a6212SJordan K. Hubbard if (FAT32(pmp)) { 454952a6212SJordan K. Hubbard scn |= getushort(dep->deHighClust) << 16; 455952a6212SJordan K. Hubbard if (scn == pmp->pm_rootdirblk) { 456952a6212SJordan K. Hubbard /* 457952a6212SJordan K. Hubbard * There should actually be 0 here. 458952a6212SJordan K. Hubbard * Just ignore the error. 459952a6212SJordan K. Hubbard */ 460952a6212SJordan K. Hubbard scn = MSDOSFSROOT; 461952a6212SJordan K. Hubbard } 462952a6212SJordan K. Hubbard } 46327a0bc89SDoug Rabson 464952a6212SJordan K. Hubbard if (isadir) { 465952a6212SJordan K. Hubbard cluster = scn; 466952a6212SJordan K. Hubbard if (cluster == MSDOSFSROOT) 467952a6212SJordan K. Hubbard blkoff = MSDOSFSROOT_OFS; 468952a6212SJordan K. Hubbard else 469952a6212SJordan K. Hubbard blkoff = 0; 470952a6212SJordan K. Hubbard } else if (cluster == MSDOSFSROOT) 471952a6212SJordan K. Hubbard blkoff = diroff; 472952a6212SJordan K. Hubbard 473952a6212SJordan K. Hubbard /* 474952a6212SJordan K. Hubbard * Now release buf to allow deget to read the entry again. 475952a6212SJordan K. Hubbard * Reserving it here and giving it to deget could result 476952a6212SJordan K. Hubbard * in a deadlock. 477952a6212SJordan K. Hubbard */ 478952a6212SJordan K. Hubbard brelse(bp); 4790d3e502fSPedro F. Giffuni bp = NULL; 480952a6212SJordan K. Hubbard 481952a6212SJordan K. Hubbard foundroot: 48227a0bc89SDoug Rabson /* 48327a0bc89SDoug Rabson * If we entered at foundroot, then we are looking for the . or .. 48427a0bc89SDoug Rabson * entry of the filesystems root directory. isadir and scn were 485952a6212SJordan K. Hubbard * setup before jumping here. And, bp is already null. 48627a0bc89SDoug Rabson */ 487952a6212SJordan K. Hubbard if (FAT32(pmp) && scn == MSDOSFSROOT) 488952a6212SJordan K. Hubbard scn = pmp->pm_rootdirblk; 48927a0bc89SDoug Rabson 49095d42526SKonstantin Belousov if (scnp != NULL) { 49195d42526SKonstantin Belousov *scnp = cluster; 49295d42526SKonstantin Belousov *blkoffp = blkoff; 493db811dd7SKonstantin Belousov return (0); 494db811dd7SKonstantin Belousov } 495db811dd7SKonstantin Belousov 49627a0bc89SDoug Rabson /* 497952a6212SJordan K. Hubbard * If deleting, and at end of pathname, return 498952a6212SJordan K. Hubbard * parameters which can be used to remove file. 49927a0bc89SDoug Rabson */ 50027a0bc89SDoug Rabson if (nameiop == DELETE && (flags & ISLASTCN)) { 501952a6212SJordan K. Hubbard /* 502952a6212SJordan K. Hubbard * Don't allow deleting the root. 503952a6212SJordan K. Hubbard */ 504952a6212SJordan K. Hubbard if (blkoff == MSDOSFSROOT_OFS) 5059ba671deSKonstantin Belousov return (EBUSY); 506952a6212SJordan K. Hubbard 507952a6212SJordan K. Hubbard /* 508952a6212SJordan K. Hubbard * Write access to directory required to delete files. 509952a6212SJordan K. Hubbard */ 510b4a58fbfSMateusz Guzik error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); 511952a6212SJordan K. Hubbard if (error) 512952a6212SJordan K. Hubbard return (error); 513952a6212SJordan K. Hubbard 514952a6212SJordan K. Hubbard /* 515952a6212SJordan K. Hubbard * Return pointer to current entry in dp->i_offset. 516952a6212SJordan K. Hubbard * Save directory inode pointer in ndp->ni_dvp for dirremove(). 517952a6212SJordan K. Hubbard */ 51827a0bc89SDoug Rabson if (dp->de_StartCluster == scn && isadir) { /* "." */ 51927a0bc89SDoug Rabson VREF(vdp); 52027a0bc89SDoug Rabson *vpp = vdp; 521952a6212SJordan K. Hubbard return (0); 52227a0bc89SDoug Rabson } 523ae7e8a02SKonstantin Belousov error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp); 524952a6212SJordan K. Hubbard if (error) 525952a6212SJordan K. Hubbard return (error); 526*aec97963SKonstantin Belousov return (msdosfs_lookup_checker(pmp, vdp, tdp, vpp)); 52727a0bc89SDoug Rabson } 52827a0bc89SDoug Rabson 52927a0bc89SDoug Rabson /* 530952a6212SJordan K. Hubbard * If rewriting (RENAME), return the inode and the 531952a6212SJordan K. Hubbard * information required to rewrite the present directory 532952a6212SJordan K. Hubbard * Must get inode of directory entry to verify it's a 533952a6212SJordan K. Hubbard * regular file, or empty directory. 53427a0bc89SDoug Rabson */ 535fcc9c112SJeff Roberson if (nameiop == RENAME && (flags & ISLASTCN)) { 536952a6212SJordan K. Hubbard if (blkoff == MSDOSFSROOT_OFS) 5379ba671deSKonstantin Belousov return (EBUSY); 538952a6212SJordan K. Hubbard 539b4a58fbfSMateusz Guzik error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); 540952a6212SJordan K. Hubbard if (error) 541952a6212SJordan K. Hubbard return (error); 542952a6212SJordan K. Hubbard 543952a6212SJordan K. Hubbard /* 544952a6212SJordan K. Hubbard * Careful about locking second inode. 545952a6212SJordan K. Hubbard * This can only occur if the target is ".". 546952a6212SJordan K. Hubbard */ 547952a6212SJordan K. Hubbard if (dp->de_StartCluster == scn && isadir) 548952a6212SJordan K. Hubbard return (EISDIR); 549952a6212SJordan K. Hubbard 550ae7e8a02SKonstantin Belousov if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, 551ae7e8a02SKonstantin Belousov &tdp)) != 0) 552952a6212SJordan K. Hubbard return (error); 553*aec97963SKonstantin Belousov if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) 554*aec97963SKonstantin Belousov != 0) 555*aec97963SKonstantin Belousov return (error); 55627a0bc89SDoug Rabson cnp->cn_flags |= SAVENAME; 557952a6212SJordan K. Hubbard return (0); 55827a0bc89SDoug Rabson } 55927a0bc89SDoug Rabson 56027a0bc89SDoug Rabson /* 561952a6212SJordan K. Hubbard * Step through the translation in the name. We do not `vput' the 562952a6212SJordan K. Hubbard * directory because we may need it again if a symbolic link 563952a6212SJordan K. Hubbard * is relative to the current directory. Instead we save it 564952a6212SJordan K. Hubbard * unlocked as "pdp". We must get the target inode before unlocking 565952a6212SJordan K. Hubbard * the directory to insure that the inode will not be removed 566952a6212SJordan K. Hubbard * before we get it. We prevent deadlock by always fetching 567952a6212SJordan K. Hubbard * inodes from the root, moving down the directory tree. Thus 568952a6212SJordan K. Hubbard * when following backward pointers ".." we must unlock the 569952a6212SJordan K. Hubbard * parent directory before getting the requested directory. 57027a0bc89SDoug Rabson */ 57127a0bc89SDoug Rabson pdp = vdp; 57227a0bc89SDoug Rabson if (flags & ISDOTDOT) { 573a6945216SKonstantin Belousov dd_arg.cluster = cluster; 574a6945216SKonstantin Belousov dd_arg.blkoff = blkoff; 575a6945216SKonstantin Belousov error = vn_vget_ino_gen(vdp, msdosfs_deget_dotdot, 576a6945216SKonstantin Belousov &dd_arg, cnp->cn_lkflags, vpp); 577a6945216SKonstantin Belousov if (error != 0) { 57884caee6bSKonstantin Belousov *vpp = NULL; 579952a6212SJordan K. Hubbard return (error); 58084caee6bSKonstantin Belousov } 581db811dd7SKonstantin Belousov /* 582db811dd7SKonstantin Belousov * Recheck that ".." still points to the inode we 583db811dd7SKonstantin Belousov * looked up before pdp lock was dropped. 584db811dd7SKonstantin Belousov */ 58595d42526SKonstantin Belousov error = msdosfs_lookup_ino(pdp, NULL, cnp, &scn, &blkoff); 586db811dd7SKonstantin Belousov if (error) { 587db811dd7SKonstantin Belousov vput(*vpp); 58884caee6bSKonstantin Belousov *vpp = NULL; 589db811dd7SKonstantin Belousov return (error); 590db811dd7SKonstantin Belousov } 59195d42526SKonstantin Belousov if (FAT32(pmp) && scn == MSDOSFSROOT) 59295d42526SKonstantin Belousov scn = pmp->pm_rootdirblk; 59395d42526SKonstantin Belousov inode1 = scn * pmp->pm_bpcluster + blkoff; 594db811dd7SKonstantin Belousov if (VTODE(*vpp)->de_inode != inode1) { 595db811dd7SKonstantin Belousov vput(*vpp); 596db811dd7SKonstantin Belousov goto restart; 597db811dd7SKonstantin Belousov } 598*aec97963SKonstantin Belousov return (msdosfs_lookup_checker(pmp, vdp, VTODE(*vpp), vpp)); 599952a6212SJordan K. Hubbard } else if (dp->de_StartCluster == scn && isadir) { 6001319c433SKonstantin Belousov if (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.') { 6011319c433SKonstantin Belousov /* fs is corrupted, non-dot lookup returned dvp */ 6021319c433SKonstantin Belousov return (EBADF); 6031319c433SKonstantin Belousov } 604952a6212SJordan K. Hubbard VREF(vdp); /* we want ourself, ie "." */ 60527a0bc89SDoug Rabson *vpp = vdp; 60627a0bc89SDoug Rabson } else { 607ae7e8a02SKonstantin Belousov if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, 608ae7e8a02SKonstantin Belousov &tdp)) != 0) 609952a6212SJordan K. Hubbard return (error); 610*aec97963SKonstantin Belousov if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) != 0) 611*aec97963SKonstantin Belousov return (error); 61227a0bc89SDoug Rabson } 61327a0bc89SDoug Rabson 61427a0bc89SDoug Rabson /* 615952a6212SJordan K. Hubbard * Insert name into cache if appropriate. 61627a0bc89SDoug Rabson */ 61727a0bc89SDoug Rabson if (cnp->cn_flags & MAKEENTRY) 61827a0bc89SDoug Rabson cache_enter(vdp, *vpp, cnp); 619952a6212SJordan K. Hubbard return (0); 62027a0bc89SDoug Rabson } 62127a0bc89SDoug Rabson 62227a0bc89SDoug Rabson /* 62327a0bc89SDoug Rabson * dep - directory entry to copy into the directory 62427a0bc89SDoug Rabson * ddep - directory to add to 62527a0bc89SDoug Rabson * depp - return the address of the denode for the created directory entry 62627a0bc89SDoug Rabson * if depp != 0 627952a6212SJordan K. Hubbard * cnp - componentname needed for Win95 long filenames 62827a0bc89SDoug Rabson */ 62927a0bc89SDoug Rabson int 63010c9700fSEd Maste createde(struct denode *dep, struct denode *ddep, struct denode **depp, 63110c9700fSEd Maste struct componentname *cnp) 63227a0bc89SDoug Rabson { 63327a0bc89SDoug Rabson int error; 63427a0bc89SDoug Rabson u_long dirclust, diroffset; 63527a0bc89SDoug Rabson struct direntry *ndep; 63627a0bc89SDoug Rabson struct msdosfsmount *pmp = ddep->de_pmp; 63727a0bc89SDoug Rabson struct buf *bp; 638952a6212SJordan K. Hubbard daddr_t bn; 639952a6212SJordan K. Hubbard int blsize; 64027a0bc89SDoug Rabson 64127a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 642952a6212SJordan K. Hubbard printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 643952a6212SJordan K. Hubbard dep, ddep, depp, cnp); 64427a0bc89SDoug Rabson #endif 64527a0bc89SDoug Rabson 64627a0bc89SDoug Rabson /* 64727a0bc89SDoug Rabson * If no space left in the directory then allocate another cluster 64827a0bc89SDoug Rabson * and chain it onto the end of the file. There is one exception 64927a0bc89SDoug Rabson * to this. That is, if the root directory has no more space it 65027a0bc89SDoug Rabson * can NOT be expanded. extendfile() checks for and fails attempts 65127a0bc89SDoug Rabson * to extend the root directory. We just return an error in that 65227a0bc89SDoug Rabson * case. 65327a0bc89SDoug Rabson */ 654952a6212SJordan K. Hubbard if (ddep->de_fndoffset >= ddep->de_FileSize) { 655952a6212SJordan K. Hubbard diroffset = ddep->de_fndoffset + sizeof(struct direntry) 656952a6212SJordan K. Hubbard - ddep->de_FileSize; 657952a6212SJordan K. Hubbard dirclust = de_clcount(pmp, diroffset); 658952a6212SJordan K. Hubbard error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); 659952a6212SJordan K. Hubbard if (error) { 660c52fd858SEdward Tomasz Napierala (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); 66127a0bc89SDoug Rabson return error; 662952a6212SJordan K. Hubbard } 663952a6212SJordan K. Hubbard 66427a0bc89SDoug Rabson /* 66527a0bc89SDoug Rabson * Update the size of the directory 66627a0bc89SDoug Rabson */ 667952a6212SJordan K. Hubbard ddep->de_FileSize += de_cn2off(pmp, dirclust); 668952a6212SJordan K. Hubbard } 669952a6212SJordan K. Hubbard 67027a0bc89SDoug Rabson /* 671952a6212SJordan K. Hubbard * We just read in the cluster with space. Copy the new directory 67227a0bc89SDoug Rabson * entry in. Then write it to disk. NOTE: DOS directories 67327a0bc89SDoug Rabson * do not get smaller as clusters are emptied. 67427a0bc89SDoug Rabson */ 675952a6212SJordan K. Hubbard error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 676952a6212SJordan K. Hubbard &bn, &dirclust, &blsize); 67727a0bc89SDoug Rabson if (error) 67827a0bc89SDoug Rabson return error; 679952a6212SJordan K. Hubbard diroffset = ddep->de_fndoffset; 680952a6212SJordan K. Hubbard if (dirclust != MSDOSFSROOT) 681952a6212SJordan K. Hubbard diroffset &= pmp->pm_crbomask; 682952a6212SJordan K. Hubbard if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { 683952a6212SJordan K. Hubbard brelse(bp); 684952a6212SJordan K. Hubbard return error; 68527a0bc89SDoug Rabson } 686952a6212SJordan K. Hubbard ndep = bptoep(pmp, bp, ddep->de_fndoffset); 687952a6212SJordan K. Hubbard 68827a0bc89SDoug Rabson DE_EXTERNALIZE(ndep, dep); 68927a0bc89SDoug Rabson 69027a0bc89SDoug Rabson /* 691952a6212SJordan K. Hubbard * Now write the Win95 long name 692952a6212SJordan K. Hubbard */ 693952a6212SJordan K. Hubbard if (ddep->de_fndcnt > 0) { 69423c53312SEd Maste uint8_t chksum = winChksum(ndep->deName); 695952a6212SJordan K. Hubbard const u_char *un = (const u_char *)cnp->cn_nameptr; 696952a6212SJordan K. Hubbard int unlen = cnp->cn_namelen; 697952a6212SJordan K. Hubbard int cnt = 1; 698952a6212SJordan K. Hubbard 699952a6212SJordan K. Hubbard while (--ddep->de_fndcnt >= 0) { 700952a6212SJordan K. Hubbard if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { 7012aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(ddep))) 702cb65c1eeSBruce Evans bdwrite(bp); 703cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 704952a6212SJordan K. Hubbard return error; 705952a6212SJordan K. Hubbard 706952a6212SJordan K. Hubbard ddep->de_fndoffset -= sizeof(struct direntry); 707952a6212SJordan K. Hubbard error = pcbmap(ddep, 708952a6212SJordan K. Hubbard de_cluster(pmp, 709952a6212SJordan K. Hubbard ddep->de_fndoffset), 710952a6212SJordan K. Hubbard &bn, 0, &blsize); 711952a6212SJordan K. Hubbard if (error) 712952a6212SJordan K. Hubbard return error; 713952a6212SJordan K. Hubbard 714952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, 715952a6212SJordan K. Hubbard NOCRED, &bp); 716952a6212SJordan K. Hubbard if (error) { 717952a6212SJordan K. Hubbard return error; 718952a6212SJordan K. Hubbard } 719952a6212SJordan K. Hubbard ndep = bptoep(pmp, bp, ddep->de_fndoffset); 720952a6212SJordan K. Hubbard } else { 721952a6212SJordan K. Hubbard ndep--; 722952a6212SJordan K. Hubbard ddep->de_fndoffset -= sizeof(struct direntry); 723952a6212SJordan K. Hubbard } 72413df76f2SAndrey A. Chernov if (!unix2winfn(un, unlen, (struct winentry *)ndep, 725c4f02a89SMax Khon cnt++, chksum, pmp)) 726952a6212SJordan K. Hubbard break; 727952a6212SJordan K. Hubbard } 728952a6212SJordan K. Hubbard } 729952a6212SJordan K. Hubbard 7302aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(ddep))) 731cb65c1eeSBruce Evans bdwrite(bp); 732cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 733952a6212SJordan K. Hubbard return error; 734952a6212SJordan K. Hubbard 735952a6212SJordan K. Hubbard /* 73627a0bc89SDoug Rabson * If they want us to return with the denode gotten. 73727a0bc89SDoug Rabson */ 73827a0bc89SDoug Rabson if (depp) { 739952a6212SJordan K. Hubbard if (dep->de_Attributes & ATTR_DIRECTORY) { 740952a6212SJordan K. Hubbard dirclust = dep->de_StartCluster; 741952a6212SJordan K. Hubbard if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 742952a6212SJordan K. Hubbard dirclust = MSDOSFSROOT; 743952a6212SJordan K. Hubbard if (dirclust == MSDOSFSROOT) 744952a6212SJordan K. Hubbard diroffset = MSDOSFSROOT_OFS; 745952a6212SJordan K. Hubbard else 746952a6212SJordan K. Hubbard diroffset = 0; 74727a0bc89SDoug Rabson } 748ae7e8a02SKonstantin Belousov return (deget(pmp, dirclust, diroffset, LK_EXCLUSIVE, depp)); 74927a0bc89SDoug Rabson } 750952a6212SJordan K. Hubbard 75127a0bc89SDoug Rabson return 0; 75227a0bc89SDoug Rabson } 75327a0bc89SDoug Rabson 75427a0bc89SDoug Rabson /* 75527a0bc89SDoug Rabson * Be sure a directory is empty except for "." and "..". Return 1 if empty, 75627a0bc89SDoug Rabson * return 0 if not empty or error. 75727a0bc89SDoug Rabson */ 75827a0bc89SDoug Rabson int 75910c9700fSEd Maste dosdirempty(struct denode *dep) 76027a0bc89SDoug Rabson { 761952a6212SJordan K. Hubbard int blsize; 76227a0bc89SDoug Rabson int error; 76327a0bc89SDoug Rabson u_long cn; 76427a0bc89SDoug Rabson daddr_t bn; 76527a0bc89SDoug Rabson struct buf *bp; 76627a0bc89SDoug Rabson struct msdosfsmount *pmp = dep->de_pmp; 76727a0bc89SDoug Rabson struct direntry *dentp; 76827a0bc89SDoug Rabson 76927a0bc89SDoug Rabson /* 77027a0bc89SDoug Rabson * Since the filesize field in directory entries for a directory is 77127a0bc89SDoug Rabson * zero, we just have to feel our way through the directory until 77227a0bc89SDoug Rabson * we hit end of file. 77327a0bc89SDoug Rabson */ 77427a0bc89SDoug Rabson for (cn = 0;; cn++) { 775952a6212SJordan K. Hubbard if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 77627a0bc89SDoug Rabson if (error == E2BIG) 777952a6212SJordan K. Hubbard return (1); /* it's empty */ 778952a6212SJordan K. Hubbard return (0); 779952a6212SJordan K. Hubbard } 780952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 781952a6212SJordan K. Hubbard if (error) { 782952a6212SJordan K. Hubbard return (0); 783952a6212SJordan K. Hubbard } 784952a6212SJordan K. Hubbard for (dentp = (struct direntry *)bp->b_data; 785952a6212SJordan K. Hubbard (char *)dentp < bp->b_data + blsize; 786952a6212SJordan K. Hubbard dentp++) { 787952a6212SJordan K. Hubbard if (dentp->deName[0] != SLOT_DELETED && 788952a6212SJordan K. Hubbard (dentp->deAttributes & ATTR_VOLUME) == 0) { 78927a0bc89SDoug Rabson /* 79027a0bc89SDoug Rabson * In dos directories an entry whose name 79127a0bc89SDoug Rabson * starts with SLOT_EMPTY (0) starts the 79227a0bc89SDoug Rabson * beginning of the unused part of the 79327a0bc89SDoug Rabson * directory, so we can just return that it 79427a0bc89SDoug Rabson * is empty. 79527a0bc89SDoug Rabson */ 79627a0bc89SDoug Rabson if (dentp->deName[0] == SLOT_EMPTY) { 79727a0bc89SDoug Rabson brelse(bp); 798952a6212SJordan K. Hubbard return (1); 79927a0bc89SDoug Rabson } 80027a0bc89SDoug Rabson /* 80127a0bc89SDoug Rabson * Any names other than "." and ".." in a 80227a0bc89SDoug Rabson * directory mean it is not empty. 80327a0bc89SDoug Rabson */ 80427a0bc89SDoug Rabson if (bcmp(dentp->deName, ". ", 11) && 80527a0bc89SDoug Rabson bcmp(dentp->deName, ".. ", 11)) { 80627a0bc89SDoug Rabson brelse(bp); 80727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 808952a6212SJordan K. Hubbard printf("dosdirempty(): entry found %02x, %02x\n", 809952a6212SJordan K. Hubbard dentp->deName[0], dentp->deName[1]); 81027a0bc89SDoug Rabson #endif 811952a6212SJordan K. Hubbard return (0); /* not empty */ 81227a0bc89SDoug Rabson } 81327a0bc89SDoug Rabson } 81427a0bc89SDoug Rabson } 81527a0bc89SDoug Rabson brelse(bp); 81627a0bc89SDoug Rabson } 81727a0bc89SDoug Rabson /* NOTREACHED */ 81827a0bc89SDoug Rabson } 81927a0bc89SDoug Rabson 82027a0bc89SDoug Rabson /* 82127a0bc89SDoug Rabson * Check to see if the directory described by target is in some 82227a0bc89SDoug Rabson * subdirectory of source. This prevents something like the following from 82327a0bc89SDoug Rabson * succeeding and leaving a bunch or files and directories orphaned. mv 82427a0bc89SDoug Rabson * /a/b/c /a/b/c/d/e/f Where c and f are directories. 82527a0bc89SDoug Rabson * 82627a0bc89SDoug Rabson * source - the inode for /a/b/c 82727a0bc89SDoug Rabson * target - the inode for /a/b/c/d/e/f 82827a0bc89SDoug Rabson * 82927a0bc89SDoug Rabson * Returns 0 if target is NOT a subdirectory of source. 83027a0bc89SDoug Rabson * Otherwise returns a non-zero error number. 83127a0bc89SDoug Rabson */ 83227a0bc89SDoug Rabson int 83395d42526SKonstantin Belousov doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn) 83427a0bc89SDoug Rabson { 83527a0bc89SDoug Rabson daddr_t scn; 83627a0bc89SDoug Rabson struct msdosfsmount *pmp; 83727a0bc89SDoug Rabson struct direntry *ep; 83827a0bc89SDoug Rabson struct denode *dep; 83927a0bc89SDoug Rabson struct buf *bp = NULL; 84027a0bc89SDoug Rabson int error = 0; 84127a0bc89SDoug Rabson 84295d42526SKonstantin Belousov *wait_scn = 0; 843952a6212SJordan K. Hubbard 84495d42526SKonstantin Belousov pmp = target->de_pmp; 8456ae13c0fSKonstantin Belousov lockmgr_assert(&pmp->pm_checkpath_lock, KA_XLOCKED); 84695d42526SKonstantin Belousov KASSERT(pmp == source->de_pmp, 84795d42526SKonstantin Belousov ("doscheckpath: source and target on different filesystems")); 84895d42526SKonstantin Belousov 84995d42526SKonstantin Belousov if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 85095d42526SKonstantin Belousov (source->de_Attributes & ATTR_DIRECTORY) == 0) 85195d42526SKonstantin Belousov return (ENOTDIR); 85295d42526SKonstantin Belousov 85395d42526SKonstantin Belousov if (target->de_StartCluster == source->de_StartCluster) 85495d42526SKonstantin Belousov return (EEXIST); 85595d42526SKonstantin Belousov 85695d42526SKonstantin Belousov if (target->de_StartCluster == MSDOSFSROOT || 85795d42526SKonstantin Belousov (FAT32(pmp) && target->de_StartCluster == pmp->pm_rootdirblk)) 85895d42526SKonstantin Belousov return (0); 85995d42526SKonstantin Belousov 86095d42526SKonstantin Belousov dep = target; 86195d42526SKonstantin Belousov vget(DETOV(dep), LK_EXCLUSIVE); 86227a0bc89SDoug Rabson for (;;) { 86327a0bc89SDoug Rabson if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 86427a0bc89SDoug Rabson error = ENOTDIR; 865952a6212SJordan K. Hubbard break; 86627a0bc89SDoug Rabson } 86727a0bc89SDoug Rabson scn = dep->de_StartCluster; 86827a0bc89SDoug Rabson error = bread(pmp->pm_devvp, cntobn(pmp, scn), 86927a0bc89SDoug Rabson pmp->pm_bpcluster, NOCRED, &bp); 87095d42526SKonstantin Belousov if (error != 0) 87127a0bc89SDoug Rabson break; 872952a6212SJordan K. Hubbard 87327a0bc89SDoug Rabson ep = (struct direntry *)bp->b_data + 1; 87427a0bc89SDoug Rabson if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 87527a0bc89SDoug Rabson bcmp(ep->deName, ".. ", 11) != 0) { 87627a0bc89SDoug Rabson error = ENOTDIR; 87795d42526SKonstantin Belousov brelse(bp); 87827a0bc89SDoug Rabson break; 87927a0bc89SDoug Rabson } 88095d42526SKonstantin Belousov 88127a0bc89SDoug Rabson scn = getushort(ep->deStartCluster); 882952a6212SJordan K. Hubbard if (FAT32(pmp)) 883952a6212SJordan K. Hubbard scn |= getushort(ep->deHighClust) << 16; 88495d42526SKonstantin Belousov brelse(bp); 885952a6212SJordan K. Hubbard 88627a0bc89SDoug Rabson if (scn == source->de_StartCluster) { 88727a0bc89SDoug Rabson error = EINVAL; 88827a0bc89SDoug Rabson break; 88927a0bc89SDoug Rabson } 89027a0bc89SDoug Rabson if (scn == MSDOSFSROOT) 89127a0bc89SDoug Rabson break; 892952a6212SJordan K. Hubbard if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 893952a6212SJordan K. Hubbard /* 894952a6212SJordan K. Hubbard * scn should be 0 in this case, 895952a6212SJordan K. Hubbard * but we silently ignore the error. 896952a6212SJordan K. Hubbard */ 897952a6212SJordan K. Hubbard break; 898952a6212SJordan K. Hubbard } 899952a6212SJordan K. Hubbard 90027a0bc89SDoug Rabson vput(DETOV(dep)); 90195d42526SKonstantin Belousov dep = NULL; 902952a6212SJordan K. Hubbard /* NOTE: deget() clears dep on error */ 90395d42526SKonstantin Belousov error = deget(pmp, scn, 0, LK_EXCLUSIVE | LK_NOWAIT, &dep); 90495d42526SKonstantin Belousov if (error != 0) { 90595d42526SKonstantin Belousov *wait_scn = scn; 90627a0bc89SDoug Rabson break; 90727a0bc89SDoug Rabson } 90895d42526SKonstantin Belousov } 90954cf9198SKonstantin Belousov #ifdef MSDOSFS_DEBUG 91027a0bc89SDoug Rabson if (error == ENOTDIR) 91127a0bc89SDoug Rabson printf("doscheckpath(): .. not a directory?\n"); 91254cf9198SKonstantin Belousov #endif 91327a0bc89SDoug Rabson if (dep != NULL) 91427a0bc89SDoug Rabson vput(DETOV(dep)); 915952a6212SJordan K. Hubbard return (error); 91627a0bc89SDoug Rabson } 91727a0bc89SDoug Rabson 91827a0bc89SDoug Rabson /* 91927a0bc89SDoug Rabson * Read in the disk block containing the directory entry (dirclu, dirofs) 92027a0bc89SDoug Rabson * and return the address of the buf header, and the address of the 92127a0bc89SDoug Rabson * directory entry within the block. 92227a0bc89SDoug Rabson */ 92327a0bc89SDoug Rabson int 92410c9700fSEd Maste readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, 92510c9700fSEd Maste struct buf **bpp, struct direntry **epp) 92627a0bc89SDoug Rabson { 92727a0bc89SDoug Rabson int error; 92827a0bc89SDoug Rabson daddr_t bn; 929952a6212SJordan K. Hubbard int blsize; 93027a0bc89SDoug Rabson 931952a6212SJordan K. Hubbard blsize = pmp->pm_bpcluster; 932952a6212SJordan K. Hubbard if (dirclust == MSDOSFSROOT 933952a6212SJordan K. Hubbard && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 934952a6212SJordan K. Hubbard blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 935952a6212SJordan K. Hubbard bn = detobn(pmp, dirclust, diroffset); 936952a6212SJordan K. Hubbard if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { 937952a6212SJordan K. Hubbard brelse(*bpp); 93827a0bc89SDoug Rabson *bpp = NULL; 939952a6212SJordan K. Hubbard return (error); 94027a0bc89SDoug Rabson } 94127a0bc89SDoug Rabson if (epp) 942952a6212SJordan K. Hubbard *epp = bptoep(pmp, *bpp, diroffset); 943952a6212SJordan K. Hubbard return (0); 94427a0bc89SDoug Rabson } 94527a0bc89SDoug Rabson 94627a0bc89SDoug Rabson /* 94727a0bc89SDoug Rabson * Read in the disk block containing the directory entry dep came from and 94827a0bc89SDoug Rabson * return the address of the buf header, and the address of the directory 94927a0bc89SDoug Rabson * entry within the block. 95027a0bc89SDoug Rabson */ 95127a0bc89SDoug Rabson int 95210c9700fSEd Maste readde(struct denode *dep, struct buf **bpp, struct direntry **epp) 95327a0bc89SDoug Rabson { 954952a6212SJordan K. Hubbard 955952a6212SJordan K. Hubbard return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 956952a6212SJordan K. Hubbard bpp, epp)); 957952a6212SJordan K. Hubbard } 958952a6212SJordan K. Hubbard 959952a6212SJordan K. Hubbard /* 960952a6212SJordan K. Hubbard * Remove a directory entry. At this point the file represented by the 961952a6212SJordan K. Hubbard * directory entry to be removed is still full length until no one has it 962952a6212SJordan K. Hubbard * open. When the file no longer being used msdosfs_inactive() is called 963952a6212SJordan K. Hubbard * and will truncate the file to 0 length. When the vnode containing the 964952a6212SJordan K. Hubbard * denode is needed for some other purpose by VFS it will call 965952a6212SJordan K. Hubbard * msdosfs_reclaim() which will remove the denode from the denode cache. 9664882501bSEd Maste * 9674882501bSEd Maste * pdep directory where the entry is removed 9684882501bSEd Maste * dep file to be removed 969952a6212SJordan K. Hubbard */ 970952a6212SJordan K. Hubbard int 97110c9700fSEd Maste removede(struct denode *pdep, struct denode *dep) 972952a6212SJordan K. Hubbard { 973952a6212SJordan K. Hubbard int error; 974952a6212SJordan K. Hubbard struct direntry *ep; 975952a6212SJordan K. Hubbard struct buf *bp; 976952a6212SJordan K. Hubbard daddr_t bn; 977952a6212SJordan K. Hubbard int blsize; 978952a6212SJordan K. Hubbard struct msdosfsmount *pmp = pdep->de_pmp; 979952a6212SJordan K. Hubbard u_long offset = pdep->de_fndoffset; 980952a6212SJordan K. Hubbard 981952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 982952a6212SJordan K. Hubbard printf("removede(): filename %s, dep %p, offset %08lx\n", 983952a6212SJordan K. Hubbard dep->de_Name, dep, offset); 984952a6212SJordan K. Hubbard #endif 985952a6212SJordan K. Hubbard 986952a6212SJordan K. Hubbard dep->de_refcnt--; 987952a6212SJordan K. Hubbard offset += sizeof(struct direntry); 988952a6212SJordan K. Hubbard do { 989952a6212SJordan K. Hubbard offset -= sizeof(struct direntry); 990952a6212SJordan K. Hubbard error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 991952a6212SJordan K. Hubbard if (error) 992952a6212SJordan K. Hubbard return error; 993952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 994952a6212SJordan K. Hubbard if (error) { 995952a6212SJordan K. Hubbard return error; 996952a6212SJordan K. Hubbard } 997952a6212SJordan K. Hubbard ep = bptoep(pmp, bp, offset); 998952a6212SJordan K. Hubbard /* 999952a6212SJordan K. Hubbard * Check whether, if we came here the second time, i.e. 1000952a6212SJordan K. Hubbard * when underflowing into the previous block, the last 1001952a6212SJordan K. Hubbard * entry in this block is a longfilename entry, too. 1002952a6212SJordan K. Hubbard */ 1003952a6212SJordan K. Hubbard if (ep->deAttributes != ATTR_WIN95 1004952a6212SJordan K. Hubbard && offset != pdep->de_fndoffset) { 1005952a6212SJordan K. Hubbard brelse(bp); 1006952a6212SJordan K. Hubbard break; 1007952a6212SJordan K. Hubbard } 1008952a6212SJordan K. Hubbard offset += sizeof(struct direntry); 1009952a6212SJordan K. Hubbard while (1) { 1010952a6212SJordan K. Hubbard /* 1011b3a15dddSPedro F. Giffuni * We are a bit aggressive here in that we delete any Win95 1012952a6212SJordan K. Hubbard * entries preceding this entry, not just the ones we "own". 1013952a6212SJordan K. Hubbard * Since these presumably aren't valid anyway, 1014952a6212SJordan K. Hubbard * there should be no harm. 1015952a6212SJordan K. Hubbard */ 1016952a6212SJordan K. Hubbard offset -= sizeof(struct direntry); 1017952a6212SJordan K. Hubbard ep--->deName[0] = SLOT_DELETED; 1018952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1019952a6212SJordan K. Hubbard || !(offset & pmp->pm_crbomask) 1020952a6212SJordan K. Hubbard || ep->deAttributes != ATTR_WIN95) 1021952a6212SJordan K. Hubbard break; 1022952a6212SJordan K. Hubbard } 10232aacee77SKonstantin Belousov if (DOINGASYNC(DETOV(pdep))) 1024cb65c1eeSBruce Evans bdwrite(bp); 1025cb65c1eeSBruce Evans else if ((error = bwrite(bp)) != 0) 1026952a6212SJordan K. Hubbard return error; 1027952a6212SJordan K. Hubbard } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1028952a6212SJordan K. Hubbard && !(offset & pmp->pm_crbomask) 1029952a6212SJordan K. Hubbard && offset); 1030952a6212SJordan K. Hubbard return 0; 1031952a6212SJordan K. Hubbard } 1032952a6212SJordan K. Hubbard 1033952a6212SJordan K. Hubbard /* 1034952a6212SJordan K. Hubbard * Create a unique DOS name in dvp 1035952a6212SJordan K. Hubbard */ 1036952a6212SJordan K. Hubbard int 103710c9700fSEd Maste uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) 1038952a6212SJordan K. Hubbard { 1039952a6212SJordan K. Hubbard struct msdosfsmount *pmp = dep->de_pmp; 1040952a6212SJordan K. Hubbard struct direntry *dentp; 1041952a6212SJordan K. Hubbard int gen; 1042952a6212SJordan K. Hubbard int blsize; 1043952a6212SJordan K. Hubbard u_long cn; 1044952a6212SJordan K. Hubbard daddr_t bn; 1045952a6212SJordan K. Hubbard struct buf *bp; 1046952a6212SJordan K. Hubbard int error; 1047952a6212SJordan K. Hubbard 1048af9f1d50SDmitrij Tejblum if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 1049011cdb57SDmitrij Tejblum return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1050c4f02a89SMax Khon cnp->cn_namelen, 0, pmp) ? 0 : EINVAL); 1051011cdb57SDmitrij Tejblum 1052952a6212SJordan K. Hubbard for (gen = 1;; gen++) { 1053952a6212SJordan K. Hubbard /* 1054952a6212SJordan K. Hubbard * Generate DOS name with generation number 1055952a6212SJordan K. Hubbard */ 1056952a6212SJordan K. Hubbard if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1057c4f02a89SMax Khon cnp->cn_namelen, gen, pmp)) 1058952a6212SJordan K. Hubbard return gen == 1 ? EINVAL : EEXIST; 1059952a6212SJordan K. Hubbard 1060952a6212SJordan K. Hubbard /* 1061952a6212SJordan K. Hubbard * Now look for a dir entry with this exact name 1062952a6212SJordan K. Hubbard */ 1063952a6212SJordan K. Hubbard for (cn = error = 0; !error; cn++) { 1064952a6212SJordan K. Hubbard if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 1065952a6212SJordan K. Hubbard if (error == E2BIG) /* EOF reached and not found */ 1066952a6212SJordan K. Hubbard return 0; 1067952a6212SJordan K. Hubbard return error; 1068952a6212SJordan K. Hubbard } 1069952a6212SJordan K. Hubbard error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); 1070952a6212SJordan K. Hubbard if (error) { 1071952a6212SJordan K. Hubbard return error; 1072952a6212SJordan K. Hubbard } 1073952a6212SJordan K. Hubbard for (dentp = (struct direntry *)bp->b_data; 1074952a6212SJordan K. Hubbard (char *)dentp < bp->b_data + blsize; 1075952a6212SJordan K. Hubbard dentp++) { 1076952a6212SJordan K. Hubbard if (dentp->deName[0] == SLOT_EMPTY) { 1077952a6212SJordan K. Hubbard /* 1078952a6212SJordan K. Hubbard * Last used entry and not found 1079952a6212SJordan K. Hubbard */ 1080952a6212SJordan K. Hubbard brelse(bp); 1081952a6212SJordan K. Hubbard return 0; 1082952a6212SJordan K. Hubbard } 1083952a6212SJordan K. Hubbard /* 1084952a6212SJordan K. Hubbard * Ignore volume labels and Win95 entries 1085952a6212SJordan K. Hubbard */ 1086952a6212SJordan K. Hubbard if (dentp->deAttributes & ATTR_VOLUME) 1087952a6212SJordan K. Hubbard continue; 1088952a6212SJordan K. Hubbard if (!bcmp(dentp->deName, cp, 11)) { 1089952a6212SJordan K. Hubbard error = EEXIST; 1090952a6212SJordan K. Hubbard break; 1091952a6212SJordan K. Hubbard } 1092952a6212SJordan K. Hubbard } 1093952a6212SJordan K. Hubbard brelse(bp); 1094952a6212SJordan K. Hubbard } 1095952a6212SJordan K. Hubbard } 1096952a6212SJordan K. Hubbard } 1097