1 /* $NetBSD: msdosfs_fat.c,v 1.29 2015/03/28 19:24:05 maxv 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 #if HAVE_NBTOOL_CONFIG_H
51 #include "nbtool_config.h"
54 #include <sys/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.29 2015/03/28 19:24:05 maxv Exp $");
58 * kernel include files.
60 #include <sys/param.h>
63 #include <sys/mount.h> /* to define statvfs structure */
64 #include <sys/errno.h>
65 #include <sys/systm.h>
66 #include <sys/kauth.h>
67 #include <sys/dirent.h>
68 #include <sys/namei.h>
70 #include <sys/vnode.h> /* to define vattr structure */
76 * msdosfs include files.
78 #include <fs/msdosfs/bpb.h>
79 #include <fs/msdosfs/msdosfsmount.h>
80 #include <fs/msdosfs/direntry.h>
81 #include <fs/msdosfs/denode.h>
82 #include <fs/msdosfs/fat.h>
87 int fc_fileextends
; /* # of file extends */
88 int fc_lfcempty
; /* # of time last file cluster cache entry
90 int fc_bmapcalls
; /* # of times pcbmap was called */
93 int fc_lmdistance
[LMMAX
]; /* counters for how far off the last
94 * cluster mapped entry was. */
95 int fc_largedistance
; /* off by more than LMMAX */
96 int fc_wherefrom
, fc_whereto
, fc_lastclust
;
100 #define DPRINTF(a) printf a
105 void print_fat_stats(void);
108 print_fat_stats(void)
112 printf("fc_fileextends=%d fc_lfcempty=%d fc_bmapcalls=%d "
113 "fc_largedistance=%d [%d->%d=%d] fc_lastclust=%d pm_fatblocksize=%d\n",
114 fc_fileextends
, fc_lfcempty
, fc_bmapcalls
, fc_largedistance
,
115 fc_wherefrom
, fc_whereto
, fc_whereto
-fc_wherefrom
,
116 fc_lastclust
, pm_fatblocksize
);
118 fc_fileextends
= fc_lfcempty
= fc_bmapcalls
= 0;
119 fc_wherefrom
= fc_whereto
= fc_lastclust
= 0;
121 for (i
= 0; i
< LMMAX
; i
++) {
122 printf("%d:%d ", i
, fc_lmdistance
[i
]);
123 fc_lmdistance
[i
] = 0;
130 static void fatblock(struct msdosfsmount
*, u_long
, u_long
*, u_long
*,
132 void updatefats(struct msdosfsmount
*, struct buf
*, u_long
);
133 static inline void usemap_free(struct msdosfsmount
*, u_long
);
134 static inline void usemap_alloc(struct msdosfsmount
*, u_long
);
135 static int fatchain(struct msdosfsmount
*, u_long
, u_long
, u_long
);
136 int chainlength(struct msdosfsmount
*, u_long
, u_long
);
137 int chainalloc(struct msdosfsmount
*, u_long
, u_long
, u_long
, u_long
*,
141 fatblock(struct msdosfsmount
*pmp
, u_long ofs
, u_long
*bnp
, u_long
*sizep
, u_long
*bop
)
145 bn
= ofs
/ pmp
->pm_fatblocksize
* pmp
->pm_fatblocksec
;
146 size
= min(pmp
->pm_fatblocksec
, pmp
->pm_FATsecs
- bn
)
147 * pmp
->pm_BytesPerSec
;
148 bn
+= pmp
->pm_fatblk
+ pmp
->pm_curfat
* pmp
->pm_FATsecs
;
150 DPRINTF(("%s(ofs=%lu bn=%lu, size=%lu, bo=%lu)\n", __func__
, ofs
, bn
,
151 size
, ofs
% pmp
->pm_fatblocksize
));
157 *bop
= ofs
% pmp
->pm_fatblocksize
;
159 pm_fatblocksize
= pmp
->pm_fatblocksize
;
163 * Map the logical cluster number of a file into a physical disk sector
164 * that is filesystem relative.
166 * dep - address of denode representing the file of interest
167 * findcn - file relative cluster whose filesystem relative cluster number
168 * and/or block number are/is to be found
169 * bnp - address of where to place the file system relative block number.
170 * If this pointer is null then don't return this quantity.
171 * cnp - address of where to place the file system relative cluster number.
172 * If this pointer is null then don't return this quantity.
174 * NOTE: Either bnp or cnp must be non-null.
175 * This function has one side effect. If the requested file relative cluster
176 * is beyond the end of file, then the actual number of clusters in the file
177 * is returned in *cnp. This is useful for determining how long a directory is.
178 * If cnp is null, nothing is returned.
181 pcbmap(struct denode
*dep
, u_long findcn
, daddr_t
*bnp
, u_long
*cnp
, int *sp
)
182 /* findcn: file relative cluster to get */
183 /* bnp: returned filesys rel sector number */
184 /* cnp: returned cluster number */
185 /* sp: returned block size */
190 u_long prevcn
= 0; /* XXX: prevcn could be used unititialized */
194 struct buf
*bp
= NULL
;
196 struct msdosfsmount
*pmp
= dep
->de_pmp
;
202 * If they don't give us someplace to return a value then don't
203 * bother doing anything.
205 if (bnp
== NULL
&& cnp
== NULL
&& sp
== NULL
)
208 cn
= dep
->de_StartCluster
;
209 DPRINTF(("%s(start cluster=%lu)\n", __func__
, cn
));
211 * The "file" that makes up the root directory is contiguous,
212 * permanently allocated, of fixed size, and is not made up of
213 * clusters. If the cluster number is beyond the end of the root
214 * directory, then return the number of clusters in the file.
216 if (cn
== MSDOSFSROOT
) {
217 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
218 if (de_cn2off(pmp
, findcn
) >= dep
->de_FileSize
) {
220 *cnp
= de_bn2cn(pmp
, pmp
->pm_rootdirsize
);
221 DPRINTF(("%s(root, %lu ETOOBIG)\n", __func__
,
222 de_cn2off(pmp
, findcn
)));
226 *bnp
= pmp
->pm_rootdirblk
+ de_cn2bn(pmp
, findcn
);
230 *sp
= min(pmp
->pm_bpcluster
,
231 dep
->de_FileSize
- de_cn2off(pmp
, findcn
));
232 DPRINTF(("%s(root, bn=%lu, cn=%u)\n", __func__
,
233 pmp
->pm_rootdirblk
+ de_cn2bn(pmp
, findcn
),
236 } else { /* just an empty file */
239 DPRINTF(("%s(root, empty ETOOBIG)\n", __func__
));
245 * All other files do I/O in cluster sized blocks
248 *sp
= pmp
->pm_bpcluster
;
251 * Rummage around in the FAT cache, maybe we can avoid tromping
252 * thru every FAT entry for the file. And, keep track of how far
253 * off the cache was from where we wanted to be.
256 fc_lookup(dep
, findcn
, &i
, &cn
);
257 DPRINTF(("%s(bpcluster=%lu i=%lu cn=%lu\n", __func__
, pmp
->pm_bpcluster
,
259 if ((bn
= findcn
- i
) >= LMMAX
) {
263 fc_lastclust
= dep
->de_fc
[FC_LASTFC
].fc_frcn
;
268 * Handle all other files or directories the normal way.
270 for (; i
< findcn
; i
++) {
272 * Stop with all reserved clusters, not just with EOF.
274 if (cn
>= (CLUST_RSRVD
& pmp
->pm_fatmask
))
276 byteoffset
= FATOFS(pmp
, cn
);
277 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
281 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
284 DPRINTF(("%s(bread, %d)\n", __func__
, error
));
293 DPRINTF(("%s(block, %lu >= %lu)\n", __func__
, bo
,
299 cn
= getulong((char *)bp
->b_data
+ bo
);
301 cn
= getushort((char *)bp
->b_data
+ bo
);
302 if (FAT12(pmp
) && (prevcn
& 1))
304 DPRINTF(("%s(cn=%lu masked=%lu)\n", __func__
, cn
,
305 cn
& pmp
->pm_fatmask
));
306 cn
&= pmp
->pm_fatmask
;
309 if (!MSDOSFSEOF(cn
, pmp
->pm_fatmask
)) {
313 *bnp
= cntobn(pmp
, cn
);
316 DPRINTF(("%s(bn=%lu, cn=%lu)\n", __func__
, cntobn(pmp
, cn
),
318 fc_setcache(dep
, FC_LASTMAP
, i
, cn
);
327 /* update last file cluster entry in the FAT cache */
328 fc_setcache(dep
, FC_LASTFC
, i
- 1, prevcn
);
329 DPRINTF(("%s(eof, %lu)\n", __func__
, i
));
334 * Find the closest entry in the FAT cache to the cluster we are looking
338 fc_lookup(struct denode
*dep
, u_long findcn
, u_long
*frcnp
, u_long
*fsrcnp
)
342 struct fatcache
*closest
= 0;
344 for (i
= 0; i
< FC_SIZE
; i
++) {
345 cn
= dep
->de_fc
[i
].fc_frcn
;
346 if (cn
!= FCE_EMPTY
&& cn
<= findcn
) {
347 if (closest
== 0 || cn
> closest
->fc_frcn
)
348 closest
= &dep
->de_fc
[i
];
352 *frcnp
= closest
->fc_frcn
;
353 *fsrcnp
= closest
->fc_fsrcn
;
358 * Purge the FAT cache in denode dep of all entries relating to file
359 * relative cluster frcn and beyond.
362 fc_purge(struct denode
*dep
, u_int frcn
)
365 struct fatcache
*fcp
;
368 for (i
= 0; i
< FC_SIZE
; i
++, fcp
++) {
369 if (fcp
->fc_frcn
>= frcn
)
370 fcp
->fc_frcn
= FCE_EMPTY
;
376 * If mirroring the FAT, update all copies, with the first copy as last.
377 * Else update only the current FAT (ignoring the others).
379 * pmp - msdosfsmount structure for filesystem to update
380 * bp - addr of modified FAT block
381 * fatbn - block number relative to begin of filesystem of the modified FAT block.
384 updatefats(struct msdosfsmount
*pmp
, struct buf
*bp
, u_long fatbn
)
389 DPRINTF(("%s(pmp %p, bp %p, fatbn %lu)\n", __func__
, pmp
, bp
, fatbn
));
392 * If we have an FSInfo block, update it.
394 if (pmp
->pm_fsinfo
) {
395 u_long cn
= pmp
->pm_nxtfree
;
397 if (pmp
->pm_freeclustercount
398 && (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
399 & (1 << (cn
% N_INUSEBITS
)))) {
401 * The cluster indicated in FSInfo isn't free
402 * any longer. Got get a new free one.
404 for (cn
= 0; cn
< pmp
->pm_maxcluster
; cn
++)
405 if (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] != (u_int
)-1)
408 + ffs(pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
412 * XXX If the fsinfo block is stored on media with
413 * 2KB or larger sectors, is the fsinfo structure
414 * padded at the end or in the middle?
416 if (bread(pmp
->pm_devvp
, de_bn2kb(pmp
, pmp
->pm_fsinfo
),
417 pmp
->pm_BytesPerSec
, B_MODIFY
, &bpn
) != 0) {
419 * Ignore the error, but turn off FSInfo update for the future.
423 struct fsinfo
*fp
= (struct fsinfo
*)bpn
->b_data
;
425 putulong(fp
->fsinfree
, pmp
->pm_freeclustercount
);
426 putulong(fp
->fsinxtfree
, pmp
->pm_nxtfree
);
427 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
434 if (pmp
->pm_flags
& MSDOSFS_FATMIRROR
) {
436 * Now copy the block(s) of the modified FAT to the other copies of
437 * the FAT and write them out. This is faster than reading in the
438 * other FATs and then writing them back out. This could tie up
439 * the FAT for quite a while. Preventing others from accessing it.
440 * To prevent us from going after the FAT quite so much we use
441 * delayed writes, unless they specified "synchronous" when the
442 * filesystem was mounted. If synch is asked for then use
443 * bwrite()'s and really slow things down.
445 for (i
= 1; i
< pmp
->pm_FATs
; i
++) {
446 fatbn
+= pmp
->pm_FATsecs
;
447 /* getblk() never fails */
448 bpn
= getblk(pmp
->pm_devvp
, de_bn2kb(pmp
, fatbn
),
450 memcpy(bpn
->b_data
, bp
->b_data
, bp
->b_bcount
);
451 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
459 * Write out the first (or current) FAT last.
461 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
466 * Maybe update fsinfo sector here?
471 * Updating entries in 12 bit FATs is a pain in the butt.
473 * The following picture shows where nibbles go when moving from a 12 bit
474 * cluster number into the appropriate bytes in the FAT.
476 * byte m byte m+1 byte m+2
477 * +----+----+ +----+----+ +----+----+
478 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
479 * +----+----+ +----+----+ +----+----+
481 * +----+----+----+ +----+----+----+
482 * | 3 0 1 | | 4 5 2 |
483 * +----+----+----+ +----+----+----+
484 * cluster n cluster n+1
486 * Where n is even. m = n + (n >> 2)
490 usemap_alloc(struct msdosfsmount
*pmp
, u_long cn
)
493 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] |= 1 << (cn
% N_INUSEBITS
);
494 pmp
->pm_freeclustercount
--;
498 usemap_free(struct msdosfsmount
*pmp
, u_long cn
)
501 pmp
->pm_freeclustercount
++;
502 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &= ~(1 << (cn
% N_INUSEBITS
));
506 clusterfree(struct msdosfsmount
*pmp
, u_long cluster
, u_long
*oldcnp
)
511 usemap_free(pmp
, cluster
);
512 error
= fatentry(FAT_GET_AND_SET
, pmp
, cluster
, &oldcn
, MSDOSFSFREE
);
514 usemap_alloc(pmp
, cluster
);
518 * If the cluster was successfully marked free, then update
519 * the count of free clusters, and turn off the "allocated"
520 * bit in the "in use" cluster bit map.
528 * Get or Set or 'Get and Set' the cluster'th entry in the FAT.
530 * function - whether to get or set a fat entry
531 * pmp - address of the msdosfsmount structure for the filesystem
532 * whose FAT is to be manipulated.
533 * cn - which cluster is of interest
534 * oldcontents - address of a word that is to receive the contents of the
535 * cluster'th entry if this is a get function
536 * newcontents - the new value to be written into the cluster'th element of
537 * the FAT if this is a set function.
539 * This function can also be used to free a cluster by setting the FAT entry
540 * for a cluster to 0.
542 * All copies of the FAT are updated if this is a set function. NOTE: If
543 * fatentry() marks a cluster as free it does not update the inusemap in
544 * the msdosfsmount structure. This is left to the caller.
547 fatentry(int function
, struct msdosfsmount
*pmp
, u_long cn
, u_long
*oldcontents
, u_long newcontents
)
551 u_long bn
, bo
, bsize
, byteoffset
;
554 DPRINTF(("%s(func %d, pmp %p, clust %lu, oldcon %p, newcon " "%lx)\n",
555 __func__
, function
, pmp
, cn
, oldcontents
, newcontents
));
559 * Be sure they asked us to do something.
561 if ((function
& (FAT_SET
| FAT_GET
)) == 0) {
562 DPRINTF(("%s(): function code doesn't specify get or set\n",
568 * If they asked us to return a cluster number but didn't tell us
569 * where to put it, give them an error.
571 if ((function
& FAT_GET
) && oldcontents
== NULL
) {
572 DPRINTF(("%s(): get function with no place to put result\n",
579 * Be sure the requested cluster is in the filesystem.
581 if (cn
< CLUST_FIRST
|| cn
> pmp
->pm_maxcluster
)
584 byteoffset
= FATOFS(pmp
, cn
);
585 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
586 if ((error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
591 if (function
& FAT_GET
) {
593 readcn
= getulong((char *)bp
->b_data
+ bo
);
595 readcn
= getushort((char *)bp
->b_data
+ bo
);
596 if (FAT12(pmp
) & (cn
& 1))
598 readcn
&= pmp
->pm_fatmask
;
599 *oldcontents
= readcn
;
601 if (function
& FAT_SET
) {
602 switch (pmp
->pm_fatmask
) {
604 readcn
= getushort((char *)bp
->b_data
+ bo
);
607 readcn
|= newcontents
<< 4;
610 readcn
|= newcontents
& 0xfff;
612 putushort((char *)bp
->b_data
+ bo
, readcn
);
615 putushort((char *)bp
->b_data
+ bo
, newcontents
);
619 * According to spec we have to retain the
620 * high order bits of the FAT entry.
622 readcn
= getulong((char *)bp
->b_data
+ bo
);
623 readcn
&= ~FAT32_MASK
;
624 readcn
|= newcontents
& FAT32_MASK
;
625 putulong((char *)bp
->b_data
+ bo
, readcn
);
628 updatefats(pmp
, bp
, bn
);
638 * Update a contiguous cluster chain
641 * start - first cluster of chain
642 * count - number of clusters in chain
643 * fillwith - what to write into FAT entry of last cluster
646 fatchain(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
)
649 u_long bn
, bo
, bsize
, byteoffset
, readcn
, newc
;
652 DPRINTF(("%s(pmp %p, start %lu, count %lu, fillwith %lx)\n", __func__
,
653 pmp
, start
, count
, fillwith
));
655 * Be sure the clusters are in the filesystem.
657 if (start
< CLUST_FIRST
|| start
+ count
- 1 > pmp
->pm_maxcluster
)
661 byteoffset
= FATOFS(pmp
, start
);
662 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
663 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
670 newc
= --count
> 0 ? start
: fillwith
;
671 switch (pmp
->pm_fatmask
) {
673 readcn
= getushort((char *)bp
->b_data
+ bo
);
676 readcn
|= newc
& 0xfff;
681 putushort((char *)bp
->b_data
+ bo
, readcn
);
687 putushort((char *)bp
->b_data
+ bo
, newc
);
691 readcn
= getulong((char *)bp
->b_data
+ bo
);
692 readcn
&= ~pmp
->pm_fatmask
;
693 readcn
|= newc
& pmp
->pm_fatmask
;
694 putulong((char *)bp
->b_data
+ bo
, readcn
);
701 updatefats(pmp
, bp
, bn
);
708 * Check the length of a free cluster chain starting at start.
711 * start - start of chain
712 * count - maximum interesting length
715 chainlength(struct msdosfsmount
*pmp
, u_long start
, u_long count
)
721 max_idx
= pmp
->pm_maxcluster
/ N_INUSEBITS
;
722 idx
= start
/ N_INUSEBITS
;
723 start
%= N_INUSEBITS
;
724 map
= pmp
->pm_inusemap
[idx
];
725 map
&= ~((1 << start
) - 1);
727 len
= ffs(map
) - 1 - start
;
728 return (len
> count
? count
: len
);
730 len
= N_INUSEBITS
- start
;
733 while (++idx
<= max_idx
) {
736 if ((map
= pmp
->pm_inusemap
[idx
]) != 0) {
742 return (len
> count
? count
: len
);
746 * Allocate contigous free clusters.
749 * start - start of cluster chain.
750 * count - number of clusters to allocate.
751 * fillwith - put this value into the FAT entry for the
752 * last allocated cluster.
753 * retcluster - put the first allocated cluster's number here.
754 * got - how many clusters were actually allocated.
757 chainalloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
, u_long
*retcluster
, u_long
*got
)
762 for (cl
= start
, n
= count
; n
-- > 0;)
763 usemap_alloc(pmp
, cl
++);
764 if ((error
= fatchain(pmp
, start
, count
, fillwith
)) != 0)
767 DPRINTF(("%s(): allocated cluster chain at %lu (%lu clusters)\n",
768 __func__
, start
, count
));
777 * Allocate contiguous free clusters.
780 * start - preferred start of cluster chain.
781 * count - number of clusters requested.
782 * fillwith - put this value into the FAT entry for the
783 * last allocated cluster.
784 * retcluster - put the first allocated cluster's number here.
785 * got - how many clusters were actually allocated.
788 clusteralloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long
*retcluster
, u_long
*got
)
791 u_long len
, newst
, foundl
, cn
, l
;
792 u_long foundcn
= 0; /* XXX: foundcn could be used unititialized */
793 u_long fillwith
= CLUST_EOFE
;
796 DPRINTF(("%s(): find %lu clusters\n", __func__
, count
));
798 if ((len
= chainlength(pmp
, start
, count
)) >= count
)
799 return (chainalloc(pmp
, start
, count
, fillwith
, retcluster
, got
));
802 * This is a new file, initialize start
807 start
= (tv
.tv_usec
>> 10) | tv
.tv_usec
;
812 * Start at a (pseudo) random place to maximize cluster runs
813 * under multiple writers.
815 newst
= (start
* 1103515245 + 12345) % (pmp
->pm_maxcluster
+ 1);
818 for (cn
= newst
; cn
<= pmp
->pm_maxcluster
;) {
819 idx
= cn
/ N_INUSEBITS
;
820 map
= pmp
->pm_inusemap
[idx
];
821 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
822 if (map
!= (u_int
)-1) {
823 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
824 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
825 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
833 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
835 for (cn
= 0; cn
< newst
;) {
836 idx
= cn
/ N_INUSEBITS
;
837 map
= pmp
->pm_inusemap
[idx
];
838 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
839 if (map
!= (u_int
)-1) {
840 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
841 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
842 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
850 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
857 return (chainalloc(pmp
, start
, len
, fillwith
, retcluster
, got
));
859 return (chainalloc(pmp
, foundcn
, foundl
, fillwith
, retcluster
, got
));
864 * Free a chain of clusters.
866 * pmp - address of the msdosfs mount structure for the filesystem
867 * containing the cluster chain to be freed.
868 * startcluster - number of the 1st cluster in the chain of clusters to be
872 freeclusterchain(struct msdosfsmount
*pmp
, u_long cluster
)
875 struct buf
*bp
= NULL
;
876 u_long bn
, bo
, bsize
, byteoffset
;
877 u_long readcn
, lbn
= -1;
879 while (cluster
>= CLUST_FIRST
&& cluster
<= pmp
->pm_maxcluster
) {
880 byteoffset
= FATOFS(pmp
, cluster
);
881 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
884 updatefats(pmp
, bp
, lbn
);
885 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
892 usemap_free(pmp
, cluster
);
894 switch (pmp
->pm_fatmask
) {
896 readcn
= getushort((char *)bp
->b_data
+ bo
);
898 cluster
= readcn
>> 4;
900 readcn
|= MSDOSFSFREE
<< 4;
904 readcn
|= MSDOSFSFREE
& 0xfff;
906 putushort((char *)bp
->b_data
+ bo
, readcn
);
909 cluster
= getushort((char *)bp
->b_data
+ bo
);
910 putushort((char *)bp
->b_data
+ bo
, MSDOSFSFREE
);
913 cluster
= getulong((char *)bp
->b_data
+ bo
);
914 putulong((char *)bp
->b_data
+ bo
,
915 (MSDOSFSFREE
& FAT32_MASK
) | (cluster
& ~FAT32_MASK
));
918 cluster
&= pmp
->pm_fatmask
;
921 updatefats(pmp
, bp
, bn
);
926 * Read in FAT blocks looking for free clusters. For every free cluster
927 * found turn off its corresponding bit in the pm_inusemap.
930 fillinusemap(struct msdosfsmount
*pmp
)
932 struct buf
*bp
= NULL
;
935 u_long bn
, bo
, bsize
, byteoffset
;
938 * Mark all clusters in use, we mark the free ones in the FAT scan
941 for (cn
= 0; cn
< (pmp
->pm_maxcluster
+ N_INUSEBITS
) / N_INUSEBITS
; cn
++)
942 pmp
->pm_inusemap
[cn
] = (u_int
)-1;
945 * Figure how many free clusters are in the filesystem by ripping
946 * through the FAT counting the number of entries whose content is
947 * zero. These represent free clusters.
949 pmp
->pm_freeclustercount
= 0;
950 for (cn
= CLUST_FIRST
; cn
<= pmp
->pm_maxcluster
; cn
++) {
951 byteoffset
= FATOFS(pmp
, cn
);
952 bo
= byteoffset
% pmp
->pm_fatblocksize
;
954 /* Read new FAT block */
957 fatblock(pmp
, byteoffset
, &bn
, &bsize
, NULL
);
958 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), bsize
,
965 readcn
= getulong((char *)bp
->b_data
+ bo
);
967 readcn
= getushort((char *)bp
->b_data
+ bo
);
968 if (FAT12(pmp
) && (cn
& 1))
970 readcn
&= pmp
->pm_fatmask
;
973 usemap_free(pmp
, cn
);
981 * Allocate a new cluster and chain it onto the end of the file.
983 * dep - the file to extend
984 * count - number of clusters to allocate
985 * bpp - where to return the address of the buf header for the first new
987 * ncp - where to put cluster number of the first newly allocated cluster
988 * If this pointer is 0, do not return the cluster number.
991 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
992 * the de_flag field of the denode and it does not change the de_FileSize
993 * field. This is left for the caller to do.
997 extendfile(struct denode
*dep
, u_long count
, struct buf
**bpp
, u_long
*ncp
, int flags
)
1000 u_long frcn
= 0, cn
, got
;
1001 struct msdosfsmount
*pmp
= dep
->de_pmp
;
1005 * Don't try to extend the root directory
1007 if (dep
->de_StartCluster
== MSDOSFSROOT
1008 && (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
1009 DPRINTF(("%s(): attempt to extend root directory\n", __func__
));
1014 * If the "file's last cluster" cache entry is empty, and the file
1015 * is not empty, then fill the cache entry by calling pcbmap().
1018 if (dep
->de_fc
[FC_LASTFC
].fc_frcn
== FCE_EMPTY
&&
1019 dep
->de_StartCluster
!= 0) {
1021 error
= pcbmap(dep
, CLUST_END
, 0, &cn
, 0);
1022 /* we expect it to return E2BIG */
1027 fc_last_to_nexttolast(dep
);
1032 * Allocate a new cluster chain and cat onto the end of the
1033 * file. If the file is empty we make de_StartCluster point
1034 * to the new block. Note that de_StartCluster being 0 is
1035 * sufficient to be sure the file is empty since we exclude
1036 * attempts to extend the root directory above, and the root
1037 * dir is the only file with a startcluster of 0 that has
1038 * blocks allocated (sort of).
1041 if (dep
->de_StartCluster
== 0)
1044 cn
= dep
->de_fc
[FC_LASTFC
].fc_fsrcn
+ 1;
1045 error
= clusteralloc(pmp
, cn
, count
, &cn
, &got
);
1052 * Give them the filesystem relative cluster number if they want
1060 if (dep
->de_StartCluster
== 0) {
1061 dep
->de_StartCluster
= cn
;
1064 error
= fatentry(FAT_SET
, pmp
,
1065 dep
->de_fc
[FC_LASTFC
].fc_fsrcn
,
1068 clusterfree(pmp
, cn
, NULL
);
1071 frcn
= dep
->de_fc
[FC_LASTFC
].fc_frcn
+ 1;
1075 * Update the "last cluster of the file" entry in the
1076 * denode's FAT cache.
1079 fc_setcache(dep
, FC_LASTFC
, frcn
+ got
- 1, cn
+ got
- 1);
1080 if ((flags
& DE_CLEAR
) &&
1081 (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
1083 bp
= getblk(pmp
->pm_devvp
,
1084 de_bn2kb(pmp
, cntobn(pmp
, cn
++)),
1085 pmp
->pm_bpcluster
, 0, 0);