Apply post-install correction of +CONTEXT files. nrelease now also
[dragonfly.git] / sys / vfs / msdosfs / msdosfs_lookup.c
CommitLineData
984263bc 1/* $FreeBSD: src/sys/msdosfs/msdosfs_lookup.c,v 1.30.2.1 2000/11/03 15:55:39 bp Exp $ */
54078292 2/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_lookup.c,v 1.16 2006/03/24 18:35:34 dillon Exp $ */
984263bc
MD
3/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */
4
5/*-
6 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
7 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
8 * All rights reserved.
9 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by TooLs GmbH.
22 * 4. The name of TooLs GmbH may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36/*
37 * Written by Paul Popelka (paulp@uts.amdahl.com)
38 *
39 * You can do anything you want with this software, just don't say you wrote
40 * it, and don't remove this notice.
41 *
42 * This software is provided "as is".
43 *
44 * The author supplies this software to be publicly redistributed on the
45 * understanding that the author is not responsible for the correct
46 * functioning of this software in any circumstances and is not liable for
47 * any damages caused by this software.
48 *
49 * October 1992
50 */
51
52#include <sys/param.h>
53#include <sys/systm.h>
984263bc
MD
54#include <sys/buf.h>
55#include <sys/vnode.h>
dadab5e9
MD
56#include <sys/proc.h>
57#include <sys/namei.h>
984263bc
MD
58#include <sys/mount.h>
59
1f2de5d4
MD
60#include "bpb.h"
61#include "direntry.h"
62#include "denode.h"
63#include "msdosfsmount.h"
64#include "fat.h"
984263bc
MD
65
66/*
67 * When we search a directory the blocks containing directory entries are
68 * read and examined. The directory entries contain information that would
69 * normally be in the inode of a unix filesystem. This means that some of
70 * a directory's contents may also be in memory resident denodes (sort of
71 * an inode). This can cause problems if we are searching while some other
72 * process is modifying a directory. To prevent one process from accessing
73 * incompletely modified directory information we depend upon being the
74 * sole owner of a directory block. bread/brelse provide this service.
75 * This being the case, when a process modifies a directory it must first
76 * acquire the disk block that contains the directory entry to be modified.
77 * Then update the disk block and the denode, and then write the disk block
78 * out to disk. This way disk blocks containing directory entries and in
79 * memory denode's will be in synch.
4625f023
CP
80 *
81 * msdosfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
82 * struct componentname *a_cnp)
984263bc
MD
83 */
84int
e62afb5f 85msdosfs_lookup(struct vop_old_lookup_args *ap)
984263bc
MD
86{
87 struct vnode *vdp = ap->a_dvp;
88 struct vnode **vpp = ap->a_vpp;
89 struct componentname *cnp = ap->a_cnp;
90 daddr_t bn;
91 int error;
92 int lockparent;
93 int wantparent;
94 int slotcount;
95 int slotoffset = 0;
96 int frcn;
97 u_long cluster;
98 int blkoff;
99 int diroff;
100 int blsize;
101 int isadir; /* ~0 if found direntry is a directory */
102 u_long scn; /* starting cluster number */
103 struct vnode *pdp;
104 struct denode *dp;
105 struct denode *tdp;
106 struct msdosfsmount *pmp;
107 struct buf *bp = 0;
108 struct direntry *dep = NULL;
109 u_char dosfilename[12];
110 int flags = cnp->cn_flags;
111 int nameiop = cnp->cn_nameiop;
dadab5e9 112 struct thread *td = cnp->cn_td;
984263bc
MD
113 int unlen;
114
115 int wincnt = 1;
116 int chksum = -1;
117 int olddos = 1;
2b69e610 118 cnp->cn_flags &= ~CNP_PDIRUNLOCK;
984263bc
MD
119
120#ifdef MSDOSFS_DEBUG
121 printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
122#endif
123 dp = VTODE(vdp);
124 pmp = dp->de_pmp;
125 *vpp = NULL;
2b69e610
MD
126 lockparent = flags & CNP_LOCKPARENT;
127 wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
984263bc
MD
128#ifdef MSDOSFS_DEBUG
129 printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
130 vdp, dp, dp->de_Attributes);
131#endif
132
133 /*
134 * If they are going after the . or .. entry in the root directory,
135 * they won't find it. DOS filesystems don't have them in the root
136 * directory. So, we fake it. deget() is in on this scam too.
137 */
138 if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' &&
139 (cnp->cn_namelen == 1 ||
140 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
141 isadir = ATTR_DIRECTORY;
142 scn = MSDOSFSROOT;
143#ifdef MSDOSFS_DEBUG
144 printf("msdosfs_lookup(): looking for . or .. in root directory\n");
145#endif
146 cluster = MSDOSFSROOT;
147 blkoff = MSDOSFSROOT_OFS;
148 goto foundroot;
149 }
150
151 switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
152 cnp->cn_namelen, 0,
153 pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
154 pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu)) {
155 case 0:
156 return (EINVAL);
157 case 1:
158 break;
159 case 2:
160 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
161 cnp->cn_namelen) + 1;
162 break;
163 case 3:
164 olddos = 0;
165 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
166 cnp->cn_namelen) + 1;
167 break;
168 }
169 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
170 wincnt = 1;
171 olddos = 1;
172 }
173 unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen);
174
175 /*
176 * Suppress search for slots unless creating
177 * file and at end of pathname, in which case
178 * we watch for a place to put the new file in
179 * case it doesn't already exist.
180 */
181 slotcount = wincnt;
fad57d0e 182 if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)
984263bc
MD
183 slotcount = 0;
184
185#ifdef MSDOSFS_DEBUG
186 printf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
187 dosfilename, cnp->cn_namelen);
188#endif
189 /*
190 * Search the directory pointed at by vdp for the name pointed at
191 * by cnp->cn_nameptr.
192 */
193 tdp = NULL;
194 /*
195 * The outer loop ranges over the clusters that make up the
196 * directory. Note that the root directory is different from all
197 * other directories. It has a fixed number of blocks that are not
198 * part of the pool of allocatable clusters. So, we treat it a
199 * little differently. The root directory starts at "cluster" 0.
200 */
201 diroff = 0;
202 for (frcn = 0;; frcn++) {
203 error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
204 if (error) {
205 if (error == E2BIG)
206 break;
207 return (error);
208 }
54078292 209 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
984263bc
MD
210 if (error) {
211 brelse(bp);
212 return (error);
213 }
214 for (blkoff = 0; blkoff < blsize;
215 blkoff += sizeof(struct direntry),
216 diroff += sizeof(struct direntry)) {
217 dep = (struct direntry *)(bp->b_data + blkoff);
218 /*
219 * If the slot is empty and we are still looking
220 * for an empty then remember this one. If the
221 * slot is not empty then check to see if it
222 * matches what we are looking for. If the slot
223 * has never been filled with anything, then the
224 * remainder of the directory has never been used,
225 * so there is no point in searching it.
226 */
227 if (dep->deName[0] == SLOT_EMPTY ||
228 dep->deName[0] == SLOT_DELETED) {
229 /*
230 * Drop memory of previous long matches
231 */
232 chksum = -1;
233
234 if (slotcount < wincnt) {
235 slotcount++;
236 slotoffset = diroff;
237 }
238 if (dep->deName[0] == SLOT_EMPTY) {
239 brelse(bp);
240 goto notfound;
241 }
242 } else {
243 /*
244 * If there wasn't enough space for our winentries,
245 * forget about the empty space
246 */
247 if (slotcount < wincnt)
248 slotcount = 0;
249
250 /*
251 * Check for Win95 long filename entry
252 */
253 if (dep->deAttributes == ATTR_WIN95) {
254 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
255 continue;
256
257 chksum = winChkName((const u_char *)cnp->cn_nameptr,
258 unlen,
259 (struct winentry *)dep,
260 chksum,
261 pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
262 pmp->pm_u2w,
263 pmp->pm_flags & MSDOSFSMNT_ULTABLE,
264 pmp->pm_ul);
265 continue;
266 }
267
268 /*
269 * Ignore volume labels (anywhere, not just
270 * the root directory).
271 */
272 if (dep->deAttributes & ATTR_VOLUME) {
273 chksum = -1;
274 continue;
275 }
276
277 /*
278 * Check for a checksum or name match
279 */
280 if (chksum != winChksum(dep->deName)
281 && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
282 chksum = -1;
283 continue;
284 }
285#ifdef MSDOSFS_DEBUG
286 printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
287 blkoff, diroff);
288#endif
289 /*
290 * Remember where this directory
291 * entry came from for whoever did
292 * this lookup.
293 */
294 dp->de_fndoffset = diroff;
295 dp->de_fndcnt = wincnt - 1;
296
297 goto found;
298 }
299 } /* for (blkoff = 0; .... */
300 /*
301 * Release the buffer holding the directory cluster just
302 * searched.
303 */
304 brelse(bp);
305 } /* for (frcn = 0; ; frcn++) */
306
307notfound:
308 /*
309 * We hold no disk buffers at this point.
310 */
311
312 /*
313 * Fixup the slot description to point to the place where
314 * we might put the new DOS direntry (putting the Win95
315 * long name entries before that)
316 */
317 if (!slotcount) {
318 slotcount = 1;
319 slotoffset = diroff;
320 }
321 if (wincnt > slotcount)
322 slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
323
324 /*
325 * If we get here we didn't find the entry we were looking for. But
326 * that's ok if we are creating or renaming and are at the end of
327 * the pathname and the directory hasn't been removed.
328 */
329#ifdef MSDOSFS_DEBUG
330 printf("msdosfs_lookup(): op %d, refcnt %ld\n",
331 nameiop, dp->de_refcnt);
332 printf(" slotcount %d, slotoffset %d\n",
333 slotcount, slotoffset);
334#endif
2b69e610 335 if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
fad57d0e 336 dp->de_refcnt != 0) {
984263bc
MD
337 /*
338 * Access for write is interpreted as allowing
339 * creation of files in the directory.
340 */
dadab5e9 341 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_td);
984263bc
MD
342 if (error)
343 return (error);
344 /*
345 * Return an indication of where the new directory
346 * entry should be put.
347 */
348 dp->de_fndoffset = slotoffset;
349 dp->de_fndcnt = wincnt - 1;
350
351 /*
352 * We return with the directory locked, so that
353 * the parameters we set up above will still be
354 * valid if we actually decide to do a direnter().
355 * We return ni_vp == NULL to indicate that the entry
356 * does not currently exist; we leave a pointer to
357 * the (locked) directory inode in ndp->ni_dvp.
358 * The pathname buffer is saved so that the name
359 * can be obtained later.
360 *
361 * NB - if the directory is unlocked, then this
362 * information cannot be used.
363 */
984263bc 364 if (!lockparent) {
5fd012e0 365 VOP_UNLOCK(vdp, 0, td);
2b69e610 366 cnp->cn_flags |= CNP_PDIRUNLOCK;
984263bc
MD
367 }
368 return (EJUSTRETURN);
369 }
984263bc
MD
370 return (ENOENT);
371
372found:
373 /*
374 * NOTE: We still have the buffer with matched directory entry at
375 * this point.
376 */
377 isadir = dep->deAttributes & ATTR_DIRECTORY;
378 scn = getushort(dep->deStartCluster);
379 if (FAT32(pmp)) {
380 scn |= getushort(dep->deHighClust) << 16;
381 if (scn == pmp->pm_rootdirblk) {
382 /*
383 * There should actually be 0 here.
384 * Just ignore the error.
385 */
386 scn = MSDOSFSROOT;
387 }
388 }
389
390 if (isadir) {
391 cluster = scn;
392 if (cluster == MSDOSFSROOT)
393 blkoff = MSDOSFSROOT_OFS;
394 else
395 blkoff = 0;
396 } else if (cluster == MSDOSFSROOT)
397 blkoff = diroff;
398
399 /*
400 * Now release buf to allow deget to read the entry again.
401 * Reserving it here and giving it to deget could result
402 * in a deadlock.
403 */
404 brelse(bp);
405 bp = 0;
406
407foundroot:
408 /*
409 * If we entered at foundroot, then we are looking for the . or ..
410 * entry of the filesystems root directory. isadir and scn were
411 * setup before jumping here. And, bp is already null.
412 */
413 if (FAT32(pmp) && scn == MSDOSFSROOT)
414 scn = pmp->pm_rootdirblk;
415
416 /*
417 * If deleting, and at end of pathname, return
418 * parameters which can be used to remove file.
419 * If the wantparent flag isn't set, we return only
420 * the directory (in ndp->ni_dvp), otherwise we go
421 * on and lock the inode, being careful with ".".
422 */
fad57d0e 423 if (nameiop == NAMEI_DELETE) {
984263bc
MD
424 /*
425 * Don't allow deleting the root.
426 */
427 if (blkoff == MSDOSFSROOT_OFS)
428 return EROFS; /* really? XXX */
429
430 /*
431 * Write access to directory required to delete files.
432 */
dadab5e9 433 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_td);
984263bc
MD
434 if (error)
435 return (error);
436
437 /*
438 * Return pointer to current entry in dp->i_offset.
439 * Save directory inode pointer in ndp->ni_dvp for dirremove().
440 */
441 if (dp->de_StartCluster == scn && isadir) { /* "." */
597aea93 442 vref(vdp);
984263bc
MD
443 *vpp = vdp;
444 return (0);
445 }
446 error = deget(pmp, cluster, blkoff, &tdp);
447 if (error)
448 return (error);
449 *vpp = DETOV(tdp);
450 if (!lockparent) {
5fd012e0 451 VOP_UNLOCK(vdp, 0, td);
2b69e610 452 cnp->cn_flags |= CNP_PDIRUNLOCK;
984263bc
MD
453 }
454 return (0);
455 }
456
457 /*
458 * If rewriting (RENAME), return the inode and the
459 * information required to rewrite the present directory
460 * Must get inode of directory entry to verify it's a
461 * regular file, or empty directory.
462 */
fad57d0e 463 if (nameiop == NAMEI_RENAME && wantparent) {
984263bc 464 if (blkoff == MSDOSFSROOT_OFS)
2b69e610 465 return EROFS; /* really? XXX */
984263bc 466
dadab5e9 467 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_td);
984263bc
MD
468 if (error)
469 return (error);
470
471 /*
472 * Careful about locking second inode.
473 * This can only occur if the target is ".".
474 */
475 if (dp->de_StartCluster == scn && isadir)
476 return (EISDIR);
477
478 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
479 return (error);
480 *vpp = DETOV(tdp);
984263bc 481 if (!lockparent) {
5fd012e0 482 VOP_UNLOCK(vdp, 0, td);
2b69e610 483 cnp->cn_flags |= CNP_PDIRUNLOCK;
984263bc
MD
484 }
485 return (0);
486 }
487
488 /*
489 * Step through the translation in the name. We do not `vput' the
490 * directory because we may need it again if a symbolic link
491 * is relative to the current directory. Instead we save it
492 * unlocked as "pdp". We must get the target inode before unlocking
493 * the directory to insure that the inode will not be removed
494 * before we get it. We prevent deadlock by always fetching
495 * inodes from the root, moving down the directory tree. Thus
496 * when following backward pointers ".." we must unlock the
497 * parent directory before getting the requested directory.
498 * There is a potential race condition here if both the current
499 * and parent directories are removed before the VFS_VGET for the
500 * inode associated with ".." returns. We hope that this occurs
501 * infrequently since we cannot avoid this race condition without
502 * implementing a sophisticated deadlock detection algorithm.
503 * Note also that this simple deadlock detection scheme will not
504 * work if the file system has any hard links other than ".."
505 * that point backwards in the directory structure.
506 */
507 pdp = vdp;
2b69e610 508 if (flags & CNP_ISDOTDOT) {
5fd012e0 509 VOP_UNLOCK(pdp, 0, td);
2b69e610 510 cnp->cn_flags |= CNP_PDIRUNLOCK;
984263bc
MD
511 error = deget(pmp, cluster, blkoff, &tdp);
512 if (error) {
5fd012e0 513 vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td);
2b69e610 514 cnp->cn_flags &= ~CNP_PDIRUNLOCK;
984263bc
MD
515 return (error);
516 }
fad57d0e 517 if (lockparent) {
5fd012e0 518 error = vn_lock(pdp, LK_EXCLUSIVE, td);
984263bc
MD
519 if (error) {
520 vput(DETOV(tdp));
521 return (error);
522 }
2b69e610 523 cnp->cn_flags &= ~CNP_PDIRUNLOCK;
984263bc
MD
524 }
525 *vpp = DETOV(tdp);
526 } else if (dp->de_StartCluster == scn && isadir) {
597aea93 527 vref(vdp); /* we want ourself, ie "." */
984263bc
MD
528 *vpp = vdp;
529 } else {
530 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
531 return (error);
fad57d0e 532 if (!lockparent) {
5fd012e0 533 VOP_UNLOCK(pdp, 0, td);
2b69e610 534 cnp->cn_flags |= CNP_PDIRUNLOCK;
984263bc
MD
535 }
536 *vpp = DETOV(tdp);
537 }
984263bc
MD
538 return (0);
539}
540
541/*
542 * dep - directory entry to copy into the directory
543 * ddep - directory to add to
544 * depp - return the address of the denode for the created directory entry
545 * if depp != 0
546 * cnp - componentname needed for Win95 long filenames
547 */
548int
4625f023
CP
549createde(struct denode *dep, struct denode *ddep, struct denode **depp,
550 struct componentname *cnp)
984263bc
MD
551{
552 int error;
553 u_long dirclust, diroffset;
554 struct direntry *ndep;
555 struct msdosfsmount *pmp = ddep->de_pmp;
556 struct buf *bp;
557 daddr_t bn;
558 int blsize;
559
560#ifdef MSDOSFS_DEBUG
561 printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
562 dep, ddep, depp, cnp);
563#endif
564
565 /*
566 * If no space left in the directory then allocate another cluster
567 * and chain it onto the end of the file. There is one exception
568 * to this. That is, if the root directory has no more space it
569 * can NOT be expanded. extendfile() checks for and fails attempts
570 * to extend the root directory. We just return an error in that
571 * case.
572 */
573 if (ddep->de_fndoffset >= ddep->de_FileSize) {
574 diroffset = ddep->de_fndoffset + sizeof(struct direntry)
575 - ddep->de_FileSize;
576 dirclust = de_clcount(pmp, diroffset);
577 error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
578 if (error) {
b1ce5639 579 detrunc(ddep, ddep->de_FileSize, 0, NULL);
984263bc
MD
580 return error;
581 }
582
583 /*
584 * Update the size of the directory
585 */
586 ddep->de_FileSize += de_cn2off(pmp, dirclust);
587 }
588
589 /*
590 * We just read in the cluster with space. Copy the new directory
591 * entry in. Then write it to disk. NOTE: DOS directories
592 * do not get smaller as clusters are emptied.
593 */
594 error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
595 &bn, &dirclust, &blsize);
596 if (error)
597 return error;
598 diroffset = ddep->de_fndoffset;
599 if (dirclust != MSDOSFSROOT)
600 diroffset &= pmp->pm_crbomask;
54078292 601 if ((error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp)) != 0) {
984263bc
MD
602 brelse(bp);
603 return error;
604 }
605 ndep = bptoep(pmp, bp, ddep->de_fndoffset);
606
607 DE_EXTERNALIZE(ndep, dep);
608
609 /*
610 * Now write the Win95 long name
611 */
612 if (ddep->de_fndcnt > 0) {
613 u_int8_t chksum = winChksum(ndep->deName);
614 const u_char *un = (const u_char *)cnp->cn_nameptr;
615 int unlen = cnp->cn_namelen;
616 int cnt = 1;
617
618 while (--ddep->de_fndcnt >= 0) {
619 if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
620 if ((error = bwrite(bp)) != 0)
621 return error;
622
623 ddep->de_fndoffset -= sizeof(struct direntry);
624 error = pcbmap(ddep,
625 de_cluster(pmp,
626 ddep->de_fndoffset),
627 &bn, 0, &blsize);
628 if (error)
629 return error;
630
54078292 631 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
984263bc
MD
632 if (error) {
633 brelse(bp);
634 return error;
635 }
636 ndep = bptoep(pmp, bp, ddep->de_fndoffset);
637 } else {
638 ndep--;
639 ddep->de_fndoffset -= sizeof(struct direntry);
640 }
641 if (!unix2winfn(un, unlen, (struct winentry *)ndep,
642 cnt++, chksum,
643 pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
644 pmp->pm_u2w))
645 break;
646 }
647 }
648
649 if ((error = bwrite(bp)) != 0)
650 return error;
651
652 /*
653 * If they want us to return with the denode gotten.
654 */
655 if (depp) {
656 if (dep->de_Attributes & ATTR_DIRECTORY) {
657 dirclust = dep->de_StartCluster;
658 if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
659 dirclust = MSDOSFSROOT;
660 if (dirclust == MSDOSFSROOT)
661 diroffset = MSDOSFSROOT_OFS;
662 else
663 diroffset = 0;
664 }
665 return deget(pmp, dirclust, diroffset, depp);
666 }
667
668 return 0;
669}
670
671/*
672 * Be sure a directory is empty except for "." and "..". Return 1 if empty,
673 * return 0 if not empty or error.
674 */
675int
4625f023 676dosdirempty(struct denode *dep)
984263bc
MD
677{
678 int blsize;
679 int error;
680 u_long cn;
681 daddr_t bn;
682 struct buf *bp;
683 struct msdosfsmount *pmp = dep->de_pmp;
684 struct direntry *dentp;
685
686 /*
687 * Since the filesize field in directory entries for a directory is
688 * zero, we just have to feel our way through the directory until
689 * we hit end of file.
690 */
691 for (cn = 0;; cn++) {
692 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
693 if (error == E2BIG)
694 return (1); /* it's empty */
695 return (0);
696 }
54078292 697 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
984263bc
MD
698 if (error) {
699 brelse(bp);
700 return (0);
701 }
702 for (dentp = (struct direntry *)bp->b_data;
703 (char *)dentp < bp->b_data + blsize;
704 dentp++) {
705 if (dentp->deName[0] != SLOT_DELETED &&
706 (dentp->deAttributes & ATTR_VOLUME) == 0) {
707 /*
708 * In dos directories an entry whose name
709 * starts with SLOT_EMPTY (0) starts the
710 * beginning of the unused part of the
711 * directory, so we can just return that it
712 * is empty.
713 */
714 if (dentp->deName[0] == SLOT_EMPTY) {
715 brelse(bp);
716 return (1);
717 }
718 /*
719 * Any names other than "." and ".." in a
720 * directory mean it is not empty.
721 */
722 if (bcmp(dentp->deName, ". ", 11) &&
723 bcmp(dentp->deName, ".. ", 11)) {
724 brelse(bp);
725#ifdef MSDOSFS_DEBUG
726 printf("dosdirempty(): entry found %02x, %02x\n",
727 dentp->deName[0], dentp->deName[1]);
728#endif
729 return (0); /* not empty */
730 }
731 }
732 }
733 brelse(bp);
734 }
735 /* NOTREACHED */
736}
737
738/*
739 * Check to see if the directory described by target is in some
740 * subdirectory of source. This prevents something like the following from
741 * succeeding and leaving a bunch or files and directories orphaned. mv
742 * /a/b/c /a/b/c/d/e/f Where c and f are directories.
743 *
744 * source - the inode for /a/b/c
745 * target - the inode for /a/b/c/d/e/f
746 *
747 * Returns 0 if target is NOT a subdirectory of source.
748 * Otherwise returns a non-zero error number.
749 * The target inode is always unlocked on return.
750 */
751int
4625f023 752doscheckpath(struct denode *source, struct denode *target)
984263bc
MD
753{
754 daddr_t scn;
755 struct msdosfsmount *pmp;
756 struct direntry *ep;
757 struct denode *dep;
758 struct buf *bp = NULL;
759 int error = 0;
760
761 dep = target;
762 if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
763 (source->de_Attributes & ATTR_DIRECTORY) == 0) {
764 error = ENOTDIR;
765 goto out;
766 }
767 if (dep->de_StartCluster == source->de_StartCluster) {
768 error = EEXIST;
769 goto out;
770 }
771 if (dep->de_StartCluster == MSDOSFSROOT)
772 goto out;
773 pmp = dep->de_pmp;
774#ifdef DIAGNOSTIC
775 if (pmp != source->de_pmp)
776 panic("doscheckpath: source and target on different filesystems");
777#endif
778 if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
779 goto out;
780
781 for (;;) {
782 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
783 error = ENOTDIR;
784 break;
785 }
786 scn = dep->de_StartCluster;
54078292 787 error = bread(pmp->pm_devvp, de_bntodoff(pmp, cntobn(pmp, scn)),
3b568787 788 pmp->pm_bpcluster, &bp);
984263bc
MD
789 if (error)
790 break;
791
792 ep = (struct direntry *) bp->b_data + 1;
793 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
794 bcmp(ep->deName, ".. ", 11) != 0) {
795 error = ENOTDIR;
796 break;
797 }
798 scn = getushort(ep->deStartCluster);
799 if (FAT32(pmp))
800 scn |= getushort(ep->deHighClust) << 16;
801
802 if (scn == source->de_StartCluster) {
803 error = EINVAL;
804 break;
805 }
806 if (scn == MSDOSFSROOT)
807 break;
808 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
809 /*
810 * scn should be 0 in this case,
811 * but we silently ignore the error.
812 */
813 break;
814 }
815
816 vput(DETOV(dep));
817 brelse(bp);
818 bp = NULL;
819 /* NOTE: deget() clears dep on error */
820 if ((error = deget(pmp, scn, 0, &dep)) != 0)
821 break;
822 }
823out:;
824 if (bp)
825 brelse(bp);
826 if (error == ENOTDIR)
827 printf("doscheckpath(): .. not a directory?\n");
828 if (dep != NULL)
829 vput(DETOV(dep));
830 return (error);
831}
832
833/*
834 * Read in the disk block containing the directory entry (dirclu, dirofs)
835 * and return the address of the buf header, and the address of the
836 * directory entry within the block.
837 */
838int
4625f023
CP
839readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
840 struct buf **bpp, struct direntry **epp)
984263bc
MD
841{
842 int error;
843 daddr_t bn;
844 int blsize;
845
846 blsize = pmp->pm_bpcluster;
847 if (dirclust == MSDOSFSROOT
848 && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
849 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
850 bn = detobn(pmp, dirclust, diroffset);
54078292 851 if ((error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, bpp)) != 0) {
984263bc
MD
852 brelse(*bpp);
853 *bpp = NULL;
854 return (error);
855 }
856 if (epp)
857 *epp = bptoep(pmp, *bpp, diroffset);
858 return (0);
859}
860
861/*
862 * Read in the disk block containing the directory entry dep came from and
863 * return the address of the buf header, and the address of the directory
864 * entry within the block.
865 */
866int
4625f023 867readde(struct denode *dep, struct buf **bpp, struct direntry **epp)
984263bc 868{
984263bc
MD
869 return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
870 bpp, epp));
871}
872
873/*
874 * Remove a directory entry. At this point the file represented by the
875 * directory entry to be removed is still full length until noone has it
876 * open. When the file no longer being used msdosfs_inactive() is called
877 * and will truncate the file to 0 length. When the vnode containing the
878 * denode is needed for some other purpose by VFS it will call
879 * msdosfs_reclaim() which will remove the denode from the denode cache.
880 */
881int
4625f023
CP
882removede(struct denode *pdep, /* directory where the entry is removed */
883 struct denode *dep) /* file to be removed */
984263bc
MD
884{
885 int error;
886 struct direntry *ep;
887 struct buf *bp;
888 daddr_t bn;
889 int blsize;
890 struct msdosfsmount *pmp = pdep->de_pmp;
891 u_long offset = pdep->de_fndoffset;
892
893#ifdef MSDOSFS_DEBUG
894 printf("removede(): filename %s, dep %p, offset %08lx\n",
895 dep->de_Name, dep, offset);
896#endif
897
898 dep->de_refcnt--;
899 offset += sizeof(struct direntry);
900 do {
901 offset -= sizeof(struct direntry);
902 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
903 if (error)
904 return error;
54078292 905 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
984263bc
MD
906 if (error) {
907 brelse(bp);
908 return error;
909 }
910 ep = bptoep(pmp, bp, offset);
911 /*
912 * Check whether, if we came here the second time, i.e.
913 * when underflowing into the previous block, the last
914 * entry in this block is a longfilename entry, too.
915 */
916 if (ep->deAttributes != ATTR_WIN95
917 && offset != pdep->de_fndoffset) {
918 brelse(bp);
919 break;
920 }
921 offset += sizeof(struct direntry);
922 while (1) {
923 /*
924 * We are a bit agressive here in that we delete any Win95
925 * entries preceding this entry, not just the ones we "own".
926 * Since these presumably aren't valid anyway,
927 * there should be no harm.
928 */
929 offset -= sizeof(struct direntry);
930 ep--->deName[0] = SLOT_DELETED;
931 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
932 || !(offset & pmp->pm_crbomask)
933 || ep->deAttributes != ATTR_WIN95)
934 break;
935 }
936 if ((error = bwrite(bp)) != 0)
937 return error;
938 } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
939 && !(offset & pmp->pm_crbomask)
940 && offset);
941 return 0;
942}
943
944/*
945 * Create a unique DOS name in dvp
946 */
947int
4625f023 948uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
984263bc
MD
949{
950 struct msdosfsmount *pmp = dep->de_pmp;
951 struct direntry *dentp;
952 int gen;
953 int blsize;
954 u_long cn;
955 daddr_t bn;
956 struct buf *bp;
957 int error;
958
959 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
960 return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
961 cnp->cn_namelen, 0,
962 pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
963 pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu) ?
964 0 : EINVAL);
965
966 for (gen = 1;; gen++) {
967 /*
968 * Generate DOS name with generation number
969 */
970 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
971 cnp->cn_namelen, gen,
972 pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
973 pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu))
974 return gen == 1 ? EINVAL : EEXIST;
975
976 /*
977 * Now look for a dir entry with this exact name
978 */
979 for (cn = error = 0; !error; cn++) {
980 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
981 if (error == E2BIG) /* EOF reached and not found */
982 return 0;
983 return error;
984 }
54078292 985 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
984263bc
MD
986 if (error) {
987 brelse(bp);
988 return error;
989 }
990 for (dentp = (struct direntry *)bp->b_data;
991 (char *)dentp < bp->b_data + blsize;
992 dentp++) {
993 if (dentp->deName[0] == SLOT_EMPTY) {
994 /*
995 * Last used entry and not found
996 */
997 brelse(bp);
998 return 0;
999 }
1000 /*
1001 * Ignore volume labels and Win95 entries
1002 */
1003 if (dentp->deAttributes & ATTR_VOLUME)
1004 continue;
1005 if (!bcmp(dentp->deName, cp, 11)) {
1006 error = EEXIST;
1007 break;
1008 }
1009 }
1010 brelse(bp);
1011 }
1012 }
1013}
1014
1015/*
1016 * Find any Win'95 long filename entry in directory dep
1017 */
1018int
4625f023 1019findwin95(struct denode *dep)
984263bc
MD
1020{
1021 struct msdosfsmount *pmp = dep->de_pmp;
1022 struct direntry *dentp;
1023 int blsize, win95;
1024 u_long cn;
1025 daddr_t bn;
1026 struct buf *bp;
1027
1028 win95 = 1;
1029 /*
1030 * Read through the directory looking for Win'95 entries
1031 * Note: Error currently handled just as EOF XXX
1032 */
1033 for (cn = 0;; cn++) {
1034 if (pcbmap(dep, cn, &bn, 0, &blsize))
1035 return (win95);
54078292 1036 if (bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp)) {
984263bc
MD
1037 brelse(bp);
1038 return (win95);
1039 }
1040 for (dentp = (struct direntry *)bp->b_data;
1041 (char *)dentp < bp->b_data + blsize;
1042 dentp++) {
1043 if (dentp->deName[0] == SLOT_EMPTY) {
1044 /*
1045 * Last used entry and not found
1046 */
1047 brelse(bp);
1048 return (win95);
1049 }
1050 if (dentp->deName[0] == SLOT_DELETED) {
1051 /*
1052 * Ignore deleted files
1053 * Note: might be an indication of Win'95 anyway XXX
1054 */
1055 continue;
1056 }
1057 if (dentp->deAttributes == ATTR_WIN95) {
1058 brelse(bp);
1059 return 1;
1060 }
1061 win95 = 0;
1062 }
1063 brelse(bp);
1064 }
1065}