1 /* $FreeBSD: src/sys/msdosfs/msdosfs_fat.c,v 1.23 2000/01/27 14:43:06 nyan Exp $ */
2 /* $DragonFly: src/sys/vfs/msdosfs/msdosfs_fat.c,v 1.11 2006/12/23 00:41:29 swildner Exp $ */
3 /* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */
6 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
7 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
9 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
37 * Written by Paul Popelka (paulp@uts.amdahl.com)
39 * You can do anything you want with this software, just don't say you wrote
40 * it, and don't remove this notice.
42 * This software is provided "as is".
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.
53 * kernel include files.
55 #include <sys/param.h>
56 #include <sys/systm.h>
58 #include <sys/mount.h> /* to define statfs structure */
59 #include <sys/vnode.h> /* to define vattr structure */
62 * msdosfs include files.
65 #include "msdosfsmount.h"
73 static int fc_fileextends
; /* # of file extends */
74 static int fc_lfcempty
; /* # of time last file cluster cache entry
76 static int fc_bmapcalls
; /* # of times pcbmap was called */
79 static int fc_lmdistance
[LMMAX
];/* counters for how far off the last
80 * cluster mapped entry was. */
81 static int fc_largedistance
; /* off by more than LMMAX */
83 static int chainalloc (struct msdosfsmount
*pmp
, u_long start
,
84 u_long count
, u_long fillwith
,
85 u_long
*retcluster
, u_long
*got
);
86 static int chainlength (struct msdosfsmount
*pmp
, u_long start
,
88 static void fatblock (struct msdosfsmount
*pmp
, u_long ofs
,
89 u_long
*bnp
, u_long
*sizep
, u_long
*bop
);
90 static int fatchain (struct msdosfsmount
*pmp
, u_long start
,
91 u_long count
, u_long fillwith
);
92 static void fc_lookup (struct denode
*dep
, u_long findcn
,
93 u_long
*frcnp
, u_long
*fsrcnp
);
94 static void updatefats (struct msdosfsmount
*pmp
, struct buf
*bp
,
97 usemap_alloc (struct msdosfsmount
*pmp
, u_long cn
);
99 usemap_free (struct msdosfsmount
*pmp
, u_long cn
);
102 fatblock(struct msdosfsmount
*pmp
, u_long ofs
, u_long
*bnp
, u_long
*sizep
,
107 bn
= ofs
/ pmp
->pm_fatblocksize
* pmp
->pm_fatblocksec
;
108 size
= min(pmp
->pm_fatblocksec
, pmp
->pm_FATsecs
- bn
)
110 bn
+= pmp
->pm_fatblk
+ pmp
->pm_curfat
* pmp
->pm_FATsecs
;
117 *bop
= ofs
% pmp
->pm_fatblocksize
;
121 * Map the logical cluster number of a file into a physical disk sector
122 * that is filesystem relative.
124 * dep - address of denode representing the file of interest
125 * findcn - file relative cluster whose filesystem relative cluster number
126 * and/or block number are/is to be found
127 * bnp - address of where to place the file system relative block number.
128 * If this pointer is null then don't return this quantity.
129 * cnp - address of where to place the file system relative cluster number.
130 * If this pointer is null then don't return this quantity.
132 * NOTE: Either bnp or cnp must be non-null.
133 * This function has one side effect. If the requested file relative cluster
134 * is beyond the end of file, then the actual number of clusters in the file
135 * is returned in *cnp. This is useful for determining how long a directory is.
136 * If cnp is null, nothing is returned.
139 pcbmap(struct denode
*dep
,
140 u_long findcn
, /* file relative cluster to get */
141 daddr_t
*bnp
, /* returned filesys relative blk number */
142 u_long
*cnp
, /* returned cluster number */
143 int *sp
) /* returned block size */
148 u_long prevcn
= 0; /* XXX: prevcn could be used unititialized */
152 struct buf
*bp
= NULL
;
154 struct msdosfsmount
*pmp
= dep
->de_pmp
;
160 * If they don't give us someplace to return a value then don't
161 * bother doing anything.
163 if (bnp
== NULL
&& cnp
== NULL
&& sp
== NULL
)
166 cn
= dep
->de_StartCluster
;
168 * The "file" that makes up the root directory is contiguous,
169 * permanently allocated, of fixed size, and is not made up of
170 * clusters. If the cluster number is beyond the end of the root
171 * directory, then return the number of clusters in the file.
173 if (cn
== MSDOSFSROOT
) {
174 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
175 if (de_cn2off(pmp
, findcn
) >= dep
->de_FileSize
) {
177 *cnp
= de_bn2cn(pmp
, pmp
->pm_rootdirsize
);
181 *bnp
= pmp
->pm_rootdirblk
+ de_cn2bn(pmp
, findcn
);
185 *sp
= min(pmp
->pm_bpcluster
,
186 dep
->de_FileSize
- de_cn2off(pmp
, findcn
));
188 } else { /* just an empty file */
196 * All other files do I/O in cluster sized blocks
199 *sp
= pmp
->pm_bpcluster
;
202 * Rummage around in the fat cache, maybe we can avoid tromping
203 * thru every fat entry for the file. And, keep track of how far
204 * off the cache was from where we wanted to be.
207 fc_lookup(dep
, findcn
, &i
, &cn
);
208 if ((bn
= findcn
- i
) >= LMMAX
)
214 * Handle all other files or directories the normal way.
216 for (; i
< findcn
; i
++) {
218 * Stop with all reserved clusters, not just with EOF.
220 if ((cn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
222 byteoffset
= FATOFS(pmp
, cn
);
223 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
227 error
= bread(pmp
->pm_devvp
, de_bntodoff(pmp
, bn
), bsize
, &bp
);
236 cn
= getulong(&bp
->b_data
[bo
]);
238 cn
= getushort(&bp
->b_data
[bo
]);
239 if (FAT12(pmp
) && (prevcn
& 1))
241 cn
&= pmp
->pm_fatmask
;
244 * Force the special cluster numbers
245 * to be the same for all cluster sizes
246 * to let the rest of msdosfs handle
247 * all cases the same.
249 if ((cn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
250 cn
|= ~pmp
->pm_fatmask
;
253 if (!MSDOSFSEOF(pmp
, cn
)) {
257 *bnp
= xcntobn(pmp
, cn
);
260 fc_setcache(dep
, FC_LASTMAP
, i
, cn
);
269 /* update last file cluster entry in the fat cache */
270 fc_setcache(dep
, FC_LASTFC
, i
- 1, prevcn
);
275 * Find the closest entry in the fat cache to the cluster we are looking
279 fc_lookup(struct denode
*dep
, u_long findcn
, u_long
*frcnp
, u_long
*fsrcnp
)
283 struct fatcache
*closest
= 0;
285 for (i
= 0; i
< FC_SIZE
; i
++) {
286 cn
= dep
->de_fc
[i
].fc_frcn
;
287 if (cn
!= FCE_EMPTY
&& cn
<= findcn
) {
288 if (closest
== 0 || cn
> closest
->fc_frcn
)
289 closest
= &dep
->de_fc
[i
];
293 *frcnp
= closest
->fc_frcn
;
294 *fsrcnp
= closest
->fc_fsrcn
;
299 * Purge the fat cache in denode dep of all entries relating to file
300 * relative cluster frcn and beyond.
303 fc_purge(struct denode
*dep
, u_int frcn
)
306 struct fatcache
*fcp
;
309 for (i
= 0; i
< FC_SIZE
; i
++, fcp
++) {
310 if (fcp
->fc_frcn
>= frcn
)
311 fcp
->fc_frcn
= FCE_EMPTY
;
317 * If mirroring the fat, update all copies, with the first copy as last.
318 * Else update only the current fat (ignoring the others).
320 * pmp - msdosfsmount structure for filesystem to update
321 * bp - addr of modified fat block
322 * fatbn - block number relative to begin of filesystem of the modified fat block.
325 updatefats(struct msdosfsmount
*pmp
, struct buf
*bp
, u_long fatbn
)
331 kprintf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp
, bp
, fatbn
);
335 * If we have an FSInfo block, update it.
337 if (pmp
->pm_fsinfo
) {
338 u_long cn
= pmp
->pm_nxtfree
;
340 if (pmp
->pm_freeclustercount
341 && (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
342 & (1 << (cn
% N_INUSEBITS
)))) {
344 * The cluster indicated in FSInfo isn't free
345 * any longer. Got get a new free one.
347 for (cn
= 0; cn
< pmp
->pm_maxcluster
; cn
+= N_INUSEBITS
)
348 if (pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] != (u_int
)-1)
351 + ffs(pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]
354 if (bread(pmp
->pm_devvp
, de_bntodoff(pmp
, pmp
->pm_fsinfo
), fsi_size(pmp
), &bpn
) != 0) {
356 * Ignore the error, but turn off FSInfo update for the future.
361 struct fsinfo
*fp
= (struct fsinfo
*)bpn
->b_data
;
363 putulong(fp
->fsinfree
, pmp
->pm_freeclustercount
);
364 putulong(fp
->fsinxtfree
, pmp
->pm_nxtfree
);
365 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
372 if (pmp
->pm_flags
& MSDOSFS_FATMIRROR
) {
374 * Now copy the block(s) of the modified fat to the other copies of
375 * the fat and write them out. This is faster than reading in the
376 * other fats and then writing them back out. This could tie up
377 * the fat for quite a while. Preventing others from accessing it.
378 * To prevent us from going after the fat quite so much we use
379 * delayed writes, unless they specfied "synchronous" when the
380 * filesystem was mounted. If synch is asked for then use
381 * bwrite()'s and really slow things down.
383 for (i
= 1; i
< pmp
->pm_FATs
; i
++) {
384 fatbn
+= pmp
->pm_FATsecs
;
385 /* getblk() never fails */
386 bpn
= getblk(pmp
->pm_devvp
, de_bntodoff(pmp
, fatbn
),
388 bcopy(bp
->b_data
, bpn
->b_data
, bp
->b_bcount
);
389 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
397 * Write out the first (or current) fat last.
399 if (pmp
->pm_flags
& MSDOSFSMNT_WAITONFAT
)
404 * Maybe update fsinfo sector here?
409 * Updating entries in 12 bit fats is a pain in the butt.
411 * The following picture shows where nibbles go when moving from a 12 bit
412 * cluster number into the appropriate bytes in the FAT.
414 * byte m byte m+1 byte m+2
415 * +----+----+ +----+----+ +----+----+
416 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
417 * +----+----+ +----+----+ +----+----+
419 * +----+----+----+ +----+----+----+
420 * | 3 0 1 | | 4 5 2 |
421 * +----+----+----+ +----+----+----+
422 * cluster n cluster n+1
424 * Where n is even. m = n + (n >> 2)
428 usemap_alloc(struct msdosfsmount
*pmp
, u_long cn
)
431 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] |= 1 << (cn
% N_INUSEBITS
);
432 pmp
->pm_freeclustercount
--;
436 usemap_free(struct msdosfsmount
*pmp
, u_long cn
)
439 pmp
->pm_freeclustercount
++;
440 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &= ~(1 << (cn
% N_INUSEBITS
));
444 clusterfree(struct msdosfsmount
*pmp
, u_long cluster
, u_long
*oldcnp
)
449 usemap_free(pmp
, cluster
);
450 error
= fatentry(FAT_GET_AND_SET
, pmp
, cluster
, &oldcn
, MSDOSFSFREE
);
452 usemap_alloc(pmp
, cluster
);
456 * If the cluster was successfully marked free, then update
457 * the count of free clusters, and turn off the "allocated"
458 * bit in the "in use" cluster bit map.
466 * Get or Set or 'Get and Set' the cluster'th entry in the fat.
468 * function - whether to get or set a fat entry
469 * pmp - address of the msdosfsmount structure for the filesystem
470 * whose fat is to be manipulated.
471 * cn - which cluster is of interest
472 * oldcontents - address of a word that is to receive the contents of the
473 * cluster'th entry if this is a get function
474 * newcontents - the new value to be written into the cluster'th element of
475 * the fat if this is a set function.
477 * This function can also be used to free a cluster by setting the fat entry
478 * for a cluster to 0.
480 * All copies of the fat are updated if this is a set function. NOTE: If
481 * fatentry() marks a cluster as free it does not update the inusemap in
482 * the msdosfsmount structure. This is left to the caller.
485 fatentry(int function
, struct msdosfsmount
*pmp
, u_long cn
, u_long
*oldcontents
,
490 u_long bn
, bo
, bsize
, byteoffset
;
494 kprintf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
495 function
, pmp
, cn
, oldcontents
, newcontents
);
500 * Be sure they asked us to do something.
502 if ((function
& (FAT_SET
| FAT_GET
)) == 0) {
503 kprintf("fatentry(): function code doesn't specify get or set\n");
508 * If they asked us to return a cluster number but didn't tell us
509 * where to put it, give them an error.
511 if ((function
& FAT_GET
) && oldcontents
== NULL
) {
512 kprintf("fatentry(): get function with no place to put result\n");
518 * Be sure the requested cluster is in the filesystem.
520 if (cn
< CLUST_FIRST
|| cn
> pmp
->pm_maxcluster
)
523 byteoffset
= FATOFS(pmp
, cn
);
524 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
525 error
= bread(pmp
->pm_devvp
, de_bntodoff(pmp
, bn
), bsize
, &bp
);
531 if (function
& FAT_GET
) {
533 readcn
= getulong(&bp
->b_data
[bo
]);
535 readcn
= getushort(&bp
->b_data
[bo
]);
536 if (FAT12(pmp
) & (cn
& 1))
538 readcn
&= pmp
->pm_fatmask
;
539 /* map reserved fat entries to same values for all fats */
540 if ((readcn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
541 readcn
|= ~pmp
->pm_fatmask
;
542 *oldcontents
= readcn
;
544 if (function
& FAT_SET
) {
545 switch (pmp
->pm_fatmask
) {
547 readcn
= getushort(&bp
->b_data
[bo
]);
550 readcn
|= newcontents
<< 4;
553 readcn
|= newcontents
& 0xfff;
555 putushort(&bp
->b_data
[bo
], readcn
);
558 putushort(&bp
->b_data
[bo
], newcontents
);
562 * According to spec we have to retain the
563 * high order bits of the fat entry.
565 readcn
= getulong(&bp
->b_data
[bo
]);
566 readcn
&= ~FAT32_MASK
;
567 readcn
|= newcontents
& FAT32_MASK
;
568 putulong(&bp
->b_data
[bo
], readcn
);
571 updatefats(pmp
, bp
, bn
);
581 * Update a contiguous cluster chain
584 * start - first cluster of chain
585 * count - number of clusters in chain
586 * fillwith - what to write into fat entry of last cluster
589 fatchain(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
)
592 u_long bn
, bo
, bsize
, byteoffset
, readcn
, newc
;
596 kprintf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
597 pmp
, start
, count
, fillwith
);
600 * Be sure the clusters are in the filesystem.
602 if (start
< CLUST_FIRST
|| start
+ count
- 1 > pmp
->pm_maxcluster
)
606 byteoffset
= FATOFS(pmp
, start
);
607 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
608 error
= bread(pmp
->pm_devvp
, de_bntodoff(pmp
, bn
), bsize
, &bp
);
615 newc
= --count
> 0 ? start
: fillwith
;
616 switch (pmp
->pm_fatmask
) {
618 readcn
= getushort(&bp
->b_data
[bo
]);
621 readcn
|= newc
& 0xfff;
626 putushort(&bp
->b_data
[bo
], readcn
);
632 putushort(&bp
->b_data
[bo
], newc
);
636 readcn
= getulong(&bp
->b_data
[bo
]);
637 readcn
&= ~pmp
->pm_fatmask
;
638 readcn
|= newc
& pmp
->pm_fatmask
;
639 putulong(&bp
->b_data
[bo
], readcn
);
646 updatefats(pmp
, bp
, bn
);
653 * Check the length of a free cluster chain starting at start.
656 * start - start of chain
657 * count - maximum interesting length
660 chainlength(struct msdosfsmount
*pmp
, u_long start
, u_long count
)
666 max_idx
= pmp
->pm_maxcluster
/ N_INUSEBITS
;
667 idx
= start
/ N_INUSEBITS
;
668 start
%= N_INUSEBITS
;
669 map
= pmp
->pm_inusemap
[idx
];
670 map
&= ~((1 << start
) - 1);
672 len
= ffs(map
) - 1 - start
;
673 return (len
> count
? count
: len
);
675 len
= N_INUSEBITS
- start
;
678 while (++idx
<= max_idx
) {
681 map
= pmp
->pm_inusemap
[idx
];
688 return (len
> count
? count
: len
);
692 * Allocate contigous free clusters.
695 * start - start of cluster chain.
696 * count - number of clusters to allocate.
697 * fillwith - put this value into the fat entry for the
698 * last allocated cluster.
699 * retcluster - put the first allocated cluster's number here.
700 * got - how many clusters were actually allocated.
703 chainalloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
,
704 u_long fillwith
, u_long
*retcluster
, u_long
*got
)
709 for (cl
= start
, n
= count
; n
-- > 0;)
710 usemap_alloc(pmp
, cl
++);
712 error
= fatchain(pmp
, start
, count
, fillwith
);
716 kprintf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
727 * Allocate contiguous free clusters.
730 * start - preferred start of cluster chain.
731 * count - number of clusters requested.
732 * fillwith - put this value into the fat entry for the
733 * last allocated cluster.
734 * retcluster - put the first allocated cluster's number here.
735 * got - how many clusters were actually allocated.
738 clusteralloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
,
739 u_long fillwith
, u_long
*retcluster
, u_long
*got
)
742 u_long len
, newst
, foundl
, cn
, l
;
743 u_long foundcn
= 0; /* XXX: foundcn could be used unititialized */
747 kprintf("clusteralloc(): find %lu clusters\n",count
);
750 if ((len
= chainlength(pmp
, start
, count
)) >= count
)
751 return (chainalloc(pmp
, start
, count
, fillwith
, retcluster
, got
));
756 * Start at a (pseudo) random place to maximize cluster runs
757 * under multiple writers.
759 newst
= krandom() % (pmp
->pm_maxcluster
+ 1);
762 for (cn
= newst
; cn
<= pmp
->pm_maxcluster
;) {
763 idx
= cn
/ N_INUSEBITS
;
764 map
= pmp
->pm_inusemap
[idx
];
765 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
766 if (map
!= (u_int
)-1) {
767 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
768 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
769 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
777 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
779 for (cn
= 0; cn
< newst
;) {
780 idx
= cn
/ N_INUSEBITS
;
781 map
= pmp
->pm_inusemap
[idx
];
782 map
|= (1 << (cn
% N_INUSEBITS
)) - 1;
783 if (map
!= (u_int
)-1) {
784 cn
= idx
* N_INUSEBITS
+ ffs(map
^(u_int
)-1) - 1;
785 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
786 return (chainalloc(pmp
, cn
, count
, fillwith
, retcluster
, got
));
794 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
801 return (chainalloc(pmp
, start
, len
, fillwith
, retcluster
, got
));
803 return (chainalloc(pmp
, foundcn
, foundl
, fillwith
, retcluster
, got
));
808 * Free a chain of clusters.
810 * pmp - address of the msdosfs mount structure for the filesystem
811 * containing the cluster chain to be freed.
812 * startcluster - number of the 1st cluster in the chain of clusters to be
816 freeclusterchain(struct msdosfsmount
*pmp
, u_long cluster
)
819 struct buf
*bp
= NULL
;
820 u_long bn
, bo
, bsize
, byteoffset
;
821 u_long readcn
, lbn
= -1;
823 while (cluster
>= CLUST_FIRST
&& cluster
<= pmp
->pm_maxcluster
) {
824 byteoffset
= FATOFS(pmp
, cluster
);
825 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
828 updatefats(pmp
, bp
, lbn
);
829 error
= bread(pmp
->pm_devvp
, de_bntodoff(pmp
, bn
), bsize
, &bp
);
836 usemap_free(pmp
, cluster
);
837 switch (pmp
->pm_fatmask
) {
839 readcn
= getushort(&bp
->b_data
[bo
]);
841 cluster
= readcn
>> 4;
843 readcn
|= MSDOSFSFREE
<< 4;
847 readcn
|= MSDOSFSFREE
& 0xfff;
849 putushort(&bp
->b_data
[bo
], readcn
);
852 cluster
= getushort(&bp
->b_data
[bo
]);
853 putushort(&bp
->b_data
[bo
], MSDOSFSFREE
);
856 cluster
= getulong(&bp
->b_data
[bo
]);
857 putulong(&bp
->b_data
[bo
],
858 (MSDOSFSFREE
& FAT32_MASK
) | (cluster
& ~FAT32_MASK
));
861 cluster
&= pmp
->pm_fatmask
;
862 if ((cluster
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
863 cluster
|= pmp
->pm_fatmask
;
866 updatefats(pmp
, bp
, bn
);
871 * Read in fat blocks looking for free clusters. For every free cluster
872 * found turn off its corresponding bit in the pm_inusemap.
875 fillinusemap(struct msdosfsmount
*pmp
)
877 struct buf
*bp
= NULL
;
880 u_long bn
, bo
, bsize
, byteoffset
;
883 * Mark all clusters in use, we mark the free ones in the fat scan
886 for (cn
= 0; cn
< (pmp
->pm_maxcluster
+ N_INUSEBITS
) / N_INUSEBITS
; cn
++)
887 pmp
->pm_inusemap
[cn
] = (u_int
)-1;
890 * Figure how many free clusters are in the filesystem by ripping
891 * through the fat counting the number of entries whose content is
892 * zero. These represent free clusters.
894 pmp
->pm_freeclustercount
= 0;
895 for (cn
= CLUST_FIRST
; cn
<= pmp
->pm_maxcluster
; cn
++) {
896 byteoffset
= FATOFS(pmp
, cn
);
897 bo
= byteoffset
% pmp
->pm_fatblocksize
;
899 /* Read new FAT block */
902 fatblock(pmp
, byteoffset
, &bn
, &bsize
, NULL
);
903 error
= bread(pmp
->pm_devvp
, de_bntodoff(pmp
, bn
), bsize
, &bp
);
910 readcn
= getulong(&bp
->b_data
[bo
]);
912 readcn
= getushort(&bp
->b_data
[bo
]);
913 if (FAT12(pmp
) && (cn
& 1))
915 readcn
&= pmp
->pm_fatmask
;
918 usemap_free(pmp
, cn
);
925 * Allocate a new cluster and chain it onto the end of the file.
927 * dep - the file to extend
928 * count - number of clusters to allocate
929 * bpp - where to return the address of the buf header for the first new
931 * ncp - where to put cluster number of the first newly allocated cluster
932 * If this pointer is 0, do not return the cluster number.
935 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
936 * the de_flag field of the denode and it does not change the de_FileSize
937 * field. This is left for the caller to do.
940 extendfile(struct denode
*dep
, u_long count
, struct buf
**bpp
, u_long
*ncp
,
946 struct msdosfsmount
*pmp
= dep
->de_pmp
;
950 * Don't try to extend the root directory
952 if (dep
->de_StartCluster
== MSDOSFSROOT
953 && (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
954 kprintf("extendfile(): attempt to extend root directory\n");
959 * If the "file's last cluster" cache entry is empty, and the file
960 * is not empty, then fill the cache entry by calling pcbmap().
963 if (dep
->de_fc
[FC_LASTFC
].fc_frcn
== FCE_EMPTY
&&
964 dep
->de_StartCluster
!= 0) {
966 error
= pcbmap(dep
, 0xffff, NULL
, &cn
, NULL
);
967 /* we expect it to return E2BIG */
974 * Allocate a new cluster chain and cat onto the end of the
975 * file. * If the file is empty we make de_StartCluster point
976 * to the new block. Note that de_StartCluster being 0 is
977 * sufficient to be sure the file is empty since we exclude
978 * attempts to extend the root directory above, and the root
979 * dir is the only file with a startcluster of 0 that has
980 * blocks allocated (sort of).
982 if (dep
->de_StartCluster
== 0)
985 cn
= dep
->de_fc
[FC_LASTFC
].fc_fsrcn
+ 1;
986 error
= clusteralloc(pmp
, cn
, count
, CLUST_EOFE
, &cn
, &got
);
993 * Give them the filesystem relative cluster number if they want
1001 if (dep
->de_StartCluster
== 0) {
1002 dep
->de_StartCluster
= cn
;
1005 error
= fatentry(FAT_SET
, pmp
,
1006 dep
->de_fc
[FC_LASTFC
].fc_fsrcn
,
1009 clusterfree(pmp
, cn
, NULL
);
1012 frcn
= dep
->de_fc
[FC_LASTFC
].fc_frcn
+ 1;
1016 * Update the "last cluster of the file" entry in the
1017 * denode's fat cache.
1019 fc_setcache(dep
, FC_LASTFC
, frcn
+ got
- 1, cn
+ got
- 1);
1021 if (flags
& DE_CLEAR
) {
1024 * Get the buf header for the new block of the file.
1026 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
1027 bp
= getblk(pmp
->pm_devvp
,
1029 pmp
->pm_bpcluster
, 0, 0);
1034 bp
= getblk(DETOV(dep
),
1035 de_cn2doff(pmp
, frcn
),
1036 pmp
->pm_bpcluster
, 0, 0);
1039 * Do the bmap now, as in msdosfs_write
1042 de_bn2cn(pmp
, de_off2bn(pmp
, bp
->b_bio1
.bio_offset
)),
1043 &dblkno
, NULL
, NULL
)) {
1044 bp
->b_bio2
.bio_offset
= NOOFFSET
;
1046 bp
->b_bio2
.bio_offset
= de_bntodoff(pmp
, dblkno
);
1048 if (bp
->b_bio2
.bio_offset
== NOOFFSET
)
1049 panic("extendfile: pcbmap");