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