22b29eda2f89d82df66d56f0866e4bc714ee5536
[dragonfly.git] / sys / vfs / msdosfs / msdosfs_fat.c
1 /* $FreeBSD: src/sys/msdosfs/msdosfs_fat.c,v 1.23 2000/01/27 14:43:06 nyan Exp $ */
2 /*      $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $      */
3
4 /*-
5  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6  * Copyright (C) 1994, 1995, 1997 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/mount.h>          /* to define statfs structure */
58 #include <sys/vnode.h>          /* to define vattr structure */
59
60 #include <sys/buf2.h>
61
62 /*
63  * msdosfs include files.
64  */
65 #include "bpb.h"
66 #include "msdosfsmount.h"
67 #include "direntry.h"
68 #include "denode.h"
69 #include "fat.h"
70
71 /*
72  * Fat cache stats.
73  */
74 static int fc_fileextends;      /* # of file extends                     */
75 static int fc_lfcempty;         /* # of time last file cluster cache entry
76                                  * was empty */
77 static int fc_bmapcalls;        /* # of times pcbmap was called          */
78
79 #define LMMAX   20
80 static int fc_lmdistance[LMMAX];/* counters for how far off the last
81                                  * cluster mapped entry was. */
82 static int fc_largedistance;    /* off by more than LMMAX                */
83
84 static void fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp,
85     u_long *fsrcnp);
86
87 /*
88  * Given a byte offset `ofs` within FAT, return block number in backing device,
89  * block size, and byte offset within a block in FAT.
90  */
91 static void
92 fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep,
93          u_long *bop)
94 {
95         u_long bn, size;
96
97         bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
98         size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) * DEV_BSIZE;
99         bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs;
100
101         if (bnp)
102                 *bnp = bn;
103         if (sizep)
104                 *sizep = size;
105         if (bop)
106                 *bop = ofs % pmp->pm_fatblocksize;
107 }
108
109 /*
110  * Map the logical cluster number of a file into a physical disk sector
111  * that is filesystem relative.
112  *
113  * dep    - address of denode representing the file of interest
114  * findcn - file relative cluster whose filesystem relative cluster number
115  *          and/or block number are/is to be found
116  * bnp    - address of where to place the file system relative block number.
117  *          If this pointer is null then don't return this quantity.
118  * cnp    - address of where to place the file system relative cluster number.
119  *          If this pointer is null then don't return this quantity.
120  *
121  * NOTE: Either bnp or cnp must be non-null.
122  * This function has one side effect.  If the requested file relative cluster
123  * is beyond the end of file, then the actual number of clusters in the file
124  * is returned in *cnp.  This is useful for determining how long a directory is.
125  *  If cnp is null, nothing is returned.
126  */
127 int
128 pcbmap(struct denode *dep,
129        u_long findcn,           /* file relative cluster to get          */
130        daddr_t *bnp,            /* returned filesys relative blk number  */
131        u_long *cnp,             /* returned cluster number               */
132        int *sp)                 /* returned block size           */
133 {
134         int error;
135         u_long i;
136         u_long cn;
137         u_long prevcn = 0; /* XXX: prevcn could be used unititialized */
138         u_long byteoffset;
139         u_long bn;
140         u_long bo;
141         struct buf *bp = NULL;
142         u_long bp_bn = -1;
143         struct msdosfsmount *pmp = dep->de_pmp;
144         u_long bsize;
145
146         fc_bmapcalls++;
147
148         /*
149          * If they don't give us someplace to return a value then don't
150          * bother doing anything.
151          */
152         if (bnp == NULL && cnp == NULL && sp == NULL)
153                 return (0);
154
155         cn = dep->de_StartCluster;
156         /*
157          * The "file" that makes up the root directory is contiguous,
158          * permanently allocated, of fixed size, and is not made up of
159          * clusters.  If the cluster number is beyond the end of the root
160          * directory, then return the number of clusters in the file.
161          */
162         if (cn == MSDOSFSROOT) {
163                 if (dep->de_Attributes & ATTR_DIRECTORY) {
164                         if (de_cn2off(pmp, findcn) >= dep->de_FileSize) {
165                                 if (cnp)
166                                         *cnp = de_bn2cn(pmp,
167                                                         pmp->pm_rootdirsize);
168                                 return (E2BIG);
169                         }
170                         if (bnp)
171                                 *bnp = pmp->pm_rootdirblk +
172                                         de_cn2bn(pmp, findcn);
173                         if (cnp)
174                                 *cnp = MSDOSFSROOT;
175                         if (sp)
176                                 *sp = min(pmp->pm_bpcluster,
177                                     dep->de_FileSize - de_cn2off(pmp, findcn));
178                         return (0);
179                 } else {                /* just an empty file */
180                         if (cnp)
181                                 *cnp = 0;
182                         return (E2BIG);
183                 }
184         }
185
186         /*
187          * All other files do I/O in cluster sized blocks
188          */
189         if (sp)
190                 *sp = pmp->pm_bpcluster;
191
192         /*
193          * Rummage around in the fat cache, maybe we can avoid tromping
194          * thru every fat entry for the file. And, keep track of how far
195          * off the cache was from where we wanted to be.
196          */
197         i = 0;
198         fc_lookup(dep, findcn, &i, &cn);
199         if ((bn = findcn - i) >= LMMAX)
200                 fc_largedistance++;
201         else
202                 fc_lmdistance[bn]++;
203
204         /*
205          * Handle all other files or directories the normal way.
206          */
207         for (; i < findcn; i++) {
208                 /*
209                  * Stop with all reserved clusters, not just with EOF.
210                  */
211                 if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
212                         goto hiteof;
213                 byteoffset = FATOFS(pmp, cn);
214                 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
215                 if (bn != bp_bn) {
216                         if (bp)
217                                 brelse(bp);
218                         error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn),
219                                       bsize, &bp);
220                         if (error) {
221                                 brelse(bp);
222                                 return (error);
223                         }
224                         bp_bn = bn;
225                 }
226                 prevcn = cn;
227                 if (FAT32(pmp))
228                         cn = getulong(&bp->b_data[bo]);
229                 else
230                         cn = getushort(&bp->b_data[bo]);
231                 if (FAT12(pmp) && (prevcn & 1))
232                         cn >>= 4;
233                 cn &= pmp->pm_fatmask;
234
235                 /*
236                  * Force the special cluster numbers
237                  * to be the same for all cluster sizes
238                  * to let the rest of msdosfs handle
239                  * all cases the same.
240                  */
241                 if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
242                         cn |= ~pmp->pm_fatmask;
243         }
244
245         if (!MSDOSFSEOF(pmp, cn)) {
246                 if (bp)
247                         brelse(bp);
248                 if (bnp)
249                         *bnp = xcntobn(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(struct denode *dep, u_long findcn, u_long *frcnp, u_long *fsrcnp)
272 {
273         int i;
274         u_long cn;
275         struct fatcache *closest = NULL;
276
277         for (i = 0; i < FC_SIZE; i++) {
278                 cn = dep->de_fc[i].fc_frcn;
279                 if (cn != FCE_EMPTY && cn <= findcn) {
280                         if (closest == NULL || cn > closest->fc_frcn)
281                                 closest = &dep->de_fc[i];
282                 }
283         }
284         if (closest) {
285                 *frcnp = closest->fc_frcn;
286                 *fsrcnp = closest->fc_fsrcn;
287         }
288 }
289
290 /*
291  * Purge the fat cache in denode dep of all entries relating to file
292  * relative cluster frcn and beyond.
293  */
294 void
295 fc_purge(struct denode *dep, u_int frcn)
296 {
297         int i;
298         struct fatcache *fcp;
299
300         fcp = dep->de_fc;
301         for (i = 0; i < FC_SIZE; i++, fcp++) {
302                 if (fcp->fc_frcn >= frcn)
303                         fcp->fc_frcn = FCE_EMPTY;
304         }
305 }
306
307 /*
308  * Update the fat.
309  * If mirroring the fat, update all copies, with the first copy as last.
310  * Else update only the current fat (ignoring the others).
311  *
312  * pmp   - msdosfsmount structure for filesystem to update
313  * bp    - addr of modified fat block
314  * fatbn - block number relative to begin of filesystem of the modified fat block.
315  */
316 static void
317 updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn)
318 {
319         int i;
320         struct buf *bpn;
321
322         mprintf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn);
323
324         /*
325          * If we have an FSInfo block, update it.
326          */
327         if (pmp->pm_fsinfo) {
328                 u_long cn = pmp->pm_nxtfree;
329
330                 if (pmp->pm_freeclustercount
331                     && (pmp->pm_inusemap[cn / N_INUSEBITS]
332                         & (1 << (cn % N_INUSEBITS)))) {
333                         /*
334                          * The cluster indicated in FSInfo isn't free
335                          * any longer.  Got get a new free one.
336                          */
337                         for (cn = 0; cn < pmp->pm_maxcluster; cn += N_INUSEBITS)
338                                 if (pmp->pm_inusemap[cn / N_INUSEBITS] != (u_int)-1)
339                                         break;
340                         pmp->pm_nxtfree = cn
341                                 + ffs(pmp->pm_inusemap[cn / N_INUSEBITS]
342                                       ^ (u_int)-1) - 1;
343                 }
344                 if (bread(pmp->pm_devvp, de_bntodoff(pmp, pmp->pm_fsinfo),
345                     fsi_size(pmp), &bpn) != 0) {
346                         /*
347                          * Ignore the error, but turn off FSInfo update for the future.
348                          */
349                         pmp->pm_fsinfo = 0;
350                         brelse(bpn);
351                 } else {
352                         struct fsinfo *fp = (struct fsinfo *)bpn->b_data;
353
354                         putulong(fp->fsinfree, pmp->pm_freeclustercount);
355                         putulong(fp->fsinxtfree, pmp->pm_nxtfree);
356                         if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
357                                 bwrite(bpn);
358                         else
359                                 bdwrite(bpn);
360                 }
361         }
362
363         if (pmp->pm_flags & MSDOSFS_FATMIRROR) {
364                 /*
365                  * Now copy the block(s) of the modified fat to the other copies of
366                  * the fat and write them out.  This is faster than reading in the
367                  * other fats and then writing them back out.  This could tie up
368                  * the fat for quite a while. Preventing others from accessing it.
369                  * To prevent us from going after the fat quite so much we use
370                  * delayed writes, unless they specfied "synchronous" when the
371                  * filesystem was mounted.  If synch is asked for then use
372                  * bwrite()'s and really slow things down.
373                  */
374                 for (i = 1; i < pmp->pm_FATs; i++) {
375                         fatbn += pmp->pm_FATsecs;
376                         /* getblk() never fails */
377                         bpn = getblk(pmp->pm_devvp, de_bntodoff(pmp, fatbn),
378                                      bp->b_bcount, 0, 0);
379                         bcopy(bp->b_data, bpn->b_data, bp->b_bcount);
380                         if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
381                                 bwrite(bpn);
382                         else
383                                 bdwrite(bpn);
384                 }
385         }
386
387         /*
388          * Write out the first (or current) fat last.
389          */
390         if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
391                 bwrite(bp);
392         else
393                 bdwrite(bp);
394         /*
395          * Maybe update fsinfo sector here?
396          */
397 }
398
399 /*
400  * Updating entries in 12 bit fats is a pain in the butt.
401  *
402  * The following picture shows where nibbles go when moving from a 12 bit
403  * cluster number into the appropriate bytes in the FAT.
404  *
405  *      byte m        byte m+1      byte m+2
406  *      +----+----+   +----+----+   +----+----+
407  *      |  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
408  *      +----+----+   +----+----+   +----+----+
409  *
410  *      +----+----+----+   +----+----+----+
411  *      |  3    0    1 |   |  4    5    2 |
412  *      +----+----+----+   +----+----+----+
413  *      cluster n          cluster n+1
414  *
415  * Where n is even. m = n + (n >> 2)
416  *
417  */
418 static __inline void
419 usemap_alloc(struct msdosfsmount *pmp, u_long cn)
420 {
421         pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
422         pmp->pm_freeclustercount--;
423 }
424
425 static __inline void
426 usemap_free(struct msdosfsmount *pmp, u_long cn)
427 {
428         pmp->pm_freeclustercount++;
429         pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
430 }
431
432 int
433 clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
434 {
435         int error;
436         u_long oldcn;
437
438         usemap_free(pmp, cluster);
439         error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
440         if (error) {
441                 usemap_alloc(pmp, cluster);
442                 return (error);
443         }
444         /*
445          * If the cluster was successfully marked free, then update
446          * the count of free clusters, and turn off the "allocated"
447          * bit in the "in use" cluster bit map.
448          */
449         if (oldcnp)
450                 *oldcnp = oldcn;
451         return (0);
452 }
453
454 /*
455  * Get or Set or 'Get and Set' the cluster'th entry in the fat.
456  *
457  * function     - whether to get or set a fat entry
458  * pmp          - address of the msdosfsmount structure for the filesystem
459  *                whose fat is to be manipulated.
460  * cn           - which cluster is of interest
461  * oldcontents  - address of a word that is to receive the contents of the
462  *                cluster'th entry if this is a get function
463  * newcontents  - the new value to be written into the cluster'th element of
464  *                the fat if this is a set function.
465  *
466  * This function can also be used to free a cluster by setting the fat entry
467  * for a cluster to 0.
468  *
469  * All copies of the fat are updated if this is a set function. NOTE: If
470  * fatentry() marks a cluster as free it does not update the inusemap in
471  * the msdosfsmount structure. This is left to the caller.
472  */
473 int
474 fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents,
475          u_long newcontents)
476 {
477         int error;
478         u_long readcn;
479         u_long bn, bo, bsize, byteoffset;
480         struct buf *bp;
481
482         mprintf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
483                 function, pmp, cn, oldcontents, newcontents);
484
485 #ifdef DIAGNOSTIC
486         /*
487          * Be sure they asked us to do something.
488          */
489         if ((function & (FAT_SET | FAT_GET)) == 0) {
490                 kprintf("fatentry(): function code doesn't specify get or set\n");
491                 return (EINVAL);
492         }
493
494         /*
495          * If they asked us to return a cluster number but didn't tell us
496          * where to put it, give them an error.
497          */
498         if ((function & FAT_GET) && oldcontents == NULL) {
499                 kprintf("fatentry(): get function with no place to put result\n");
500                 return (EINVAL);
501         }
502 #endif
503
504         /*
505          * Be sure the requested cluster is in the filesystem.
506          */
507         if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
508                 return (EINVAL);
509
510         byteoffset = FATOFS(pmp, cn);
511         fatblock(pmp, byteoffset, &bn, &bsize, &bo);
512         error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), bsize, &bp);
513         if (error) {
514                 brelse(bp);
515                 return (error);
516         }
517
518         if (function & FAT_GET) {
519                 if (FAT32(pmp))
520                         readcn = getulong(&bp->b_data[bo]);
521                 else
522                         readcn = getushort(&bp->b_data[bo]);
523                 if (FAT12(pmp) & (cn & 1))
524                         readcn >>= 4;
525                 readcn &= pmp->pm_fatmask;
526                 /* map reserved fat entries to same values for all fats */
527                 if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
528                         readcn |= ~pmp->pm_fatmask;
529                 *oldcontents = readcn;
530         }
531         if (function & FAT_SET) {
532                 switch (pmp->pm_fatmask) {
533                 case FAT12_MASK:
534                         readcn = getushort(&bp->b_data[bo]);
535                         if (cn & 1) {
536                                 readcn &= 0x000f;
537                                 readcn |= newcontents << 4;
538                         } else {
539                                 readcn &= 0xf000;
540                                 readcn |= newcontents & 0xfff;
541                         }
542                         putushort(&bp->b_data[bo], readcn);
543                         break;
544                 case FAT16_MASK:
545                         putushort(&bp->b_data[bo], newcontents);
546                         break;
547                 case FAT32_MASK:
548                         /*
549                          * According to spec we have to retain the
550                          * high order bits of the fat entry.
551                          */
552                         readcn = getulong(&bp->b_data[bo]);
553                         readcn &= ~FAT32_MASK;
554                         readcn |= newcontents & FAT32_MASK;
555                         putulong(&bp->b_data[bo], readcn);
556                         break;
557                 }
558                 updatefats(pmp, bp, bn);
559                 bp = NULL;
560                 pmp->pm_fmod = 1;
561         }
562         if (bp)
563                 brelse(bp);
564         return (0);
565 }
566
567 /*
568  * Update a contiguous cluster chain
569  *
570  * pmp      - mount point
571  * start    - first cluster of chain
572  * count    - number of clusters in chain
573  * fillwith - what to write into fat entry of last cluster
574  */
575 static int
576 fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith)
577 {
578         int error;
579         u_long bn, bo, bsize, byteoffset, readcn, newc;
580         struct buf *bp;
581
582         mprintf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
583             pmp, start, count, fillwith);
584         /*
585          * Be sure the clusters are in the filesystem.
586          */
587         if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
588                 return (EINVAL);
589
590         while (count > 0) {
591                 byteoffset = FATOFS(pmp, start);
592                 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
593                 error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), bsize, &bp);
594                 if (error) {
595                         brelse(bp);
596                         return (error);
597                 }
598                 while (count > 0) {
599                         start++; /* Callers must guarantee contiguous free
600                                     clusters. */
601                         newc = --count > 0 ? start : fillwith;
602                         switch (pmp->pm_fatmask) {
603                         case FAT12_MASK:
604                                 readcn = getushort(&bp->b_data[bo]);
605                                 if (start & 1) {
606                                         readcn &= 0xf000;
607                                         readcn |= newc & 0xfff;
608                                 } else {
609                                         readcn &= 0x000f;
610                                         readcn |= newc << 4;
611                                 }
612                                 putushort(&bp->b_data[bo], readcn);
613                                 bo++;
614                                 if (!(start & 1))
615                                         bo++;
616                                 break;
617                         case FAT16_MASK:
618                                 putushort(&bp->b_data[bo], newc);
619                                 bo += 2;
620                                 break;
621                         case FAT32_MASK:
622                                 readcn = getulong(&bp->b_data[bo]);
623                                 readcn &= ~pmp->pm_fatmask;
624                                 readcn |= newc & pmp->pm_fatmask;
625                                 putulong(&bp->b_data[bo], readcn);
626                                 bo += 4;
627                                 break;
628                         }
629                         if (bo >= bsize)
630                                 break;
631                 }
632                 updatefats(pmp, bp, bn);
633         }
634         pmp->pm_fmod = 1;
635         return (0);
636 }
637
638 /*
639  * Check the length of a free cluster chain starting at start.
640  *
641  * pmp   - mount point
642  * start - start of chain
643  * count - maximum interesting length
644  */
645 static int
646 chainlength(struct msdosfsmount *pmp, u_long start, u_long count)
647 {
648         u_long idx, max_idx;
649         u_int map;
650         u_long len;
651
652         max_idx = pmp->pm_maxcluster / N_INUSEBITS;
653         idx = start / N_INUSEBITS;
654         start %= N_INUSEBITS;
655         map = pmp->pm_inusemap[idx];
656         map &= ~((1 << start) - 1);
657         if (map) {
658                 len = ffs(map) - 1 - start;
659                 return (len > count ? count : len);
660         }
661         len = N_INUSEBITS - start;
662         if (len >= count)
663                 return (count);
664         while (++idx <= max_idx) {
665                 if (len >= count)
666                         break;
667                 map = pmp->pm_inusemap[idx];
668                 if (map) {
669                         len +=  ffs(map) - 1;
670                         break;
671                 }
672                 len += N_INUSEBITS;
673         }
674         return (len > count ? count : len);
675 }
676
677 /*
678  * Allocate contigous free clusters.
679  *
680  * pmp        - mount point.
681  * start      - start of cluster chain.
682  * count      - number of clusters to allocate.
683  * fillwith   - put this value into the fat entry for the
684  *              last allocated cluster.
685  * retcluster - put the first allocated cluster's number here.
686  * got        - how many clusters were actually allocated.
687  */
688 static int
689 chainalloc(struct msdosfsmount *pmp, u_long start, u_long count,
690            u_long fillwith, u_long *retcluster, u_long *got)
691 {
692         int error;
693         u_long cl, n;
694
695         for (cl = start, n = count; n-- > 0;)
696                 usemap_alloc(pmp, cl++);
697
698         error = fatchain(pmp, start, count, fillwith);
699         if (error != 0)
700                 return (error);
701         mprintf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
702             start, count);
703         if (retcluster)
704                 *retcluster = start;
705         if (got)
706                 *got = count;
707         return (0);
708 }
709
710 /*
711  * Allocate contiguous free clusters.
712  *
713  * pmp        - mount point.
714  * start      - preferred start of cluster chain.
715  * count      - number of clusters requested.
716  * fillwith   - put this value into the fat entry for the
717  *              last allocated cluster.
718  * retcluster - put the first allocated cluster's number here.
719  * got        - how many clusters were actually allocated.
720  */
721 int
722 clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count,
723              u_long fillwith, u_long *retcluster, u_long *got)
724 {
725         u_long idx;
726         u_long len, newst, foundl, cn, l;
727         u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
728         u_int map;
729
730         mprintf("clusteralloc(): find %lu clusters\n",count);
731         if (start) {
732                 if ((len = chainlength(pmp, start, count)) >= count)
733                         return (chainalloc(pmp, start, count, fillwith,
734                                 retcluster, got));
735         } else
736                 len = 0;
737
738         /*
739          * Start at a (pseudo) random place to maximize cluster runs
740          * under multiple writers.
741          */
742         newst = krandom() % (pmp->pm_maxcluster + 1);
743         foundl = 0;
744
745         for (cn = newst; cn <= pmp->pm_maxcluster;) {
746                 idx = cn / N_INUSEBITS;
747                 map = pmp->pm_inusemap[idx];
748                 map |= (1 << (cn % N_INUSEBITS)) - 1;
749                 if (map != (u_int)-1) {
750                         cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
751                         if ((l = chainlength(pmp, cn, count)) >= count)
752                                 return (chainalloc(pmp, cn, count, fillwith,
753                                         retcluster, got));
754                         if (l > foundl) {
755                                 foundcn = cn;
756                                 foundl = l;
757                         }
758                         cn += l + 1;
759                         continue;
760                 }
761                 cn += N_INUSEBITS - cn % N_INUSEBITS;
762         }
763         for (cn = 0; cn < newst;) {
764                 idx = cn / N_INUSEBITS;
765                 map = pmp->pm_inusemap[idx];
766                 map |= (1 << (cn % N_INUSEBITS)) - 1;
767                 if (map != (u_int)-1) {
768                         cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
769                         if ((l = chainlength(pmp, cn, count)) >= count)
770                                 return (chainalloc(pmp, cn, count, fillwith,
771                                         retcluster, got));
772                         if (l > foundl) {
773                                 foundcn = cn;
774                                 foundl = l;
775                         }
776                         cn += l + 1;
777                         continue;
778                 }
779                 cn += N_INUSEBITS - cn % N_INUSEBITS;
780         }
781
782         if (!foundl)
783                 return (ENOSPC);
784
785         if (len)
786                 return (chainalloc(pmp, start, len, fillwith, retcluster, got));
787         else
788                 return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster,
789                         got));
790 }
791
792
793 /*
794  * Free a chain of clusters.
795  *
796  * pmp          - address of the msdosfs mount structure for the filesystem
797  *                containing the cluster chain to be freed.
798  * startcluster - number of the 1st cluster in the chain of clusters to be
799  *                freed.
800  */
801 int
802 freeclusterchain(struct msdosfsmount *pmp, u_long cluster)
803 {
804         int error;
805         struct buf *bp = NULL;
806         u_long bn, bo, bsize, byteoffset;
807         u_long readcn, lbn = -1;
808
809         while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) {
810                 byteoffset = FATOFS(pmp, cluster);
811                 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
812                 if (lbn != bn) {
813                         if (bp)
814                                 updatefats(pmp, bp, lbn);
815                         error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn),
816                                       bsize, &bp);
817                         if (error) {
818                                 brelse(bp);
819                                 return (error);
820                         }
821                         lbn = bn;
822                 }
823                 usemap_free(pmp, cluster);
824                 switch (pmp->pm_fatmask) {
825                 case FAT12_MASK:
826                         readcn = getushort(&bp->b_data[bo]);
827                         if (cluster & 1) {
828                                 cluster = readcn >> 4;
829                                 readcn &= 0x000f;
830                                 readcn |= MSDOSFSFREE << 4;
831                         } else {
832                                 cluster = readcn;
833                                 readcn &= 0xf000;
834                                 readcn |= MSDOSFSFREE & 0xfff;
835                         }
836                         putushort(&bp->b_data[bo], readcn);
837                         break;
838                 case FAT16_MASK:
839                         cluster = getushort(&bp->b_data[bo]);
840                         putushort(&bp->b_data[bo], MSDOSFSFREE);
841                         break;
842                 case FAT32_MASK:
843                         cluster = getulong(&bp->b_data[bo]);
844                         putulong(&bp->b_data[bo],
845                                  (MSDOSFSFREE & FAT32_MASK) |
846                                  (cluster & ~FAT32_MASK));
847                         break;
848                 }
849                 cluster &= pmp->pm_fatmask;
850                 if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD)
851                         cluster |= pmp->pm_fatmask;
852         }
853         if (bp)
854                 updatefats(pmp, bp, bn);
855         return (0);
856 }
857
858 /*
859  * Read in fat blocks looking for free clusters. For every free cluster
860  * found turn off its corresponding bit in the pm_inusemap.
861  */
862 int
863 fillinusemap(struct msdosfsmount *pmp)
864 {
865         struct buf *bp = NULL;
866         u_long cn, readcn;
867         int error;
868         u_long bn, bo, bsize, byteoffset;
869
870         /*
871          * Mark all clusters in use, we mark the free ones in the fat scan
872          * loop further down.
873          */
874         for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++)
875                 pmp->pm_inusemap[cn] = (u_int)-1;
876
877         /*
878          * Figure how many free clusters are in the filesystem by ripping
879          * through the fat counting the number of entries whose content is
880          * zero.  These represent free clusters.
881          */
882         pmp->pm_freeclustercount = 0;
883         for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
884                 byteoffset = FATOFS(pmp, cn);
885                 bo = byteoffset % pmp->pm_fatblocksize;
886                 if (!bo || !bp) {
887                         /* Read new FAT block */
888                         if (bp)
889                                 brelse(bp);
890                         fatblock(pmp, byteoffset, &bn, &bsize, NULL);
891                         error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn),
892                                       bsize, &bp);
893                         if (error) {
894                                 brelse(bp);
895                                 return (error);
896                         }
897                 }
898                 if (FAT32(pmp))
899                         readcn = getulong(&bp->b_data[bo]);
900                 else
901                         readcn = getushort(&bp->b_data[bo]);
902                 if (FAT12(pmp) && (cn & 1))
903                         readcn >>= 4;
904                 readcn &= pmp->pm_fatmask;
905
906                 if (readcn == 0)
907                         usemap_free(pmp, cn);
908         }
909         brelse(bp);
910         return (0);
911 }
912
913 /*
914  * Allocate a new cluster and chain it onto the end of the file.
915  *
916  * dep   - the file to extend
917  * count - number of clusters to allocate
918  * bpp   - where to return the address of the buf header for the first new
919  *         file block
920  * ncp   - where to put cluster number of the first newly allocated cluster
921  *         If this pointer is 0, do not return the cluster number.
922  * flags - see fat.h
923  *
924  * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
925  * the de_flag field of the denode and it does not change the de_FileSize
926  * field.  This is left for the caller to do.
927  */
928 int
929 extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp,
930            int flags)
931 {
932         int error;
933         u_long frcn;
934         u_long cn, got;
935         struct msdosfsmount *pmp = dep->de_pmp;
936         struct buf *bp;
937
938         /*
939          * Don't try to extend the root directory
940          */
941         if (dep->de_StartCluster == MSDOSFSROOT
942             && (dep->de_Attributes & ATTR_DIRECTORY)) {
943                 kprintf("extendfile(): attempt to extend root directory\n");
944                 return (ENOSPC);
945         }
946
947         /*
948          * If the "file's last cluster" cache entry is empty, and the file
949          * is not empty, then fill the cache entry by calling pcbmap().
950          */
951         fc_fileextends++;
952         if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
953             dep->de_StartCluster != 0) {
954                 fc_lfcempty++;
955                 error = pcbmap(dep, 0xffff, NULL, &cn, NULL);
956                 /* we expect it to return E2BIG */
957                 if (error != E2BIG)
958                         return (error);
959         }
960
961         while (count > 0) {
962                 /*
963                  * Allocate a new cluster chain and cat onto the end of the
964                  * file.  * If the file is empty we make de_StartCluster point
965                  * to the new block.  Note that de_StartCluster being 0 is
966                  * sufficient to be sure the file is empty since we exclude
967                  * attempts to extend the root directory above, and the root
968                  * dir is the only file with a startcluster of 0 that has
969                  * blocks allocated (sort of).
970                  */
971                 if (dep->de_StartCluster == 0)
972                         cn = 0;
973                 else
974                         cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
975                 error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got);
976                 if (error)
977                         return (error);
978
979                 count -= got;
980
981                 /*
982                  * Give them the filesystem relative cluster number if they want
983                  * it.
984                  */
985                 if (ncp) {
986                         *ncp = cn;
987                         ncp = NULL;
988                 }
989
990                 if (dep->de_StartCluster == 0) {
991                         dep->de_StartCluster = cn;
992                         frcn = 0;
993                 } else {
994                         error = fatentry(FAT_SET, pmp,
995                                          dep->de_fc[FC_LASTFC].fc_fsrcn,
996                                          0, cn);
997                         if (error) {
998                                 clusterfree(pmp, cn, NULL);
999                                 return (error);
1000                         }
1001                         frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
1002                 }
1003
1004                 /*
1005                  * Update the "last cluster of the file" entry in the
1006                  * denode's fat cache.
1007                  */
1008                 fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1);
1009
1010                 if (flags & DE_CLEAR) {
1011                         while (got-- > 0) {
1012                                 /*
1013                                  * Get the buf header for the new block of the file.
1014                                  */
1015                                 if (dep->de_Attributes & ATTR_DIRECTORY) {
1016                                         bp = getblk(pmp->pm_devvp,
1017                                                     xcntodoff(pmp, cn),
1018                                                     pmp->pm_bpcluster, 0, 0);
1019                                         ++cn;
1020                                 } else {
1021                                         daddr_t dblkno;
1022
1023                                         bp = getblk(DETOV(dep),
1024                                                     de_cn2doff(pmp, frcn),
1025                                                     pmp->pm_bpcluster, 0, 0);
1026                                         ++frcn;
1027                                         /*
1028                                          * Do the bmap now, as in msdosfs_write
1029                                          */
1030                                         if (pcbmap(dep,
1031                                             de_bn2cn(pmp, de_off2bn(pmp,
1032                                             bp->b_bio1.bio_offset)),
1033                                             &dblkno, NULL, NULL)) {
1034                                                 bp->b_bio2.bio_offset = NOOFFSET;
1035                                         } else {
1036                                                 bp->b_bio2.bio_offset = de_bntodoff(pmp, dblkno);
1037                                         }
1038                                         if (bp->b_bio2.bio_offset == NOOFFSET)
1039                                                 panic("extendfile: pcbmap");
1040                                 }
1041                                 clrbuf(bp);
1042                                 if (bpp) {
1043                                         *bpp = bp;
1044                                         bpp = NULL;
1045                                 } else
1046                                         bdwrite(bp);
1047                         }
1048                 }
1049         }
1050
1051         return (0);
1052 }