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