1 /* $NetBSD: msdosfs_fat.c,v 1.17 2009/03/14 15:36:21 dsl Exp $ */
4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
35 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 * You can do anything you want with this software, just don't say you wrote
38 * it, and don't remove this notice.
40 * This software is provided "as is".
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.
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.17 2009/03/14 15:36:21 dsl Exp $");
54 * kernel include files.
56 #include <sys/param.h>
57 #include <sys/systm.h>
60 #include <sys/namei.h>
61 #include <sys/mount.h> /* to define statvfs structure */
62 #include <sys/vnode.h> /* to define vattr structure */
63 #include <sys/errno.h>
64 #include <sys/dirent.h>
65 #include <sys/kauth.h>
68 * msdosfs include files.
70 #include <fs/msdosfs/bpb.h>
71 #include <fs/msdosfs/msdosfsmount.h>
72 #include <fs/msdosfs/direntry.h>
73 #include <fs/msdosfs/denode.h>
74 #include <fs/msdosfs/fat.h>
79 int fc_fileextends
; /* # of file extends */
80 int fc_lfcempty
; /* # of time last file cluster cache entry
82 int fc_bmapcalls
; /* # of times pcbmap was called */
85 int fc_lmdistance
[LMMAX
]; /* counters for how far off the last
86 * cluster mapped entry was. */
87 int fc_largedistance
; /* off by more than LMMAX */
88 int fc_wherefrom
, fc_whereto
, fc_lastclust
;
92 void print_fat_stats(void);
99 printf("fc_fileextends=%d fc_lfcempty=%d fc_bmapcalls=%d "
100 "fc_largedistance=%d [%d->%d=%d] fc_lastclust=%d pm_fatblocksize=%d\n",
101 fc_fileextends
, fc_lfcempty
, fc_bmapcalls
, fc_largedistance
,
102 fc_wherefrom
, fc_whereto
, fc_whereto
-fc_wherefrom
,
103 fc_lastclust
, pm_fatblocksize
);
105 fc_fileextends
= fc_lfcempty
= fc_bmapcalls
= 0;
106 fc_wherefrom
= fc_whereto
= fc_lastclust
= 0;
108 for (i
= 0; i
< LMMAX
; i
++) {
109 printf("%d:%d ", i
, fc_lmdistance
[i
]);
110 fc_lmdistance
[i
] = 0;
117 static void fatblock(struct msdosfsmount
*, u_long
, u_long
*, u_long
*,
119 void updatefats(struct msdosfsmount
*, struct buf
*, u_long
);
120 static inline void usemap_free(struct msdosfsmount
*, u_long
);
121 static inline void usemap_alloc(struct msdosfsmount
*, u_long
);
122 static int fatchain(struct msdosfsmount
*, u_long
, u_long
, u_long
);
123 int chainlength(struct msdosfsmount
*, u_long
, u_long
);
124 int chainalloc(struct msdosfsmount
*, u_long
, u_long
, u_long
, u_long
*,
128 fatblock(struct msdosfsmount
*pmp
, u_long ofs
, u_long
*bnp
, u_long
*sizep
, u_long
*bop
)
132 bn
= ofs
/ pmp
->pm_fatblocksize
* pmp
->pm_fatblocksec
;
133 size
= min(pmp
->pm_fatblocksec
, pmp
->pm_FATsecs
- bn
)
134 * pmp
->pm_BytesPerSec
;
135 bn
+= pmp
->pm_fatblk
+ pmp
->pm_curfat
* pmp
->pm_FATsecs
;
142 *bop
= ofs
% pmp
->pm_fatblocksize
;
144 pm_fatblocksize
= pmp
->pm_fatblocksize
;
148 * Map the logical cluster number of a file into a physical disk sector
149 * that is filesystem relative.
151 * dep - address of denode representing the file of interest
152 * findcn - file relative cluster whose filesystem relative cluster number
153 * and/or block number are/is to be found
154 * bnp - address of where to place the file system relative block number.
155 * If this pointer is null then don't return this quantity.
156 * cnp - address of where to place the file system relative cluster number.
157 * If this pointer is null then don't return this quantity.
159 * NOTE: Either bnp or cnp must be non-null.
160 * This function has one side effect. If the requested file relative cluster
161 * is beyond the end of file, then the actual number of clusters in the file
162 * is returned in *cnp. This is useful for determining how long a directory is.
163 * If cnp is null, nothing is returned.
166 pcbmap(struct denode
*dep
, u_long findcn
, daddr_t
*bnp
, u_long
*cnp
, int *sp
)
167 /* findcn: file relative cluster to get */
168 /* bnp: returned filesys rel sector number */
169 /* cnp: returned cluster number */
170 /* sp: returned block size */
175 u_long prevcn
= 0; /* XXX: prevcn could be used unititialized */
179 struct buf
*bp
= NULL
;
181 struct msdosfsmount
*pmp
= dep
->de_pmp
;
187 * If they don't give us someplace to return a value then don't
188 * bother doing anything.
190 if (bnp
== NULL
&& cnp
== NULL
&& sp
== NULL
)
193 cn
= dep
->de_StartCluster
;
195 * The "file" that makes up the root directory is contiguous,
196 * permanently allocated, of fixed size, and is not made up of
197 * clusters. If the cluster number is beyond the end of the root
198 * directory, then return the number of clusters in the file.
200 if (cn
== MSDOSFSROOT
) {
201 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
202 if (de_cn2off(pmp
, findcn
) >= dep
->de_FileSize
) {
204 *cnp
= de_bn2cn(pmp
, pmp
->pm_rootdirsize
);
208 *bnp
= pmp
->pm_rootdirblk
+ de_cn2bn(pmp
, findcn
);
212 *sp
= min(pmp
->pm_bpcluster
,
213 dep
->de_FileSize
- de_cn2off(pmp
, findcn
));
215 } else { /* just an empty file */
223 * All other files do I/O in cluster sized blocks
226 *sp
= pmp
->pm_bpcluster
;
229 * Rummage around in the fat cache, maybe we can avoid tromping
230 * thru every fat entry for the file. And, keep track of how far
231 * off the cache was from where we wanted to be.
234 fc_lookup(dep
, findcn
, &i
, &cn
);
235 if ((bn
= findcn
- i
) >= LMMAX
) {
239 fc_lastclust
= dep
->de_fc
[FC_LASTFC
].fc_frcn
;
244 * Handle all other files or directories the normal way.
246 for (; i
< findcn
; i
++) {
248 * Stop with all reserved clusters, not just with EOF.
250 if (cn
>= (CLUST_RSRVD
& pmp
->pm_fatmask
))
252 byteoffset
= FATOFS(pmp
, cn
);
253 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
257 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
273 cn
= getulong((char *)bp
->b_data
+ bo
);
275 cn
= getushort((char *)bp
->b_data
+ bo
);
276 if (FAT12(pmp
) && (prevcn
& 1))
278 cn
&= pmp
->pm_fatmask
;
281 if (!MSDOSFSEOF(cn
, pmp
->pm_fatmask
)) {
285 *bnp
= cntobn(pmp
, cn
);
288 fc_setcache(dep
, FC_LASTMAP
, i
, cn
);
297 /* update last file cluster entry in the fat cache */
298 fc_setcache(dep
, FC_LASTFC
, i
- 1, prevcn
);
303 * Find the closest entry in the fat cache to the cluster we are looking
307 fc_lookup(struct denode
*dep
, u_long findcn
, u_long
*frcnp
, u_long
*fsrcnp
)
311 struct fatcache
*closest
= 0;
313 for (i
= 0; i
< FC_SIZE
; i
++) {
314 cn
= dep
->de_fc
[i
].fc_frcn
;
315 if (cn
!= FCE_EMPTY
&& cn
<= findcn
) {
316 if (closest
== 0 || cn
> closest
->fc_frcn
)
317 closest
= &dep
->de_fc
[i
];
321 *frcnp
= closest
->fc_frcn
;
322 *fsrcnp
= closest
->fc_fsrcn
;
327 * Purge the fat cache in denode dep of all entries relating to file
328 * relative cluster frcn and beyond.
331 fc_purge(struct denode
*dep
, u_int frcn
)
334 struct fatcache
*fcp
;
337 for (i
= 0; i
< FC_SIZE
; i
++, fcp
++) {
338 if (fcp
->fc_frcn
>= frcn
)
339 fcp
->fc_frcn
= FCE_EMPTY
;
345 * If mirroring the fat, update all copies, with the first copy as last.
346 * Else update only the current fat (ignoring the others).
348 * pmp - msdosfsmount structure for filesystem to update
349 * bp - addr of modified fat block
350 * fatbn - block number relative to begin of filesystem of the modified fat block.
353 updatefats(struct msdosfsmount
*pmp
, struct buf
*bp
, u_long fatbn
)
359 printf("updatefats(pmp %p, bp %p, fatbn %lu)\n",
364 * If we have an FSInfo block, update it.
366 if (pmp
->pm_fsinfo
) {
367 u_long cn
= pmp
->pm_nxtfree
;
369 if (pmp
->pm_freeclustercount
370 && (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
371 & (1 << (cn
% N_INUSEBITS
)))) {
373 * The cluster indicated in FSInfo isn't free
374 * any longer. Got get a new free one.
376 for (cn
= 0; cn
< pmp
->pm_maxcluster
; cn
++)
377 if (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] != (u_int
)-1)
380 + ffs(pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
384 * XXX If the fsinfo block is stored on media with
385 * 2KB or larger sectors, is the fsinfo structure
386 * padded at the end or in the middle?
388 if (bread(pmp
->pm_devvp
, de_bn2kb(pmp
, pmp
->pm_fsinfo
),
389 pmp
->pm_BytesPerSec
, NOCRED
, B_MODIFY
, &bpn
) != 0) {
391 * Ignore the error, but turn off FSInfo update for the future.
396 struct fsinfo
*fp
= (struct fsinfo
*)bpn
->b_data
;
398 putulong(fp
->fsinfree
, pmp
->pm_freeclustercount
);
399 putulong(fp
->fsinxtfree
, pmp
->pm_nxtfree
);
400 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
407 if (pmp
->pm_flags
& MSDOSFS_FATMIRROR
) {
409 * Now copy the block(s) of the modified fat to the other copies of
410 * the fat and write them out. This is faster than reading in the
411 * other fats and then writing them back out. This could tie up
412 * the fat for quite a while. Preventing others from accessing it.
413 * To prevent us from going after the fat quite so much we use
414 * delayed writes, unless they specified "synchronous" when the
415 * filesystem was mounted. If synch is asked for then use
416 * bwrite()'s and really slow things down.
418 for (i
= 1; i
< pmp
->pm_FATs
; i
++) {
419 fatbn
+= pmp
->pm_FATsecs
;
420 /* getblk() never fails */
421 bpn
= getblk(pmp
->pm_devvp
, de_bn2kb(pmp
, fatbn
),
423 memcpy(bpn
->b_data
, bp
->b_data
, bp
->b_bcount
);
424 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
432 * Write out the first (or current) fat last.
434 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
439 * Maybe update fsinfo sector here?
444 * Updating entries in 12 bit fats is a pain in the butt.
446 * The following picture shows where nibbles go when moving from a 12 bit
447 * cluster number into the appropriate bytes in the FAT.
449 * byte m byte m+1 byte m+2
450 * +----+----+ +----+----+ +----+----+
451 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
452 * +----+----+ +----+----+ +----+----+
454 * +----+----+----+ +----+----+----+
455 * | 3 0 1 | | 4 5 2 |
456 * +----+----+----+ +----+----+----+
457 * cluster n cluster n+1
459 * Where n is even. m = n + (n >> 2)
463 usemap_alloc(struct msdosfsmount
*pmp
, u_long cn
)
466 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] |= 1 << (cn
% N_INUSEBITS
);
467 pmp
->pm_freeclustercount
--;
471 usemap_free(struct msdosfsmount
*pmp
, u_long cn
)
474 pmp
->pm_freeclustercount
++;
475 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &= ~(1 << (cn
% N_INUSEBITS
));
479 clusterfree(struct msdosfsmount
*pmp
, u_long cluster
, u_long
*oldcnp
)
484 usemap_free(pmp
, cluster
);
485 error
= fatentry(FAT_GET_AND_SET
, pmp
, cluster
, &oldcn
, MSDOSFSFREE
);
487 usemap_alloc(pmp
, cluster
);
491 * If the cluster was successfully marked free, then update
492 * the count of free clusters, and turn off the "allocated"
493 * bit in the "in use" cluster bit map.
501 * Get or Set or 'Get and Set' the cluster'th entry in the fat.
503 * function - whether to get or set a fat entry
504 * pmp - address of the msdosfsmount structure for the filesystem
505 * whose fat is to be manipulated.
506 * cn - which cluster is of interest
507 * oldcontents - address of a word that is to receive the contents of the
508 * cluster'th entry if this is a get function
509 * newcontents - the new value to be written into the cluster'th element of
510 * the fat if this is a set function.
512 * This function can also be used to free a cluster by setting the fat entry
513 * for a cluster to 0.
515 * All copies of the fat are updated if this is a set function. NOTE: If
516 * fatentry() marks a cluster as free it does not update the inusemap in
517 * the msdosfsmount structure. This is left to the caller.
520 fatentry(int function
, struct msdosfsmount
*pmp
, u_long cn
, u_long
*oldcontents
, u_long newcontents
)
524 u_long bn
, bo
, bsize
, byteoffset
;
528 printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
529 function
, pmp
, cn
, oldcontents
, newcontents
);
534 * Be sure they asked us to do something.
536 if ((function
& (FAT_SET
| FAT_GET
)) == 0) {
537 printf("fatentry(): function code doesn't specify get or set\n");
542 * If they asked us to return a cluster number but didn't tell us
543 * where to put it, give them an error.
545 if ((function
& FAT_GET
) && oldcontents
== NULL
) {
546 printf("fatentry(): get function with no place to put result\n");
552 * Be sure the requested cluster is in the filesystem.
554 if (cn
< CLUST_FIRST
|| cn
> pmp
->pm_maxcluster
)
557 byteoffset
= FATOFS(pmp
, cn
);
558 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
559 if ((error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
, NOCRED
,
565 if (function
& FAT_GET
) {
567 readcn
= getulong((char *)bp
->b_data
+ bo
);
569 readcn
= getushort((char *)bp
->b_data
+ bo
);
570 if (FAT12(pmp
) & (cn
& 1))
572 readcn
&= pmp
->pm_fatmask
;
573 *oldcontents
= readcn
;
575 if (function
& FAT_SET
) {
576 switch (pmp
->pm_fatmask
) {
578 readcn
= getushort((char *)bp
->b_data
+ bo
);
581 readcn
|= newcontents
<< 4;
584 readcn
|= newcontents
& 0xfff;
586 putushort((char *)bp
->b_data
+ bo
, readcn
);
589 putushort((char *)bp
->b_data
+ bo
, newcontents
);
593 * According to spec we have to retain the
594 * high order bits of the fat entry.
596 readcn
= getulong((char *)bp
->b_data
+ bo
);
597 readcn
&= ~FAT32_MASK
;
598 readcn
|= newcontents
& FAT32_MASK
;
599 putulong((char *)bp
->b_data
+ bo
, readcn
);
602 updatefats(pmp
, bp
, bn
);
612 * Update a contiguous cluster chain
615 * start - first cluster of chain
616 * count - number of clusters in chain
617 * fillwith - what to write into fat entry of last cluster
620 fatchain(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
)
623 u_long bn
, bo
, bsize
, byteoffset
, readcn
, newc
;
627 printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
628 pmp
, start
, count
, fillwith
);
631 * Be sure the clusters are in the filesystem.
633 if (start
< CLUST_FIRST
|| start
+ count
- 1 > pmp
->pm_maxcluster
)
637 byteoffset
= FATOFS(pmp
, start
);
638 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
639 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
, NOCRED
,
647 newc
= --count
> 0 ? start
: fillwith
;
648 switch (pmp
->pm_fatmask
) {
650 readcn
= getushort((char *)bp
->b_data
+ bo
);
653 readcn
|= newc
& 0xfff;
658 putushort((char *)bp
->b_data
+ bo
, readcn
);
664 putushort((char *)bp
->b_data
+ bo
, newc
);
668 readcn
= getulong((char *)bp
->b_data
+ bo
);
669 readcn
&= ~pmp
->pm_fatmask
;
670 readcn
|= newc
& pmp
->pm_fatmask
;
671 putulong((char *)bp
->b_data
+ bo
, readcn
);
678 updatefats(pmp
, bp
, bn
);
685 * Check the length of a free cluster chain starting at start.
688 * start - start of chain
689 * count - maximum interesting length
692 chainlength(struct msdosfsmount
*pmp
, u_long start
, u_long count
)
698 max_idx
= pmp
->pm_maxcluster
/ N_INUSEBITS
;
699 idx
= start
/ N_INUSEBITS
;
700 start
%= N_INUSEBITS
;
701 map
= pmp
->pm_inusemap
[idx
];
702 map
&= ~((1 << start
) - 1);
704 len
= ffs(map
) - 1 - start
;
705 return (len
> count
? count
: len
);
707 len
= N_INUSEBITS
- start
;
710 while (++idx
<= max_idx
) {
713 if ((map
= pmp
->pm_inusemap
[idx
]) != 0) {
719 return (len
> count
? count
: len
);
723 * Allocate contigous free clusters.
726 * start - start of cluster chain.
727 * count - number of clusters to allocate.
728 * fillwith - put this value into the fat entry for the
729 * last allocated cluster.
730 * retcluster - put the first allocated cluster's number here.
731 * got - how many clusters were actually allocated.
734 chainalloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
, u_long
*retcluster
, u_long
*got
)
739 for (cl
= start
, n
= count
; n
-- > 0;)
740 usemap_alloc(pmp
, cl
++);
741 if ((error
= fatchain(pmp
, start
, count
, fillwith
)) != 0)
744 printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
755 * Allocate contiguous free clusters.
758 * start - preferred start of cluster chain.
759 * count - number of clusters requested.
760 * fillwith - put this value into the fat entry for the
761 * last allocated cluster.
762 * retcluster - put the first allocated cluster's number here.
763 * got - how many clusters were actually allocated.
766 clusteralloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long
*retcluster
, u_long
*got
)
769 u_long len
, newst
, foundl
, cn
, l
;
770 u_long foundcn
= 0; /* XXX: foundcn could be used unititialized */
771 u_long fillwith
= CLUST_EOFE
;
775 printf("clusteralloc(): find %lu clusters\n",count
);
778 if ((len
= chainlength(pmp
, start
, count
)) >= count
)
779 return (chainalloc(pmp
, start
, count
, fillwith
, retcluster
, got
));
782 * This is a new file, initialize start
787 start
= (tv
.tv_usec
>> 10) | tv
.tv_usec
;
792 * Start at a (pseudo) random place to maximize cluster runs
793 * under multiple writers.
795 newst
= (start
* 1103515245 + 12345) % (pmp
->pm_maxcluster
+ 1);
798 for (cn
= newst
; cn
<= pmp
->pm_maxcluster
;) {
799 idx
= cn
/ N_INUSEBITS
;
800 map
= pmp
->pm_inusemap
[idx
];
801 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
802 if (map
!= (u_int
)-1) {
803 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
804 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
805 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
813 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
815 for (cn
= 0; cn
< newst
;) {
816 idx
= cn
/ N_INUSEBITS
;
817 map
= pmp
->pm_inusemap
[idx
];
818 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
819 if (map
!= (u_int
)-1) {
820 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
821 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
822 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
830 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
837 return (chainalloc(pmp
, start
, len
, fillwith
, retcluster
, got
));
839 return (chainalloc(pmp
, foundcn
, foundl
, fillwith
, retcluster
, got
));
844 * Free a chain of clusters.
846 * pmp - address of the msdosfs mount structure for the filesystem
847 * containing the cluster chain to be freed.
848 * startcluster - number of the 1st cluster in the chain of clusters to be
852 freeclusterchain(struct msdosfsmount
*pmp
, u_long cluster
)
855 struct buf
*bp
= NULL
;
856 u_long bn
, bo
, bsize
, byteoffset
;
857 u_long readcn
, lbn
= -1;
859 while (cluster
>= CLUST_FIRST
&& cluster
<= pmp
->pm_maxcluster
) {
860 byteoffset
= FATOFS(pmp
, cluster
);
861 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
864 updatefats(pmp
, bp
, lbn
);
865 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
866 NOCRED
, B_MODIFY
, &bp
);
873 usemap_free(pmp
, cluster
);
875 switch (pmp
->pm_fatmask
) {
877 readcn
= getushort((char *)bp
->b_data
+ bo
);
879 cluster
= readcn
>> 4;
881 readcn
|= MSDOSFSFREE
<< 4;
885 readcn
|= MSDOSFSFREE
& 0xfff;
887 putushort((char *)bp
->b_data
+ bo
, readcn
);
890 cluster
= getushort((char *)bp
->b_data
+ bo
);
891 putushort((char *)bp
->b_data
+ bo
, MSDOSFSFREE
);
894 cluster
= getulong((char *)bp
->b_data
+ bo
);
895 putulong((char *)bp
->b_data
+ bo
,
896 (MSDOSFSFREE
& FAT32_MASK
) | (cluster
& ~FAT32_MASK
));
899 cluster
&= pmp
->pm_fatmask
;
902 updatefats(pmp
, bp
, bn
);
907 * Read in fat blocks looking for free clusters. For every free cluster
908 * found turn off its corresponding bit in the pm_inusemap.
911 fillinusemap(struct msdosfsmount
*pmp
)
913 struct buf
*bp
= NULL
;
916 u_long bn
, bo
, bsize
, byteoffset
;
919 * Mark all clusters in use, we mark the free ones in the fat scan
922 for (cn
= 0; cn
< (pmp
->pm_maxcluster
+ N_INUSEBITS
) / N_INUSEBITS
; cn
++)
923 pmp
->pm_inusemap
[cn
] = (u_int
)-1;
926 * Figure how many free clusters are in the filesystem by ripping
927 * through the fat counting the number of entries whose content is
928 * zero. These represent free clusters.
930 pmp
->pm_freeclustercount
= 0;
931 for (cn
= CLUST_FIRST
; cn
<= pmp
->pm_maxcluster
; cn
++) {
932 byteoffset
= FATOFS(pmp
, cn
);
933 bo
= byteoffset
% pmp
->pm_fatblocksize
;
935 /* Read new FAT block */
938 fatblock(pmp
, byteoffset
, &bn
, &bsize
, NULL
);
939 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
947 readcn
= getulong((char *)bp
->b_data
+ bo
);
949 readcn
= getushort((char *)bp
->b_data
+ bo
);
950 if (FAT12(pmp
) && (cn
& 1))
952 readcn
&= pmp
->pm_fatmask
;
955 usemap_free(pmp
, cn
);
962 * Allocate a new cluster and chain it onto the end of the file.
964 * dep - the file to extend
965 * count - number of clusters to allocate
966 * bpp - where to return the address of the buf header for the first new
968 * ncp - where to put cluster number of the first newly allocated cluster
969 * If this pointer is 0, do not return the cluster number.
972 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
973 * the de_flag field of the denode and it does not change the de_FileSize
974 * field. This is left for the caller to do.
978 extendfile(struct denode
*dep
, u_long count
, struct buf
**bpp
, u_long
*ncp
, int flags
)
981 u_long frcn
= 0, cn
, got
;
982 struct msdosfsmount
*pmp
= dep
->de_pmp
;
986 * Don't try to extend the root directory
988 if (dep
->de_StartCluster
== MSDOSFSROOT
989 && (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
990 printf("extendfile(): attempt to extend root directory\n");
995 * If the "file's last cluster" cache entry is empty, and the file
996 * is not empty, then fill the cache entry by calling pcbmap().
999 if (dep
->de_fc
[FC_LASTFC
].fc_frcn
== FCE_EMPTY
&&
1000 dep
->de_StartCluster
!= 0) {
1002 error
= pcbmap(dep
, CLUST_END
, 0, &cn
, 0);
1003 /* we expect it to return E2BIG */
1008 fc_last_to_nexttolast(dep
);
1013 * Allocate a new cluster chain and cat onto the end of the
1014 * file. If the file is empty we make de_StartCluster point
1015 * to the new block. Note that de_StartCluster being 0 is
1016 * sufficient to be sure the file is empty since we exclude
1017 * attempts to extend the root directory above, and the root
1018 * dir is the only file with a startcluster of 0 that has
1019 * blocks allocated (sort of).
1022 if (dep
->de_StartCluster
== 0)
1025 cn
= dep
->de_fc
[FC_LASTFC
].fc_fsrcn
+ 1;
1026 error
= clusteralloc(pmp
, cn
, count
, &cn
, &got
);
1033 * Give them the filesystem relative cluster number if they want
1041 if (dep
->de_StartCluster
== 0) {
1042 dep
->de_StartCluster
= cn
;
1045 error
= fatentry(FAT_SET
, pmp
,
1046 dep
->de_fc
[FC_LASTFC
].fc_fsrcn
,
1049 clusterfree(pmp
, cn
, NULL
);
1052 frcn
= dep
->de_fc
[FC_LASTFC
].fc_frcn
+ 1;
1056 * Update the "last cluster of the file" entry in the
1057 * denode's fat cache.
1060 fc_setcache(dep
, FC_LASTFC
, frcn
+ got
- 1, cn
+ got
- 1);
1061 if ((flags
& DE_CLEAR
) &&
1062 (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
1064 bp
= getblk(pmp
->pm_devvp
,
1065 de_bn2kb(pmp
, cntobn(pmp
, cn
++)),
1066 pmp
->pm_bpcluster
, 0, 0);