1/*
2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* $FreeBSD: src/sys/msdosfs/msdosfs_lookup.c,v 1.31 2000/05/05 09:58:35 phk Exp $ */
24/*	$NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $	*/
25
26/*-
27 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
28 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
29 * All rights reserved.
30 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 *    must display the following acknowledgement:
42 *	This product includes software developed by TooLs GmbH.
43 * 4. The name of TooLs GmbH may not be used to endorse or promote products
44 *    derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57/*
58 * Written by Paul Popelka (paulp@uts.amdahl.com)
59 *
60 * You can do anything you want with this software, just don't say you wrote
61 * it, and don't remove this notice.
62 *
63 * This software is provided "as is".
64 *
65 * The author supplies this software to be publicly redistributed on the
66 * understanding that the author is not responsible for the correct
67 * functioning of this software in any circumstances and is not liable for
68 * any damages caused by this software.
69 *
70 * October 1992
71 */
72
73#include <sys/param.h>
74#include <sys/systm.h>
75#include <sys/buf.h>
76#include <sys/vnode.h>
77#include <sys/mount.h>
78#include <sys/namei.h>
79#include <sys/utfconv.h>
80#include <libkern/OSMalloc.h>
81
82#include "bpb.h"
83#include "direntry.h"
84#include "denode.h"
85#include "msdosfsmount.h"
86#include "fat.h"
87#include "msdosfs_kdebug.h"
88
89#ifndef DEBUG
90#define DEBUG 0
91#endif
92
93int msdosfs_unicode_to_dos_lookup(u_int16_t *unicode, size_t unichars, u_char shortname[SHORT_NAME_LEN]);
94
95/*
96 * Convert a Unicode filename to the equivalent short name.
97 *
98 * Note: This is for use during lookup, not when creating new names.
99 * Therefore, it does not cut out embedded spaces, and does not worry
100 * about mixed case.
101 *
102 * Returns non-zero if the name was successfully converted to a short name.
103 */
104int msdosfs_unicode_to_dos_lookup(u_int16_t *unicode, size_t unichars, u_char shortname[SHORT_NAME_LEN])
105{
106	size_t i;
107	int j;
108	u_char c = ' ';
109
110	if (unichars > SHORT_NAME_LEN+1)
111		return 0;
112
113	/* Fill the short name with spaces, the short name pad character */
114	memset(shortname, ' ', SHORT_NAME_LEN);
115
116	/* Process the base name, up to the first period */
117	for (i=0; i<unichars && i<8; ++i)
118	{
119		if (unicode[i] == '.')	/* Dot => start extension */
120			break;
121
122		if (unicode[i] == ' ')
123			c = ' ';
124		else
125			c = msdosfs_unicode2dos(unicode[i]);
126
127		if (c < ' ')
128			return 0;
129		shortname[i] = c;
130	}
131
132	/*
133	 * Fail if last char of base is a space (since msdosfs_dos2unicodefn would trim it),
134	 * or if the base name is empty (the loop above never executed).
135	 */
136	if (c == ' ')
137		return 0;
138
139	/* Short names cannot start with a space. */
140	if (shortname[0] == ' ')
141		return 0;
142
143	/* Is the name a base only, no extension? */
144	if (i == unichars)
145		return 1;
146
147	/* Skip over the dot between base and extension */
148	if (unicode[i] == '.')
149		++i;
150	else
151		return 0;			/* Base name too long */
152
153	/* Process the extension */
154	for (j=8; j < 11 && i < unichars; ++i, ++j)
155	{
156		if (unicode[i] == '.')	/* No dots in the extension */
157			return 0;
158
159		if (unicode[i] == ' ')
160			c = ' ';
161		else
162			c = msdosfs_unicode2dos(unicode[i]);
163
164		if (c < ' ')
165			return 0;
166		shortname[j] = c;
167	}
168
169	/* Was the extension too long? */
170	if (i < unichars)
171		return 0;
172
173	/* Was the extension empty? */
174	if (j == 8)
175		return 0;
176
177	/* Fail if last char of extension is a space (since msdosfs_dos2unicodefn would trim it) */
178	if (c == ' ')
179		return 0;
180
181	/* Do we need to bother with names starting with 0xE5? */
182	if (shortname[0] == 0xE5)
183		shortname[0] = SLOT_E5;
184
185	return 1;
186}
187
188
189/*
190 * msdosfs_lookup_name
191 *
192 * Search a directory for an entry with a given name.  If found, returns
193 * the cluster containing the name's short name directory entry, and the
194 * byte offset from the start of the directory (not the cluster!).
195 *
196 * Assumes dep's de_lock has been acquired.
197 */
198int msdosfs_lookup_name(
199	struct denode *dep,					/* parent directory */
200	struct componentname *cnp,			/* the name to look up */
201	uint32_t *dirclust,					/* cluster containing short name entry */
202	uint32_t *diroffset,				/* byte offset from start of directory */
203	struct dosdirentry *direntry,		/* copy of found directory entry */
204	u_int16_t *found_name,
205	u_int16_t *found_name_length,
206	boolean_t *case_folded,
207	vfs_context_t context)
208{
209    int error;
210    int chksum;			/* checksum of short name entry */
211    struct dosdirentry *dirp;
212    buf_t bp;
213    daddr64_t bn;
214    int frcn;			/* file relative cluster (within parent directory) */
215    uint32_t cluster=0;		/* physical cluster containing directory entry */
216    unsigned blkoff;			/* offset within directory block */
217    unsigned diroff=0;			/* offset from start of directory */
218    uint32_t blsize;		/* size of one directory block */
219    u_int16_t ucfn[WIN_MAXLEN];
220    u_char shortname[SHORT_NAME_LEN];
221    size_t unichars;	/* number of UTF-16 characters in original name */
222    int try_short_name;	/* If true, compare short names */
223    boolean_t did_case_fold = FALSE;
224
225    KERNEL_DEBUG_CONSTANT(MSDOSFS_LOOKUP_NAME|DBG_FUNC_START, dep->de_pmp, dep, 0, 0, 0);
226
227    dirp = NULL;
228    chksum = -1;
229
230    /*
231     * Decode lookup name into UCS-2 (Unicode)
232     */
233    error = utf8_decodestr((uint8_t *)cnp->cn_nameptr, cnp->cn_namelen, ucfn, &unichars, sizeof(ucfn), 0, UTF_PRECOMPOSED|UTF_SFM_CONVERSIONS);
234    if (error) 	goto exit;
235    unichars /= 2; /* bytes to chars */
236    if (found_name_length)
237		*found_name_length = unichars;
238
239    /*
240     * Try to convert the name to a short name.  Unlike the case of creating
241     * a new name in the directory, allow embedded spaces and mixed case,
242     * but do not mangle the short name.  Keep track of whether there is
243     * a valid short name to look up.
244     */
245    try_short_name = msdosfs_unicode_to_dos_lookup(ucfn, unichars, shortname);
246
247    /*
248     * Search the directory pointed at by dep for the name in ucfn.
249     */
250
251    /*
252     * The outer loop ranges over the clusters that make up the
253     * directory.  Note that the root directory is different from all
254     * other directories.  It has a fixed number of blocks that are not
255     * part of the pool of allocatable clusters.  So, we treat it a
256     * little differently. The root directory starts at "cluster" 0.
257     */
258    diroff = 0;
259    for (frcn = 0; error == 0; frcn++) {
260		error = msdosfs_pcbmap(dep, frcn, 1, &bn, &cluster, &blsize);
261		if (error) {
262			if (error == E2BIG)
263				error = ENOENT;
264			break;
265		}
266		error = (int)buf_meta_bread(dep->de_pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
267		if (error) {
268			buf_brelse(bp);
269			break;
270		}
271		for (blkoff = 0; blkoff < blsize;
272			 blkoff += sizeof(struct dosdirentry),
273			 diroff += sizeof(struct dosdirentry))
274		{
275			dirp = (struct dosdirentry *)((char *)buf_dataptr(bp) + blkoff);
276
277			/*
278			 * Skip over deleted entries.
279			 */
280			if (dirp->deName[0] == SLOT_DELETED)
281			{
282				chksum = -1;	/* Forget previous matching long name entries. */
283				continue;
284			}
285
286			/*
287			 * If we found an entry that has never been used, then
288			 * there is no need to search further.
289			 */
290			if (dirp->deName[0] == SLOT_EMPTY)
291			{
292				error = ENOENT;
293				break;
294			}
295
296			/*
297			 * Check for Win95 long filename entry
298			 */
299			if (dirp->deAttributes == ATTR_WIN95) {
300				chksum = msdosfs_winChkName(ucfn, (int)unichars,
301											(struct winentry *)dirp,
302											chksum,
303											found_name, &did_case_fold);
304				continue;
305			}
306
307			/*
308			 * Ignore volume labels (anywhere, not just
309			 * the root directory).
310			 */
311			if (dirp->deAttributes & ATTR_VOLUME) {
312				chksum = -1;
313				continue;
314			}
315
316			/*
317			 * If we get here, we've found a short name entry.
318			 *
319			 * If there was a long name, and it matched, then verify the
320			 * checksum.  If the checksum doesn't match, then compare the
321			 * short name.
322			 */
323			if (chksum != msdosfs_winChksum(dirp->deName) &&
324				(!try_short_name || bcmp(shortname, dirp->deName, SHORT_NAME_LEN)))
325			{
326				/* No match.  Forget long name checksum, if any. */
327				chksum = -1;
328				continue;
329			}
330
331			/* If we get here, we found a matching name. */
332
333			/*
334			 * If we need to return the actual on-disk name, and there was no valid
335			 * long name, then convert the short name to Unicode.
336			 */
337			if (found_name && found_name_length && chksum == -1)
338			{
339				*found_name_length = msdosfs_dos2unicodefn(dirp->deName, found_name, dirp->deLowerCase);
340			}
341
342			/* Return the location and contents of the short name entry. */
343			if (dirclust)
344				*dirclust = cluster;
345			if (diroffset)
346				*diroffset = diroff;
347			if (direntry)
348				*direntry = *dirp;
349			error = 0;
350			buf_brelse(bp);
351			goto exit;
352		}	/* for (blkoff = 0; .... */
353
354		/*
355		 * Release the buffer holding the directory cluster just
356		 * searched.
357		 */
358		buf_brelse(bp);
359    }	/* for (frcn = 0; error == 0; frcn++) */
360
361exit:
362	if (case_folded)
363		*case_folded = did_case_fold;
364    KERNEL_DEBUG_CONSTANT(MSDOSFS_LOOKUP_NAME|DBG_FUNC_END, error, cluster, diroff, 0, 0);
365    return error;
366}
367
368/*
369 * Try to find the file/directory in the name cache.  If not
370 * found there, then look in the directory on disk.
371 *
372 * When we search a directory the blocks containing directory entries are
373 * read and examined.  The directory entries contain information that would
374 * normally be in the inode of a unix filesystem.  This means that some of
375 * a directory's contents may also be in memory resident denodes (sort of
376 * an inode).  This can cause problems if we are searching while some other
377 * process is modifying a directory.  To prevent one process from accessing
378 * incompletely modified directory information we depend upon being the
379 * sole owner of a directory block.  buf_bread/buf_brelse provide this service.
380 * This being the case, when a process modifies a directory it must first
381 * acquire the disk block that contains the directory entry to be modified.
382 * Then update the disk block and the denode, and then write the disk block
383 * out to disk.  This way disk blocks containing directory entries and in
384 * memory denode's will be in synch.
385 */
386
387int msdosfs_vnop_lookup(struct vnop_lookup_args *ap)
388/* {
389		vnode_t a_dvp;
390		vnode_t *a_vpp;
391		struct componentname *a_cnp;
392		vfs_context_t a_context;
393	} */
394{
395	vnode_t dvp = ap->a_dvp;
396	vnode_t *vpp = ap->a_vpp;
397	struct componentname *cnp = ap->a_cnp;
398	vfs_context_t context = ap->a_context;
399	int flags = cnp->cn_flags;
400	int nameiop = cnp->cn_nameiop;
401	int error;
402	struct msdosfsmount *pmp;
403	struct denode *pdp;	/* denode of dvp */
404	struct denode *dp;	/* denode of found item */
405	uint32_t cluster;		/* physical cluster containing directory entry */
406	uint32_t diroff;		/* offset from start of directory */
407	uint32_t scn;			/* starting cluster number of found item */
408	int isadir;			/* non-zero if found dosdirentry is a directory */
409	struct dosdirentry direntry;
410	u_int16_t found_name[WIN_MAXLEN];  /* TODO: Should we malloc this? */
411	u_int16_t found_name_len;
412	size_t utf8_len;
413	boolean_t case_folded;
414
415	/*
416	 * TODO: What should we log here?  pmp, pdp, flags, nameiop?
417	 */
418    KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_START, VTODE(dvp), flags, nameiop, 0, 0);
419
420	*vpp = NULL;	/* In case we return an error */
421
422	error = cache_lookup(dvp, vpp, cnp);
423
424	if (error)
425	{
426		/* We found a cache entry, positive or negative. */
427		if (error == -1)	/* Positive entry? */
428			error = 0;		/* Yes.  Caller expects no error */
429
430		/* TODO: Should log that we found something via cache_lookup. */
431		KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_END, error, 0, 0, 0, 0);
432		return error;
433	}
434
435	/* If we get here, we need to look for the item on disk. */
436
437	pdp = VTODE(dvp);
438	lck_mtx_lock(pdp->de_lock);
439	pmp = pdp->de_pmp;
440
441	/*
442	 * If they are going after the . or .. entry in the root directory,
443	 * they won't find it.  DOS filesystems don't have them in the root
444	 * directory.  So, we fake it. msdosfs_deget() is in on this scam too.
445	 */
446	if ((pdp->de_flag & DE_ROOT) && cnp->cn_nameptr[0] == '.' &&
447	    (cnp->cn_namelen == 1 ||
448		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.')))
449	{
450		isadir = ATTR_DIRECTORY;
451		scn = MSDOSFSROOT;
452		cluster = MSDOSFSROOT;
453		diroff = MSDOSFSROOT_OFS;
454		goto foundroot;
455	}
456
457	/*
458	 * If they're looking for ".", then just take another reference on dvp.
459	 */
460	if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
461	{
462		vnode_get(dvp);
463		*vpp = dvp;
464		goto exit;	/* error must be 0 if we got here */
465	}
466
467	/*
468	 * If they're looking for "..", then just take another reference on dvp's
469	 * parent vnode.
470	 */
471	if (flags & ISDOTDOT)
472	{
473		vnode_t vp;
474
475		dp = pdp->de_parent;
476		if (dp == NULL)
477			panic("msdosfs_vnop_lookup: de_parent == NULL when looking for ..\n");
478		vp = DETOV(dp);
479		if (vp == NULLVP)
480			panic("msdosfs_vnop_lookup: vp == NULL when looking for ..\n");
481		vnode_get(vp);
482		*vpp = vp;
483		goto exit;	/* error must be 0 if we got here */
484	}
485
486	error = msdosfs_lookup_name(pdp, cnp, &cluster, &diroff, &direntry, found_name, &found_name_len, &case_folded, context);
487
488	if (error == ENOENT)
489	{
490		/*
491		 * If we get here we didn't find the entry we were looking for. But
492		 * that's ok if we are creating or renaming and are at the end of
493		 * the pathname and the directory hasn't been removed.
494		 */
495		if ((nameiop == CREATE || nameiop == RENAME) &&
496			(flags & ISLASTCN) && pdp->de_refcnt != 0)
497		{
498			error = EJUSTRETURN;
499			goto exit;
500		}
501
502		/*
503		 * Insert name into cache (as non-existent) if appropriate.
504		 */
505		if ((flags & MAKEENTRY) && nameiop != CREATE)
506			cache_enter(dvp, *vpp, cnp);
507
508		goto exit;
509	}
510
511	/*
512	 * If we got any other error from msdosfs_lookup_name, return it now.
513	 */
514	if (error)
515		goto exit;
516
517	/*
518	 * If we get here, we've found the directory entry.
519	 */
520	isadir = direntry.deAttributes & ATTR_DIRECTORY;
521	scn = getuint16(direntry.deStartCluster);
522	if (FAT32(pmp)) {
523		scn |= getuint16(direntry.deHighClust) << 16;
524		if (scn == pmp->pm_rootdirblk) {
525			/*
526			 * There should actually be 0 here.
527			 * Just ignore the error.
528			 */
529			scn = MSDOSFSROOT;
530		}
531	}
532
533foundroot:
534	/*
535	 * If we entered at foundroot, then we are looking for the . or ..
536	 * entry of the filesystems root directory.  isadir and scn were
537	 * setup before jumping here.
538	 */
539	if (FAT32(pmp) && scn == MSDOSFSROOT)
540		scn = pmp->pm_rootdirblk;
541
542	if (nameiop == DELETE && (flags & ISLASTCN)) {
543		/*
544		 * Don't allow deleting the root.
545		 */
546		if (diroff == MSDOSFSROOT_OFS)
547		{
548			error = EROFS;				/* correct error? */
549			goto exit;
550		}
551	}
552
553	if (nameiop == RENAME && (flags & ISLASTCN)) {
554		if (diroff == MSDOSFSROOT_OFS)
555		{
556			error = EROFS;				/* really? XXX */
557			goto exit;
558		}
559
560		if (pdp->de_StartCluster == scn && isadir)
561		{
562			error = EISDIR;
563			goto exit;
564		}
565	}
566
567	/*
568	 * Return a vnode for the found directory entry.
569	 *
570	 * We construct a temporary componentname to hold the actual
571	 * on-disk name so that the on-disk name (with correct case)
572	 * gets inserted into the name cache.
573	 */
574	struct componentname found_cnp;
575	if (case_folded)
576	{
577		found_cnp = *cnp;
578		found_cnp.cn_pnlen = 1024;
579		found_cnp.cn_pnbuf = found_cnp.cn_nameptr = OSMalloc(found_cnp.cn_pnlen, msdosfs_malloc_tag);
580		if (found_cnp.cn_nameptr == NULL)
581		{
582			error = ENOMEM;
583			goto exit;
584		}
585		error = utf8_encodestr(found_name, found_name_len * 2, (u_int8_t *)found_cnp.cn_nameptr, &utf8_len, found_cnp.cn_pnlen, 0, UTF_DECOMPOSED|UTF_SFM_CONVERSIONS);
586		if (error == 0)
587		{
588			found_cnp.cn_namelen = (int)utf8_len;
589		}
590	}
591	if (error == 0)
592	{
593		error = msdosfs_deget(pmp, cluster, diroff, dvp, case_folded ? &found_cnp : cnp, &dp, context);
594	}
595	if (case_folded)
596	{
597		OSFree(found_cnp.cn_nameptr, 1024, msdosfs_malloc_tag);
598	}
599	if (error == 0)
600		*vpp = DETOV(dp);
601
602exit:
603	lck_mtx_unlock(pdp->de_lock);
604	KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_END, error, 0, 0, 0, 0);
605	return error;
606}
607
608
609/*
610 * dep  - directory entry to copy into the directory
611 * ddep - directory to add to
612 * depp - return the address of the denode for the created directory entry
613 *	  if depp != 0
614 * cnp  - componentname needed for Win95 long filenames
615 * offset - directory offset for short name entry
616 * long_count - number of long name entries needed
617 */
618int msdosfs_createde(
619	struct denode *dep,
620	struct denode *ddep,
621	struct denode **depp,
622	struct componentname *cnp,
623	uint32_t offset,		/* also offset of current entry being written */
624	uint32_t long_count,	/* also count of entries remaining to write */
625	vfs_context_t context)
626{
627	int error;
628	uint32_t dirclust, diroffset;
629	struct dosdirentry *ndep;
630	struct msdosfsmount *pmp = ddep->de_pmp;
631	struct buf *bp;
632	daddr64_t bn;
633	uint32_t blsize;
634
635    KERNEL_DEBUG_CONSTANT(MSDOSFS_CREATEDE|DBG_FUNC_START, ddep, offset, long_count, 0, 0);
636
637	/*
638	 * If no space left in the directory then allocate another cluster
639	 * and chain it onto the end of the file.  There is one exception
640	 * to this.  That is, if the root directory has no more space it
641	 * can NOT be expanded.  msdosfs_extendfile() checks for and fails attempts
642	 * to extend the root directory.  We just return an error in that
643	 * case.
644	 */
645    if (offset >= ddep->de_FileSize) {
646        diroffset = offset + sizeof(struct dosdirentry)
647        		- ddep->de_FileSize;
648        dirclust = de_clcount(pmp, diroffset);
649        error = msdosfs_extendfile(ddep, dirclust, NULL);
650        if (error) {
651            (void)msdosfs_detrunc(ddep, ddep->de_FileSize, 0, context);
652            goto done;
653        }
654
655        /*
656         * Update the size of the directory
657         */
658        ddep->de_FileSize += de_cn2off(pmp, dirclust);
659    }
660
661	/*
662	 * We just read in the cluster with space.  Copy the new directory
663	 * entry in.  Then write it to disk. NOTE:  DOS directories
664	 * do not get smaller as clusters are emptied.
665	 */
666	error = msdosfs_pcbmap(ddep, de_cluster(pmp, offset), 1,
667		       &bn, &dirclust, &blsize);
668	if (error)
669		goto done;
670	diroffset = offset;
671	if ((error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp)) != 0) {
672		buf_brelse(bp);
673		goto done;
674	}
675	ndep = bptoep(pmp, bp, offset);
676
677	if (DEBUG)
678	{
679		/* Make sure the slot is not in use */
680		if (ndep->deName[0] != 0 && ndep->deName[0] != 0xE5)
681			panic("msdosfs_createde: short name slot in use!");
682
683		/* If it's a directory, make sure it's start cluster is non-zero */
684		if ((ndep->deAttributes & ATTR_DIRECTORY) &&
685			*(uint16_t *)(ndep->deStartCluster) == 0 &&
686			*(uint16_t *)(ndep->deHighClust) == 0)
687		{
688			panic("msdosfs_createde: directory with start cluster == 0");
689		}
690	}
691
692	/* NOTE: DE_EXTERNALIZE does not set the name or lower case flags */
693	bcopy(dep->de_Name, ndep->deName, 11);
694	ndep->deLowerCase = dep->de_LowerCase;
695	DE_EXTERNALIZE(ndep, dep);
696
697	/*
698	 * Now write the Win95 long name
699	 */
700	if (long_count > 0) {
701		u_int8_t chksum = msdosfs_winChksum(ndep->deName);
702		u_int16_t ucfn[WIN_MAXLEN];
703		size_t unichars;
704		int cnt = 1;
705
706		/*
707		 * Decode component name into Unicode
708		 * NOTE: We should be using a "precompose" flag
709		 */
710		(void) utf8_decodestr((u_int8_t*)cnp->cn_nameptr, cnp->cn_namelen, ucfn,
711					&unichars, sizeof(ucfn), 0,
712					UTF_PRECOMPOSED|UTF_SFM_CONVERSIONS);
713		unichars /= 2; /* bytes to chars */
714
715		while (long_count-- > 0) {
716			if (!(offset & pmp->pm_crbomask)) {
717				error = (int)buf_bdwrite(bp);
718				if (error)
719					goto done;
720
721				offset -= sizeof(struct dosdirentry);
722				error = msdosfs_pcbmap(ddep,
723							de_cluster(pmp, offset), 1,
724							&bn, 0, &blsize);
725				if (error)
726					goto done;
727
728				error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize,
729					      vfs_context_ucred(context), &bp);
730				if (error) {
731					buf_brelse(bp);
732					goto done;
733				}
734				ndep = bptoep(pmp, bp, offset);
735			} else {
736				ndep--;
737				offset -= sizeof(struct dosdirentry);
738			}
739
740			if (DEBUG)
741			{
742				/* Make sure the slot is not in use */
743				if (ndep->deName[0] != 0 && ndep->deName[0] != 0xE5)
744					panic("msdosfs_createde: long name slot in use!\n");
745			}
746
747			if (!msdosfs_unicode2winfn(ucfn, (int)unichars, (struct winentry *)ndep, cnt++, chksum))
748				break;
749		}
750	}
751
752	error = (int)buf_bdwrite(bp);
753	if (error)
754		goto done;
755
756    ddep->de_flag |= DE_UPDATE;
757
758	/*
759	 * If they want us to return with the denode gotten.
760	 */
761	if (depp)
762		error = msdosfs_deget(pmp, dirclust, diroffset, DETOV(ddep), cnp, depp, context);
763
764done:
765    KERNEL_DEBUG_CONSTANT(MSDOSFS_CREATEDE|DBG_FUNC_END, error, depp ? (uintptr_t)*depp : 0, 0, 0, 0);
766
767	return error;
768}
769
770/*
771 * Be sure a directory is empty except for "." and "..". Return 1 if empty,
772 * return 0 if not empty or error.
773 */
774int msdosfs_dosdirempty(struct denode *dep, vfs_context_t context)
775{
776	uint32_t blsize;
777	int error;
778	uint32_t cn;
779	daddr64_t bn;
780	struct buf *bp;
781	struct msdosfsmount *pmp = dep->de_pmp;
782	struct dosdirentry *dentp;
783	char *bdata;
784
785	/*
786	 * Since the filesize field in directory entries for a directory is
787	 * zero, we just have to feel our way through the directory until
788	 * we hit end of file.
789	 */
790	for (cn = 0;; cn++) {
791		if ((error = msdosfs_pcbmap(dep, cn, 1, &bn, NULL, &blsize)) != 0) {
792			if (error == E2BIG)
793				return (1);	/* it's empty */
794			return (0);
795		}
796		error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
797		if (error) {
798			buf_brelse(bp);
799			return (0);
800		}
801		bdata = (char *)buf_dataptr(bp);
802
803		for (dentp = (struct dosdirentry *)bdata;
804		     (char *)dentp < bdata + blsize;
805		     dentp++)
806		{
807			if (dentp->deName[0] != SLOT_DELETED &&
808			    (dentp->deAttributes & ATTR_VOLUME) == 0) {
809				/*
810				 * In dos directories an entry whose name
811				 * starts with SLOT_EMPTY (0) starts the
812				 * beginning of the unused part of the
813				 * directory, so we can just return that it
814				 * is empty.
815				 */
816				if (dentp->deName[0] == SLOT_EMPTY) {
817					buf_brelse(bp);
818					return 1;
819				}
820				/*
821				 * Any names other than "." and ".." in a
822				 * directory mean it is not empty.
823				 */
824				if (bcmp(dentp->deName, ".          ", SHORT_NAME_LEN) &&
825				    bcmp(dentp->deName, "..         ", SHORT_NAME_LEN)) {
826					buf_brelse(bp);
827					return (0);	/* not empty */
828				}
829			}
830		}
831		buf_brelse(bp);
832	}
833
834	return 1;
835}
836
837/*
838 * Check to see if the directory described by target is in some
839 * subdirectory of source.  This prevents something like the following from
840 * succeeding and leaving a bunch or files and directories orphaned:
841 *   mv /a/b/c /a/b/c/d/e/f
842 * where c and f are directories.
843 *
844 * source - the inode for /a/b/c (the directory being moved)
845 * target - the inode for /a/b/c/d/e/f (the destination parent directory)
846 *
847 * Returns 0 if target is NOT a subdirectory of source.
848 * Otherwise returns a non-zero error number.
849 *
850 * This routine works by following the chain of ".." entries starting at
851 * target until we reach source, or the root of the volume.  It reads the
852 * directory entries directly, not via directory denodes.  It assumes that
853 * the caller has prevented the hierarchy from changing.  This routine takes
854 * no locks.
855 */
856int msdosfs_doscheckpath(struct denode *source, struct denode *target, vfs_context_t context)
857{
858	daddr64_t scn, source_scn;
859	struct msdosfsmount *pmp;
860	struct dosdirentry *ep;
861	struct buf *bp = NULL;
862	int error = 0;
863	int isFAT32;
864	char *bdata;
865
866	pmp = target->de_pmp;
867	isFAT32 = FAT32(pmp);
868	scn = target->de_StartCluster;
869	if (scn == pmp->pm_rootdirblk)
870		scn = 0;
871	source_scn = source->de_StartCluster;
872	/* Assumes the caller has prevented the source from being the root */
873
874	/* scn == 0 means the root directory */
875	while (scn != 0)
876	{
877		if (scn == source_scn)
878			return EINVAL;
879
880		/* Read the first cluster of the current directory */
881		error = (int)buf_meta_bread(pmp->pm_devvp, cntobn(pmp, scn),
882			pmp->pm_bpcluster, vfs_context_ucred(context), &bp);
883		if (error) break;
884		bdata = (char *)buf_dataptr(bp);
885
886		/* Point to the second entry, which should be the ".." entry */
887		ep = (struct dosdirentry *) bdata + 1;
888		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
889		    bcmp(ep->deName, "..         ", SHORT_NAME_LEN) != 0)
890		{
891			error = ENOTDIR;
892			break;
893		}
894
895		/* Get the cluster number from the ".." entry */
896		scn = getuint16(ep->deStartCluster);
897		if (isFAT32)
898			scn |= getuint16(ep->deHighClust) << 16;
899
900		/*
901		 * When ".." points to the root, the cluster number should be 0.
902		 * On FAT32, it's conceivable that an implementation might incorrectly
903		 * have set the cluster number to the first cluster of the root.
904		 * If so, we need to exit.  For FAT12 and FAT16, pm_rootdirblk will be
905		 * 0, in which case this is just a slightly early exit of the loop
906		 * (the while condition would be false the next time through).
907		 */
908		if (scn == pmp->pm_rootdirblk)
909			break;
910
911		/* Release the block we read above */
912		buf_brelse(bp);
913		bp = NULL;
914	}
915
916	if (bp)
917		buf_brelse(bp);
918	if (error == ENOTDIR)
919		printf("msdosfs_doscheckpath(): .. not a directory?\n");
920	return (error);
921}
922
923/*
924 * Read in the disk block containing the directory entry (dirclu, dirofs)
925 * and return the address of the buf header, and the address of the
926 * directory entry within the block.
927 */
928int msdosfs_readep(struct msdosfsmount *pmp,
929	uint32_t dirclust, uint32_t diroffset,
930	struct buf **bpp, struct dosdirentry **epp, vfs_context_t context)
931{
932	int error;
933	daddr64_t bn;
934	int blsize;
935
936	/*
937	 * Handle the special case of the root directory.  If there is a volume
938	 * label entry, then get that.  Otherwise, return an error.
939	 */
940	if ((dirclust == MSDOSFSROOT
941	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
942	    && diroffset == MSDOSFSROOT_OFS)
943	{
944		if (pmp->pm_label_cluster == CLUST_EOFE)
945			return EIO;
946		else
947		{
948			dirclust = pmp->pm_label_cluster;
949			diroffset = pmp->pm_label_offset;
950		}
951	}
952
953	/*
954	 * Sanity check the diroffset.  It should be a multiple of the directory
955	 * entry size (i.e. a multiple of 32).
956	 */
957	if (diroffset % sizeof(struct dosdirentry))
958	{
959		printf("msdosfs: msdosfs_readep: invalid diroffset (%u)\n", diroffset);
960		return EIO;
961	}
962
963	/* Figure out which block contains the directory entry. */
964	blsize = pmp->pm_bpcluster;
965	if (dirclust == MSDOSFSROOT
966	    && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
967	{
968		blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
969	}
970	bn = detobn(pmp, dirclust, diroffset);
971
972	/*
973	 * We occasionally get panic reports that appear to be caused because
974	 * blsize == 0.  I haven't figured out what can cause that, so try
975	 * logging some information that might help, and return an error.
976	 */
977	if (blsize == 0)
978	{
979		printf("msdosfs: msdosfs_readep: blsize==0; pm_fatmask=0x%x, pm_bpcluster=0x%x, "
980			"pm_BlockSize=0x%x, pm_PhysBlockSize=0x%x, pm_BlocksPerSec=0x%x, "
981			"pm_cnshift=0x%x, pm_bnshift=0x%x, pm_crbomask=0x%x, "
982			"pm_rootdirblk=0x%x, pm_rootdirsize=0x%x, "
983			"pm_label_cluster=0x%x, pm_label_offset=0x%x, "
984			"dirclust=0x%x, diroffset=0x%x, bn=0x%llx\n",
985			pmp->pm_fatmask, pmp->pm_bpcluster,
986			pmp->pm_BlockSize, pmp->pm_PhysBlockSize, pmp->pm_BlocksPerSec,
987			pmp->pm_cnshift, pmp->pm_bnshift, pmp->pm_crbomask,
988			pmp->pm_rootdirblk, pmp->pm_rootdirsize,
989			pmp->pm_label_cluster, pmp->pm_label_offset,
990			dirclust, diroffset, bn);
991		return EIO;
992	}
993
994	/* Read the block containing the directory entry, then return the requested entry. */
995	if ((error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), bpp)) != 0)
996	{
997		buf_brelse(*bpp);
998		*bpp = NULL;
999		return (error);
1000	}
1001	if (epp)
1002		*epp = bptoep(pmp, *bpp, diroffset);
1003	return (0);
1004}
1005
1006
1007/*
1008 * Remove a directory entry. At this point the file represented by the
1009 * directory entry to be removed is still full length until noone has it
1010 * open.  When the file no longer being used msdosfs_vnop_inactive() is called
1011 * and will truncate the file to 0 length.  When the vnode containing the
1012 * denode is needed for some other purpose by VFS it will call
1013 * msdosfs_vnop_reclaim() which will remove the denode from the denode cache.
1014 */
1015int msdosfs_removede(struct denode *pdep, uint32_t offset, vfs_context_t context)
1016{
1017    int error;
1018    struct dosdirentry *ep;
1019    struct buf *bp;
1020    daddr64_t bn;
1021    uint32_t blsize;
1022    struct msdosfsmount *pmp = pdep->de_pmp;
1023	uint32_t cur_offset;
1024
1025	cur_offset = offset;
1026    cur_offset += sizeof(struct dosdirentry);
1027    do {
1028        cur_offset -= sizeof(struct dosdirentry);
1029        error = msdosfs_pcbmap(pdep, de_cluster(pmp, cur_offset), 1, &bn, NULL, &blsize);
1030        if (error)
1031            return error;
1032        error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
1033        if (error) {
1034            buf_brelse(bp);
1035            return error;
1036        }
1037        ep = bptoep(pmp, bp, cur_offset);
1038
1039        /*
1040         * Stop deleting long name entries when we find some other short
1041         * name entry.
1042         */
1043        if (ep->deAttributes != ATTR_WIN95
1044            && cur_offset != offset) {
1045            buf_brelse(bp);
1046            break;
1047        }
1048        cur_offset += sizeof(struct dosdirentry);
1049        while (1) {
1050            /*
1051             * We are a bit agressive here in that we delete any Win95
1052             * entries preceding this entry, not just the ones we "own".
1053             * Since these presumably aren't valid anyway,
1054             * there should be no harm.
1055             */
1056            cur_offset -= sizeof(struct dosdirentry);
1057            ep--->deName[0] = SLOT_DELETED;
1058            if ((cur_offset & pmp->pm_crbomask) == 0
1059                || ep->deAttributes != ATTR_WIN95)
1060                break;
1061        }
1062		error = (int)buf_bdwrite(bp);
1063        if (error)
1064            return error;
1065    } while ((cur_offset & pmp->pm_crbomask) == 0
1066             && cur_offset);
1067    pdep->de_flag |= DE_UPDATE;
1068
1069    return error;
1070}
1071
1072/*
1073 * Scan the directory given by "dep" and determine whether it contains a DOS
1074 * (8.3-style) short name equal to "short_name".  If not, then return 0.
1075 * If the short name already exists in the directory, return EEXIST.  If
1076 * there is any other error reading the directory, return that error.
1077 */
1078int msdosfs_scan_dir_for_short_name(
1079	struct denode *dep,
1080	u_char short_name[SHORT_NAME_LEN],
1081	vfs_context_t context)
1082{
1083	daddr64_t bn;
1084	struct dosdirentry *dentp;
1085	struct buf *bp = NULL;
1086	char *bdata;
1087	uint32_t blsize;
1088	uint32_t cn;
1089	int error;
1090
1091	for (cn = error = 0; !error; cn++) {
1092		if ((error = msdosfs_pcbmap(dep, cn, 1, &bn, NULL, &blsize)) != 0) {
1093			if (error == E2BIG)	/* EOF reached and not found */
1094				error = 0;
1095			break;
1096		}
1097		error = (int)buf_meta_bread(dep->de_pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
1098		if (error) {
1099			break;
1100		}
1101		bdata = (char *)buf_dataptr(bp);
1102
1103		for (dentp = (struct dosdirentry *)bdata; (char *)dentp < bdata + blsize; dentp++) {
1104			if (dentp->deName[0] == SLOT_EMPTY) {
1105				/*
1106				 * Last used entry and not found.  Note: error == 0 here.
1107				 */
1108				break;
1109			}
1110			/*
1111			 * Ignore volume labels and Win95 entries
1112			 */
1113			if (dentp->deAttributes & ATTR_VOLUME)
1114				continue;
1115			if (!bcmp(dentp->deName, short_name, SHORT_NAME_LEN)) {
1116				error = EEXIST;
1117				break;
1118			}
1119		}
1120		buf_brelse(bp);
1121		bp = NULL;
1122	}
1123	if (bp)
1124		buf_brelse(bp);
1125
1126	return error;
1127}
1128
1129/*
1130 * Determine a DOS (8.3-style) short name that is unique within the directory given
1131 * by "dep".  The short_name parameter is both input and output; on input, it is
1132 * the short name derived from the Unicode name (as produced by msdosfs_unicode_to_dos_name);
1133 * on output, it is the unique short name (which may contain a generation number).
1134 * The dir_offset parameter is the offset (in bytes, a multiple of 32) from the start
1135 * of the directory to the first long name entry (used as a hint to derive a
1136 * likely unique generation number), or 1 if no generation number should be used.
1137 */
1138int msdosfs_uniqdosname(struct denode *dep,
1139                        u_char short_name[SHORT_NAME_LEN],
1140                        uint32_t dir_offset,
1141                        vfs_context_t context)
1142{
1143	int generation;
1144	int error;
1145	enum { SIMPLE_GENERATION_LIMIT = 6 };
1146
1147    KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME|DBG_FUNC_START, dep->de_pmp, dep, 0, 0, 0);
1148
1149    if (dir_offset == 1)
1150    {
1151        /*
1152         * dir_offset == 1 means the short name is case-insensitively equal to
1153         * the long name, so don't use a generation number.
1154         */
1155        error = msdosfs_scan_dir_for_short_name(dep, short_name, context);
1156    }
1157    else
1158	{
1159		/* Try a few simple (small) generation numbers first. */
1160		for (error = EEXIST, generation = 1;
1161			 error == EEXIST && generation < SIMPLE_GENERATION_LIMIT;
1162			 ++generation)
1163		{
1164			error = msdosfs_apply_generation_to_short_name(short_name, generation);
1165			if (!error)
1166				error = msdosfs_scan_dir_for_short_name(dep, short_name, context);
1167		}
1168		if (error == 0)
1169			goto done;
1170
1171		/*
1172		 * We've had too many collisions, so use a generation number based on dir_offset,
1173		 * that is likely to be unique in the directory.
1174		 */
1175		generation = SIMPLE_GENERATION_LIMIT + (dir_offset / sizeof(struct dosdirentry));
1176		KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME, dep->de_pmp, dep, generation, 0, 0);
1177
1178		for (error = EEXIST; error == EEXIST && generation < 1000000; ++generation)
1179		{
1180			error = msdosfs_apply_generation_to_short_name(short_name, generation);
1181			if (!error)
1182				error = msdosfs_scan_dir_for_short_name(dep, short_name, context);
1183		}
1184	}
1185
1186done:
1187	KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME|DBG_FUNC_END, error, 0, 0, 0, 0);
1188
1189	return error;
1190}
1191
1192/*
1193 * Find room in a directory to create the entries for a given name.  It also returns
1194 * the short name (without any generation number that may be needed), whether the
1195 * short name needs a generation number, and the lower case flags.
1196 *
1197 * Inputs:
1198 *	dep			directory to search for free/unused entries
1199 *	cnp			the name to be created (used to determine number of slots needed).
1200 *
1201 * Outputs:
1202 *	short_name	The derived short name, without any generation number
1203 *	needs_generation
1204 *				Returns non-zero if the short name needs a generation number inserted
1205 *	lower_case	The case ("NT") flags for the new name
1206 *	offset		Byte offset from start of directory where short name (last entry) goes
1207 *	long_count	Number of entries needed for long name entries
1208 *
1209 * Result:
1210 *	0
1211 *				The outputs are valid.  Note: the resulting offset may be beyond the
1212 *				end of the directory; if so, it is the caller's responsibility to try
1213 *				to grow the directory.
1214 *	ENAMETOOLONG
1215 *				The name provided is illegal.
1216 *	other errno
1217 *				An error reading the directory.
1218 */
1219int msdosfs_findslots(
1220	struct denode *dep,
1221	struct componentname *cnp,
1222	uint8_t short_name[SHORT_NAME_LEN],
1223	int *needs_generation,
1224	uint8_t *lower_case,
1225	uint32_t *offset,
1226	uint32_t *long_count,
1227	vfs_context_t context)
1228{
1229	int error = 0;
1230	u_int16_t ucfn[WIN_MAXLEN];
1231	size_t unichars;
1232	int wincnt=0;	/* Number of consecutive entries needed for long name + dir entry */
1233	int short_name_kind;
1234	int slotcount;	/* Number of consecutive entries found so far */
1235	uint32_t diroff;	/* Byte offset of entry from start of directory */
1236	unsigned blkoff;	/* Byte offset of entry from start of block */
1237	int frcn;	/* File (directory) relative cluster number */
1238	daddr64_t bn;	/* Physical disk block number */
1239	uint32_t blsize;	/* Size of directory cluster, in bytes */
1240	struct dosdirentry *entry;
1241	struct msdosfsmount *pmp;
1242	struct buf *bp = NULL;
1243	char *bdata;
1244
1245	pmp = dep->de_pmp;
1246
1247    KERNEL_DEBUG_CONSTANT(MSDOSFS_FINDSLOTS|DBG_FUNC_START, pmp, dep, 0, 0, 0);
1248
1249	/*
1250	 * Decode name into UCS-2 (Unicode)
1251	 *
1252	 * This function does not generate the on-disk Unicode name; it just cares
1253	 * about the length of the Unicode name.  It assumes that the Services For
1254	 * Macintosh conversions do not change the Unicode name length.  Therefore,
1255	 * we don't pass the flag for Services For Macintosh conversions here.
1256	 */
1257	(void) utf8_decodestr((u_int8_t*)cnp->cn_nameptr, cnp->cn_namelen, ucfn, &unichars,
1258							sizeof(ucfn), 0, UTF_PRECOMPOSED);
1259	unichars /= 2; /* bytes to chars */
1260
1261	/*
1262	 * Determine the number of consecutive directory entries we'll need.
1263	 */
1264	short_name_kind = msdosfs_unicode_to_dos_name(ucfn, unichars, short_name, lower_case);
1265	switch (short_name_kind) {
1266	case 0:
1267			/*
1268			 * The name is syntactically invalid.  Normally, we'd return EINVAL,
1269			 * but ENAMETOOLONG makes it clear that the name is the problem (and
1270			 * allows Carbon to return a more meaningful error).
1271			 */
1272			error = ENAMETOOLONG;
1273			goto done;
1274	case 1:
1275			/*
1276			 * The name is already a short, DOS name, so no long name entries needed.
1277			 */
1278			wincnt = 1;
1279			break;
1280	case 2:
1281	case 3:
1282			/*
1283			 * The name needs long name entries.  The +1 is for the short name entry.
1284			 */
1285			wincnt = msdosfs_winSlotCnt(ucfn, (int)unichars) + 1;
1286			break;
1287	}
1288
1289	/*
1290	 * Look for some consecutive unused directory entries.
1291	 */
1292	slotcount = 0;		/* None found yet. */
1293
1294	/* The outer loop ranges over the clusters in the directory. */
1295	diroff = 0;
1296	for (frcn = 0; ; frcn++) {
1297		error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize);
1298		if (error) {
1299			if (error == E2BIG)
1300			{
1301				/* E2BIG means we hit the end of directory, which is OK here. */
1302				error = 0;
1303				break;
1304			}
1305			else
1306			{
1307				goto done;
1308			}
1309		}
1310		error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp);
1311		if (error) {
1312			goto done;
1313		}
1314		bdata = (char *)buf_dataptr(bp);
1315
1316		/* Loop over entries in the cluster. */
1317		for (blkoff = 0; blkoff < blsize;
1318			 blkoff += sizeof(struct dosdirentry),
1319			 diroff += sizeof(struct dosdirentry))
1320		{
1321			entry = (struct dosdirentry *)(bdata + blkoff);
1322
1323			if (entry->deName[0] == SLOT_EMPTY ||
1324				entry->deName[0] == SLOT_DELETED)
1325			{
1326				slotcount++;
1327				if (slotcount == wincnt) {
1328					/* Found enough space! */
1329					*offset = diroff;
1330					goto found;
1331				}
1332			} else {
1333				/* Empty space wasn't big enough, so forget about it. */
1334				slotcount = 0;
1335			}
1336		}
1337		buf_brelse(bp);
1338		bp = NULL;
1339	}
1340	/*
1341	 * Fix up the slot description to point to where we would put the
1342	 * DOS entry (with Win95 long name entries before that).  If we
1343	 * would need to grow the directory, then the offset will be greater
1344	 * than or equal to the size of the directory.
1345	 */
1346found:
1347	if (wincnt > slotcount) {
1348		/*
1349		 * If we get here, we hit the end of the directory without finding
1350		 * enough consecutive slots.  "slotcount" is the number of free slots
1351		 * at the end of the last cluster.  "diroff" is the size of the
1352		 * directory, in bytes.
1353		 *
1354		 * Note the "- 1" below; that's because the returned offset is the
1355		 * offset of the last slot that would be used (for the short name
1356		 * entry); without subtracting one, we'd end up pointing to the slot
1357		 * immediately past the last one being used.
1358		 */
1359		*offset = diroff + sizeof(struct dosdirentry) * (wincnt - slotcount - 1);
1360	}
1361	*long_count = wincnt - 1;
1362	*needs_generation = (short_name_kind == 3);
1363
1364done:
1365	if (bp)
1366		buf_brelse(bp);
1367
1368    KERNEL_DEBUG_CONSTANT(MSDOSFS_FINDSLOTS|DBG_FUNC_END, error, *lower_case, *offset, *long_count, 0);
1369
1370	return error;
1371}
1372
1373
1374/*
1375 * Write all modified blocks for a given directory.
1376 */
1377int msdosfs_dir_flush(struct denode *dep, int sync)
1378{
1379	int error;
1380	uint32_t frcn;	/* File (directory) relative cluster number */
1381	uint32_t blsize;	/* Size of directory block */
1382	daddr64_t bn;	/* Device block number */
1383	vnode_t devvp = dep->de_pmp->pm_devvp;
1384	buf_t bp;
1385
1386	if (dep->de_refcnt <= 0)
1387	{
1388		/* Don't bother updating a deleted directory */
1389		return 0;
1390	}
1391
1392	for (frcn=0; ; frcn++)
1393	{
1394		error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize);
1395		if (error)
1396		{
1397			if (error == E2BIG)
1398				break;
1399			return error;
1400		}
1401
1402		bp = buf_getblk(devvp, bn, blsize, 0, 0, BLK_META|BLK_ONLYVALID);
1403		if (bp)
1404		{
1405			if (buf_flags(bp) & B_DELWRI)
1406			{
1407				if (sync)
1408					buf_bwrite(bp);
1409				else
1410					buf_bawrite(bp);
1411			}
1412			else
1413			{
1414				buf_brelse(bp);
1415			}
1416		}
1417	}
1418
1419	return 0;
1420}
1421
1422
1423/*
1424 * Invalidate all blocks for a given directory.
1425 */
1426int msdosfs_dir_invalidate(struct denode *dep)
1427{
1428	int error;
1429	uint32_t frcn;	/* File (directory) relative cluster number */
1430	uint32_t blsize;	/* Size of directory block */
1431	daddr64_t bn;	/* Device block number */
1432	vnode_t devvp = dep->de_pmp->pm_devvp;
1433
1434	for (frcn=0; ; frcn++)
1435	{
1436		error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize);
1437		if (error)
1438		{
1439			if (error == E2BIG)
1440				break;
1441			return error;
1442		}
1443
1444		(void) buf_invalblkno(devvp, bn, BUF_WAIT);
1445	}
1446
1447	return 0;
1448}
1449