xref: /freebsd/sys/fs/msdosfs/msdosfs_fat.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
1 /*	$Id: msdosfs_fat.c,v 1.9 1995/11/07 14:06:42 phk Exp $ */
2 /*	$NetBSD: msdosfs_fat.c,v 1.12 1994/08/21 18:44:04 ws Exp $	*/
3 
4 /*-
5  * Copyright (C) 1994 Wolfgang Solfrank.
6  * Copyright (C) 1994 TooLs GmbH.
7  * All rights reserved.
8  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by TooLs GmbH.
21  * 4. The name of TooLs GmbH may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /*
36  * Written by Paul Popelka (paulp@uts.amdahl.com)
37  *
38  * You can do anything you want with this software, just don't say you wrote
39  * it, and don't remove this notice.
40  *
41  * This software is provided "as is".
42  *
43  * The author supplies this software to be publicly redistributed on the
44  * understanding that the author is not responsible for the correct
45  * functioning of this software in any circumstances and is not liable for
46  * any damages caused by this software.
47  *
48  * October 1992
49  */
50 
51 /*
52  * kernel include files.
53  */
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/buf.h>
57 #include <sys/file.h>
58 #include <sys/namei.h>
59 #include <sys/mount.h>		/* to define statfs structure */
60 #include <sys/vnode.h>		/* to define vattr structure */
61 #include <sys/errno.h>
62 
63 /*
64  * msdosfs include files.
65  */
66 #include <msdosfs/bpb.h>
67 #include <msdosfs/msdosfsmount.h>
68 #include <msdosfs/direntry.h>
69 #include <msdosfs/denode.h>
70 #include <msdosfs/fat.h>
71 
72 /*
73  * Fat cache stats.
74  */
75 int fc_fileextends;		/* # of file extends			 */
76 int fc_lfcempty;		/* # of time last file cluster cache entry
77 				 * was empty */
78 int fc_bmapcalls;		/* # of times pcbmap was called		 */
79 
80 #define	LMMAX	20
81 int fc_lmdistance[LMMAX];	/* counters for how far off the last
82 				 * cluster mapped entry was. */
83 int fc_largedistance;		/* off by more than LMMAX		 */
84 
85 /* Byte offset in FAT on filesystem pmp, cluster cn */
86 #define	FATOFS(pmp, cn)	(FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
87 
88 static int	chainalloc __P((struct msdosfsmount *pmp, u_long start,
89 				u_long count, u_long fillwith,
90 				u_long *retcluster, u_long *got));
91 static int	chainlength __P((struct msdosfsmount *pmp, u_long start,
92 				 u_long count));
93 static void	fatblock __P((struct msdosfsmount *pmp, u_long ofs,
94 			      u_long *bnp, u_long *sizep, u_long *bop));
95 static int	fatchain __P((struct msdosfsmount *pmp, u_long start,
96 			      u_long count, u_long fillwith));
97 static void	fc_lookup __P((struct denode *dep, u_long findcn,
98 			       u_long *frcnp, u_long *fsrcnp));
99 static void	updatefats __P((struct msdosfsmount *pmp, struct buf *bp,
100 				u_long fatbn));
101 static void	usemap_alloc __P((struct msdosfsmount *pmp, u_long cn));
102 static void	usemap_free __P((struct msdosfsmount *pmp, u_long cn));
103 
104 static void
105 fatblock(pmp, ofs, bnp, sizep, bop)
106 	struct msdosfsmount *pmp;
107 	u_long ofs;
108 	u_long *bnp;
109 	u_long *sizep;
110 	u_long *bop;
111 {
112 	u_long bn, size;
113 
114 	bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
115 	size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
116 	    * pmp->pm_BytesPerSec;
117 	bn += pmp->pm_fatblk;
118 	if (bnp)
119 		*bnp = bn;
120 	if (sizep)
121 		*sizep = size;
122 	if (bop)
123 		*bop = ofs % pmp->pm_fatblocksize;
124 }
125 
126 /*
127  * Map the logical cluster number of a file into a physical disk sector
128  * that is filesystem relative.
129  *
130  * dep	  - address of denode representing the file of interest
131  * findcn - file relative cluster whose filesystem relative cluster number
132  *	    and/or block number are/is to be found
133  * bnp	  - address of where to place the file system relative block number.
134  *	    If this pointer is null then don't return this quantity.
135  * cnp	  - address of where to place the file system relative cluster number.
136  *	    If this pointer is null then don't return this quantity.
137  *
138  * NOTE: Either bnp or cnp must be non-null.
139  * This function has one side effect.  If the requested file relative cluster
140  * is beyond the end of file, then the actual number of clusters in the file
141  * is returned in *cnp.  This is useful for determining how long a directory is.
142  *  If cnp is null, nothing is returned.
143  */
144 int
145 pcbmap(dep, findcn, bnp, cnp)
146 	struct denode *dep;
147 	u_long findcn;		/* file relative cluster to get		 */
148 	daddr_t *bnp;		/* returned filesys relative blk number	 */
149 	u_long *cnp;		/* returned cluster number		 */
150 {
151 	int error;
152 	u_long i;
153 	u_long cn;
154 	u_long prevcn;
155 	u_long byteoffset;
156 	u_long bn;
157 	u_long bo;
158 	struct buf *bp = NULL;
159 	u_long bp_bn = -1;
160 	struct msdosfsmount *pmp = dep->de_pmp;
161 	u_long bsize;
162 	int fat12 = FAT12(pmp);	/* 12 bit fat	 */
163 
164 	fc_bmapcalls++;
165 
166 	/*
167 	 * If they don't give us someplace to return a value then don't
168 	 * bother doing anything.
169 	 */
170 	if (bnp == NULL && cnp == NULL)
171 		return 0;
172 
173 	cn = dep->de_StartCluster;
174 	/*
175 	 * The "file" that makes up the root directory is contiguous,
176 	 * permanently allocated, of fixed size, and is not made up of
177 	 * clusters.  If the cluster number is beyond the end of the root
178 	 * directory, then return the number of clusters in the file.
179 	 */
180 	if (cn == MSDOSFSROOT) {
181 		if (dep->de_Attributes & ATTR_DIRECTORY) {
182 			if (findcn * pmp->pm_SectPerClust >= pmp->pm_rootdirsize) {
183 				if (cnp)
184 					*cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
185 				return E2BIG;
186 			}
187 			if (bnp)
188 				*bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
189 			if (cnp)
190 				*cnp = MSDOSFSROOT;
191 			return 0;
192 		} else {		/* just an empty file */
193 			if (cnp)
194 				*cnp = 0;
195 			return E2BIG;
196 		}
197 	}
198 
199 	/*
200 	 * Rummage around in the fat cache, maybe we can avoid tromping
201 	 * thru every fat entry for the file. And, keep track of how far
202 	 * off the cache was from where we wanted to be.
203 	 */
204 	i = 0;
205 	fc_lookup(dep, findcn, &i, &cn);
206 	if ((bn = findcn - i) >= LMMAX)
207 		fc_largedistance++;
208 	else
209 		fc_lmdistance[bn]++;
210 
211 	/*
212 	 * Handle all other files or directories the normal way.
213 	 */
214 	prevcn = 0;
215 	for (; i < findcn; i++) {
216 		if (MSDOSFSEOF(cn))
217 			goto hiteof;
218 		byteoffset = FATOFS(pmp, cn);
219 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
220 		if (bn != bp_bn) {
221 			if (bp)
222 				brelse(bp);
223 			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
224 			if (error)
225 				return error;
226 			bp_bn = bn;
227 		}
228 		prevcn = cn;
229 		cn = getushort(&bp->b_data[bo]);
230 		if (fat12) {
231 			if (prevcn & 1)
232 				cn >>= 4;
233 			cn &= 0x0fff;
234 			/*
235 			 * Force the special cluster numbers in the range
236 			 * 0x0ff0-0x0fff to be the same as for 16 bit
237 			 * cluster numbers to let the rest of msdosfs think
238 			 * it is always dealing with 16 bit fats.
239 			 */
240 			if ((cn & 0x0ff0) == 0x0ff0)
241 				cn |= 0xf000;
242 		}
243 	}
244 
245 	if (!MSDOSFSEOF(cn)) {
246 		if (bp)
247 			brelse(bp);
248 		if (bnp)
249 			*bnp = cntobn(pmp, cn);
250 		if (cnp)
251 			*cnp = cn;
252 		fc_setcache(dep, FC_LASTMAP, i, cn);
253 		return 0;
254 	}
255 
256 hiteof:;
257 	if (cnp)
258 		*cnp = i;
259 	if (bp)
260 		brelse(bp);
261 	/* update last file cluster entry in the fat cache */
262 	fc_setcache(dep, FC_LASTFC, i - 1, prevcn);
263 	return E2BIG;
264 }
265 
266 /*
267  * Find the closest entry in the fat cache to the cluster we are looking
268  * for.
269  */
270 static void
271 fc_lookup(dep, findcn, frcnp, fsrcnp)
272 	struct denode *dep;
273 	u_long findcn;
274 	u_long *frcnp;
275 	u_long *fsrcnp;
276 {
277 	int i;
278 	u_long cn;
279 	struct fatcache *closest = 0;
280 
281 	for (i = 0; i < FC_SIZE; i++) {
282 		cn = dep->de_fc[i].fc_frcn;
283 		if (cn != FCE_EMPTY && cn <= findcn) {
284 			if (closest == 0 || cn > closest->fc_frcn)
285 				closest = &dep->de_fc[i];
286 		}
287 	}
288 	if (closest) {
289 		*frcnp = closest->fc_frcn;
290 		*fsrcnp = closest->fc_fsrcn;
291 	}
292 }
293 
294 /*
295  * Purge the fat cache in denode dep of all entries relating to file
296  * relative cluster frcn and beyond.
297  */
298 void fc_purge(dep, frcn)
299 	struct denode *dep;
300 	u_int frcn;
301 {
302 	int i;
303 	struct fatcache *fcp;
304 
305 	fcp = dep->de_fc;
306 	for (i = 0; i < FC_SIZE; i++, fcp++) {
307 		if (fcp->fc_frcn >= frcn)
308 			fcp->fc_frcn = FCE_EMPTY;
309 	}
310 }
311 
312 /*
313  * Update all copies of the fat. The first copy is updated last.
314  *
315  * pmp	 - msdosfsmount structure for filesystem to update
316  * bp	 - addr of modified fat block
317  * fatbn - block number relative to begin of filesystem of the modified fat block.
318  */
319 static void
320 updatefats(pmp, bp, fatbn)
321 	struct msdosfsmount *pmp;
322 	struct buf *bp;
323 	u_long fatbn;
324 {
325 	int i;
326 	struct buf *bpn;
327 
328 #ifdef MSDOSFS_DEBUG
329 	printf("updatefats(pmp %p, bp %p, fatbn %ld)\n", pmp, bp, fatbn);
330 #endif
331 
332 	/*
333 	 * Now copy the block(s) of the modified fat to the other copies of
334 	 * the fat and write them out.  This is faster than reading in the
335 	 * other fats and then writing them back out.  This could tie up
336 	 * the fat for quite a while. Preventing others from accessing it.
337 	 * To prevent us from going after the fat quite so much we use
338 	 * delayed writes, unless they specfied "synchronous" when the
339 	 * filesystem was mounted.  If synch is asked for then use
340 	 * bwrite()'s and really slow things down.
341 	 */
342 	for (i = 1; i < pmp->pm_FATs; i++) {
343 		fatbn += pmp->pm_FATsecs;
344 		/* getblk() never fails */
345 		bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, 0, 0);
346 		bcopy(bp->b_data, bpn->b_data, bp->b_bcount);
347 		if (pmp->pm_waitonfat)
348 			bwrite(bpn);
349 		else
350 			bdwrite(bpn);
351 	}
352 	/*
353 	 * Write out the first fat last.
354 	 */
355 	if (pmp->pm_waitonfat)
356 		bwrite(bp);
357 	else
358 		bdwrite(bp);
359 }
360 
361 /*
362  * Updating entries in 12 bit fats is a pain in the butt.
363  *
364  * The following picture shows where nibbles go when moving from a 12 bit
365  * cluster number into the appropriate bytes in the FAT.
366  *
367  *	byte m        byte m+1      byte m+2
368  *	+----+----+   +----+----+   +----+----+
369  *	|  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
370  *	+----+----+   +----+----+   +----+----+
371  *
372  *	+----+----+----+   +----+----+----+
373  *	|  3    0    1 |   |  4    5    2 |
374  *	+----+----+----+   +----+----+----+
375  *	cluster n  	   cluster n+1
376  *
377  * Where n is even. m = n + (n >> 2)
378  *
379  */
380 static inline void
381 usemap_alloc(pmp, cn)
382 	struct msdosfsmount *pmp;
383 	u_long cn;
384 {
385 	pmp->pm_inusemap[cn / N_INUSEBITS]
386 			 |= 1 << (cn % N_INUSEBITS);
387 	pmp->pm_freeclustercount--;
388 }
389 
390 static inline void
391 usemap_free(pmp, cn)
392 	struct msdosfsmount *pmp;
393 	u_long cn;
394 {
395 	pmp->pm_freeclustercount++;
396 	pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
397 }
398 
399 int
400 clusterfree(pmp, cluster, oldcnp)
401 	struct msdosfsmount *pmp;
402 	u_long cluster;
403 	u_long *oldcnp;
404 {
405 	int error;
406 	u_long oldcn;
407 
408 	error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
409 	if (error == 0) {
410 		/*
411 		 * If the cluster was successfully marked free, then update
412 		 * the count of free clusters, and turn off the "allocated"
413 		 * bit in the "in use" cluster bit map.
414 		 */
415 		usemap_free(pmp, cluster);
416 		if (oldcnp)
417 			*oldcnp = oldcn;
418 	}
419 	return error;
420 }
421 
422 /*
423  * Get or Set or 'Get and Set' the cluster'th entry in the fat.
424  *
425  * function	- whether to get or set a fat entry
426  * pmp		- address of the msdosfsmount structure for the filesystem
427  *		  whose fat is to be manipulated.
428  * cn		- which cluster is of interest
429  * oldcontents	- address of a word that is to receive the contents of the
430  *		  cluster'th entry if this is a get function
431  * newcontents	- the new value to be written into the cluster'th element of
432  *		  the fat if this is a set function.
433  *
434  * This function can also be used to free a cluster by setting the fat entry
435  * for a cluster to 0.
436  *
437  * All copies of the fat are updated if this is a set function. NOTE: If
438  * fatentry() marks a cluster as free it does not update the inusemap in
439  * the msdosfsmount structure. This is left to the caller.
440  */
441 int
442 fatentry(function, pmp, cn, oldcontents, newcontents)
443 	int function;
444 	struct msdosfsmount *pmp;
445 	u_long cn;
446 	u_long *oldcontents;
447 	u_long newcontents;
448 {
449 	int error;
450 	u_long readcn;
451 	u_long bn, bo, bsize, byteoffset;
452 	struct buf *bp;
453 
454 	/*
455 	 * printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
456 	 *	  function, pmp, cluster, oldcontents, newcontents);
457 	 */
458 
459 #ifdef DIAGNOSTIC
460 	/*
461 	 * Be sure they asked us to do something.
462 	 */
463 	if ((function & (FAT_SET | FAT_GET)) == 0) {
464 		printf("fatentry(): function code doesn't specify get or set\n");
465 		return EINVAL;
466 	}
467 
468 	/*
469 	 * If they asked us to return a cluster number but didn't tell us
470 	 * where to put it, give them an error.
471 	 */
472 	if ((function & FAT_GET) && oldcontents == NULL) {
473 		printf("fatentry(): get function with no place to put result\n");
474 		return EINVAL;
475 	}
476 #endif
477 
478 	/*
479 	 * Be sure the requested cluster is in the filesystem.
480 	 */
481 	if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
482 		return EINVAL;
483 
484 	byteoffset = FATOFS(pmp, cn);
485 	fatblock(pmp, byteoffset, &bn, &bsize, &bo);
486 	error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
487 	if (error)
488 		return error;
489 
490 	if (function & FAT_GET) {
491 		readcn = getushort(&bp->b_data[bo]);
492 		if (FAT12(pmp)) {
493 			if (cn & 1)
494 				readcn >>= 4;
495 			readcn &= 0x0fff;
496 			/* map certain 12 bit fat entries to 16 bit */
497 			if ((readcn & 0x0ff0) == 0x0ff0)
498 				readcn |= 0xf000;
499 		}
500 		*oldcontents = readcn;
501 	}
502 	if (function & FAT_SET) {
503 		if (FAT12(pmp)) {
504 			readcn = getushort(&bp->b_data[bo]);
505 			if (cn & 1) {
506 				readcn &= 0x000f;
507 				readcn |= newcontents << 4;
508 			} else {
509 				readcn &= 0xf000;
510 				readcn |= newcontents & 0xfff;
511 			}
512 			putushort(&bp->b_data[bo], readcn);
513 		} else
514 			putushort(&bp->b_data[bo], newcontents);
515 		updatefats(pmp, bp, bn);
516 		bp = NULL;
517 		pmp->pm_fmod = 1;
518 	}
519 	if (bp)
520 		brelse(bp);
521 	return 0;
522 }
523 
524 /*
525  * Update a contiguous cluster chain
526  *
527  * pmp	    - mount point
528  * start    - first cluster of chain
529  * count    - number of clusters in chain
530  * fillwith - what to write into fat entry of last cluster
531  */
532 static int
533 fatchain(pmp, start, count, fillwith)
534 	struct msdosfsmount *pmp;
535 	u_long start;
536 	u_long count;
537 	u_long fillwith;
538 {
539 	int error;
540 	u_long bn, bo, bsize, byteoffset, readcn, newc;
541 	struct buf *bp;
542 
543 #ifdef MSDOSFS_DEBUG
544 	printf("fatchain(pmp %p, start %ld, count %ld, fillwith %ld)\n",
545 	       pmp, start, count, fillwith);
546 #endif
547 	/*
548 	 * Be sure the clusters are in the filesystem.
549 	 */
550 	if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
551 		return EINVAL;
552 
553 	while (count > 0) {
554 		byteoffset = FATOFS(pmp, start);
555 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
556 		error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
557 		if (error)
558 			return error;
559 		while (count > 0) {
560 			start++;
561 			newc = --count > 0 ? start : fillwith;
562 			if (FAT12(pmp)) {
563 				readcn = getushort(&bp->b_data[bo]);
564 				if (start & 1) {
565 					readcn &= 0xf000;
566 					readcn |= newc & 0xfff;
567 				} else {
568 					readcn &= 0x000f;
569 					readcn |= newc << 4;
570 				}
571 				putushort(&bp->b_data[bo], readcn);
572 				bo++;
573 				if (!(start & 1))
574 					bo++;
575 			} else {
576 				putushort(&bp->b_data[bo], newc);
577 				bo += 2;
578 			}
579 			if (bo >= bsize)
580 				break;
581 		}
582 		updatefats(pmp, bp, bn);
583 	}
584 	pmp->pm_fmod = 1;
585 	return 0;
586 }
587 
588 /*
589  * Check the length of a free cluster chain starting at start.
590  *
591  * pmp	 - mount point
592  * start - start of chain
593  * count - maximum interesting length
594  */
595 static int
596 chainlength(pmp, start, count)
597 	struct msdosfsmount *pmp;
598 	u_long start;
599 	u_long count;
600 {
601 	u_long idx, max_idx;
602 	u_int map;
603 	u_long len;
604 
605 	max_idx = pmp->pm_maxcluster / N_INUSEBITS;
606 	idx = start / N_INUSEBITS;
607 	start %= N_INUSEBITS;
608 	map = pmp->pm_inusemap[idx];
609 	map &= ~((1 << start) - 1);
610 	if (map) {
611 		len = ffs(map) - 1 - start;
612 		return len > count ? count : len;
613 	}
614 	len = N_INUSEBITS - start;
615 	if (len >= count)
616 		return count;
617 	while (++idx <= max_idx) {
618 		if (len >= count)
619 			break;
620 		map = pmp->pm_inusemap[idx];
621 		if (map) {
622 			len +=  ffs(map) - 1;
623 			break;
624 		}
625 		len += N_INUSEBITS;
626 	}
627 	return len > count ? count : len;
628 }
629 
630 /*
631  * Allocate contigous free clusters.
632  *
633  * pmp	      - mount point.
634  * start      - start of cluster chain.
635  * count      - number of clusters to allocate.
636  * fillwith   - put this value into the fat entry for the
637  *		last allocated cluster.
638  * retcluster - put the first allocated cluster's number here.
639  * got	      - how many clusters were actually allocated.
640  */
641 static int
642 chainalloc(pmp, start, count, fillwith, retcluster, got)
643 	struct msdosfsmount *pmp;
644 	u_long start;
645 	u_long count;
646 	u_long fillwith;
647 	u_long *retcluster;
648 	u_long *got;
649 {
650 	int error;
651 
652 	error = fatchain(pmp, start, count, fillwith);
653 	if (error == 0) {
654 #ifdef MSDOSFS_DEBUG
655 		printf("clusteralloc(): allocated cluster chain at %ld (%ld clusters)\n",
656 		       start, count);
657 #endif
658 		if (retcluster)
659 			*retcluster = start;
660 		if (got)
661 			*got = count;
662 		while (count-- > 0)
663 			usemap_alloc(pmp, start++);
664 	}
665 	return error;
666 }
667 
668 /*
669  * Allocate contiguous free clusters.
670  *
671  * pmp	      - mount point.
672  * start      - preferred start of cluster chain.
673  * count      - number of clusters requested.
674  * fillwith   - put this value into the fat entry for the
675  *		last allocated cluster.
676  * retcluster - put the first allocated cluster's number here.
677  * got	      - how many clusters were actually allocated.
678  */
679 int
680 clusteralloc(pmp, start, count, fillwith, retcluster, got)
681 	struct msdosfsmount *pmp;
682 	u_long start;
683 	u_long count;
684 	u_long fillwith;
685 	u_long *retcluster;
686 	u_long *got;
687 {
688 	u_long idx;
689 	u_long len, newst, foundcn, foundl, cn, l;
690 	u_int map;
691 
692 #ifdef MSDOSFS_DEBUG
693 	printf("clusteralloc(): find %d clusters\n",count);
694 #endif
695 	if (start) {
696 		if ((len = chainlength(pmp, start, count)) >= count)
697 			return chainalloc(pmp, start, count, fillwith, retcluster, got);
698 	} else {
699 		/*
700 		 * This is a new file, initialize start
701 		 */
702 		struct timeval tv;
703 
704 		microtime(&tv);
705 		start = (tv.tv_usec >> 10)|tv.tv_usec;
706 		len = 0;
707 	}
708 
709 	/*
710 	 * Start at a (pseudo) random place to maximize cluster runs
711 	 * under multiple writers.
712 	 */
713 	foundcn = newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
714 	foundl = 0;
715 
716 	for (cn = newst; cn <= pmp->pm_maxcluster;) {
717 		idx = cn / N_INUSEBITS;
718 		map = pmp->pm_inusemap[idx];
719 		map |= (1 << (cn % N_INUSEBITS)) - 1;
720 		if (map != (u_int)-1) {
721 			cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
722 			if ((l = chainlength(pmp, cn, count)) >= count)
723 				return chainalloc(pmp, cn, count, fillwith, retcluster, got);
724 			if (l > foundl) {
725 				foundcn = cn;
726 				foundl = l;
727 			}
728 			cn += l + 1;
729 			continue;
730 		}
731 		cn += N_INUSEBITS - cn % N_INUSEBITS;
732 	}
733 	for (cn = 0; cn < newst;) {
734 		idx = cn / N_INUSEBITS;
735 		map = pmp->pm_inusemap[idx];
736 		map |= (1 << (cn % N_INUSEBITS)) - 1;
737 		if (map != (u_int)-1) {
738 			cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
739 			if ((l = chainlength(pmp, cn, count)) >= count)
740 				return chainalloc(pmp, cn, count, fillwith, retcluster, got);
741 			if (l > foundl) {
742 				foundcn = cn;
743 				foundl = l;
744 			}
745 			cn += l + 1;
746 			continue;
747 		}
748 		cn += N_INUSEBITS - cn % N_INUSEBITS;
749 	}
750 
751 	if (!foundl)
752 		return ENOSPC;
753 
754 	if (len)
755 		return chainalloc(pmp, start, len, fillwith, retcluster, got);
756 	else
757 		return chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got);
758 }
759 
760 
761 /*
762  * Free a chain of clusters.
763  *
764  * pmp		- address of the msdosfs mount structure for the filesystem
765  *		  containing the cluster chain to be freed.
766  * startcluster - number of the 1st cluster in the chain of clusters to be
767  *		  freed.
768  */
769 int
770 freeclusterchain(pmp, cluster)
771 	struct msdosfsmount *pmp;
772 	u_long cluster;
773 {
774 	int error = 0;
775 	struct buf *bp = NULL;
776 	u_long bn, bo, bsize, byteoffset;
777 	u_long readcn, lbn = -1;
778 
779 	while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) {
780 		byteoffset = FATOFS(pmp, cluster);
781 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
782 		if (lbn != bn) {
783 			if (bp)
784 				updatefats(pmp, bp, lbn);
785 			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
786 			if (error)
787 				return error;
788 			lbn = bn;
789 		}
790 		usemap_free(pmp, cluster);
791 		readcn = getushort(&bp->b_data[bo]);
792 		if (FAT12(pmp)) {
793 			if (cluster & 1) {
794 				cluster = readcn >> 4;
795 				readcn &= 0x000f;
796 				readcn |= MSDOSFSFREE << 4;
797 			} else {
798 				cluster = readcn;
799 				readcn &= 0xf000;
800 				readcn |= MSDOSFSFREE & 0xfff;
801 			}
802 			putushort(&bp->b_data[bo], readcn);
803 			cluster &= 0x0fff;
804 			if ((cluster&0x0ff0) == 0x0ff0)
805 				cluster |= 0xf000;
806 		} else {
807 			cluster = readcn;
808 			putushort(&bp->b_data[bo], MSDOSFSFREE);
809 		}
810 	}
811 	if (bp)
812 		updatefats(pmp, bp, bn);
813 	return error;
814 }
815 
816 /*
817  * Read in fat blocks looking for free clusters. For every free cluster
818  * found turn off its corresponding bit in the pm_inusemap.
819  */
820 int
821 fillinusemap(pmp)
822 	struct msdosfsmount *pmp;
823 {
824 	struct buf *bp = NULL;
825 	u_long cn, readcn;
826 	int error;
827 	int fat12 = FAT12(pmp);
828 	u_long bn, bo, bsize, byteoffset;
829 
830 	/*
831 	 * Mark all clusters in use, we mark the free ones in the fat scan
832 	 * loop further down.
833 	 */
834 	for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++)
835 		pmp->pm_inusemap[cn] = (u_int)-1;
836 
837 	/*
838 	 * Figure how many free clusters are in the filesystem by ripping
839 	 * through the fat counting the number of entries whose content is
840 	 * zero.  These represent free clusters.
841 	 */
842 	pmp->pm_freeclustercount = 0;
843 	for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
844 		byteoffset = FATOFS(pmp, cn);
845 		bo = byteoffset % pmp->pm_fatblocksize;
846 		if (!bo || !bp) {
847 			/* Read new FAT block */
848 			if (bp)
849 				brelse(bp);
850 			fatblock(pmp, byteoffset, &bn, &bsize, NULL);
851 			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
852 			if (error)
853 				return error;
854 		}
855 		readcn = getushort(&bp->b_data[bo]);
856 		if (fat12) {
857 			if (cn & 1)
858 				readcn >>= 4;
859 			readcn &= 0x0fff;
860 		}
861 
862 		if (readcn == 0)
863 			usemap_free(pmp, cn);
864 	}
865 	brelse(bp);
866 	return 0;
867 }
868 
869 /*
870  * Allocate a new cluster and chain it onto the end of the file.
871  *
872  * dep	 - the file to extend
873  * count - number of clusters to allocate
874  * bpp	 - where to return the address of the buf header for the first new
875  *	   file block
876  * ncp	 - where to put cluster number of the first newly allocated cluster
877  *	   If this pointer is 0, do not return the cluster number.
878  * flags - see fat.h
879  *
880  * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
881  * the de_flag field of the denode and it does not change the de_FileSize
882  * field.  This is left for the caller to do.
883  */
884 int
885 extendfile(dep, count, bpp, ncp, flags)
886 	struct denode *dep;
887 	u_long count;
888 	struct buf **bpp;
889 	u_long *ncp;
890 	int flags;
891 {
892 	int error = 0;
893 	u_long frcn;
894 	u_long cn, got;
895 	struct msdosfsmount *pmp = dep->de_pmp;
896 	struct buf *bp;
897 
898 	/*
899 	 * Don't try to extend the root directory
900 	 */
901 	if (DETOV(dep)->v_flag & VROOT) {
902 		printf("extendfile(): attempt to extend root directory\n");
903 		return ENOSPC;
904 	}
905 
906 	/*
907 	 * If the "file's last cluster" cache entry is empty, and the file
908 	 * is not empty, then fill the cache entry by calling pcbmap().
909 	 */
910 	fc_fileextends++;
911 	if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
912 	    dep->de_StartCluster != 0) {
913 		fc_lfcempty++;
914 		error = pcbmap(dep, 0xffff, 0, &cn);
915 		/* we expect it to return E2BIG */
916 		if (error != E2BIG)
917 			return error;
918 		error = 0;
919 	}
920 
921 	while (count > 0) {
922 		/*
923 		 * Allocate a new cluster chain and cat onto the end of the file.
924 		 * If the file is empty we make de_StartCluster point to the new
925 		 * block.  Note that de_StartCluster being 0 is sufficient to be
926 		 * sure the file is empty since we exclude attempts to extend the
927 		 * root directory above, and the root dir is the only file with a
928 		 * startcluster of 0 that has blocks allocated (sort of).
929 		 */
930 		if (dep->de_StartCluster == 0)
931 			cn = 0;
932 		else
933 			cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
934 		error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got);
935 		if (error)
936 			return error;
937 
938 		count -= got;
939 
940 		/*
941 		 * Give them the filesystem relative cluster number if they want
942 		 * it.
943 		 */
944 		if (ncp) {
945 			*ncp = cn;
946 			ncp = NULL;
947 		}
948 
949 		if (dep->de_StartCluster == 0) {
950 			dep->de_StartCluster = cn;
951 			frcn = 0;
952 		} else {
953 			error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
954 					 0, cn);
955 			if (error) {
956 				clusterfree(pmp, cn, NULL);
957 				return error;
958 			}
959 
960 			frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
961 		}
962 
963 		/*
964 		 * Update the "last cluster of the file" entry in the denode's fat
965 		 * cache.
966 		 */
967 		fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1);
968 
969 		if (flags & DE_CLEAR) {
970 			while (got-- > 0) {
971 				/*
972 				 * Get the buf header for the new block of the file.
973 				 */
974 				if (dep->de_Attributes & ATTR_DIRECTORY)
975 					bp = getblk(pmp->pm_devvp, cntobn(pmp, cn++),
976 						    pmp->pm_bpcluster, 0, 0);
977 				else {
978 					bp = getblk(DETOV(dep), frcn++, pmp->pm_bpcluster, 0, 0);
979 					/*
980 					 * Do the bmap now, as in msdosfs_write
981 					 */
982 					if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
983 						bp->b_blkno = -1;
984 					if (bp->b_blkno == -1)
985 						panic("extendfile: pcbmap");
986 				}
987 				clrbuf(bp);
988 				if (bpp) {
989 					*bpp = bp;
990 					bpp = NULL;
991 				} else {
992 					bp->b_flags |= B_AGE;
993 					bawrite(bp);
994 				}
995 			}
996 		}
997 	}
998 
999 	return 0;
1000 }
1001