|
|
1.1 root 1: /*
2: * Written by Paul Popelka ([email protected])
3: *
4: * You can do anything you want with this software,
5: * just don't say you wrote it,
6: * and don't remove this notice.
7: *
8: * This software is provided "as is".
9: *
10: * The author supplies this software to be publicly
11: * redistributed on the understanding that the author
12: * is not responsible for the correct functioning of
13: * this software in any circumstances and is not liable
14: * for any damages caused by this software.
15: *
16: * October 1992
17: *
18: * pcfs_fat.c,v 1.3 1993/05/20 03:34:12 cgd Exp
19: */
20:
21: /*
22: * kernel include files.
23: */
24: #include "param.h"
25: #include "systm.h"
26: #include "buf.h"
27: #include "file.h"
28: #include "namei.h"
29: #include "mount.h" /* to define statfs structure */
30: #include "vnode.h" /* to define vattr structure */
31: #include "errno.h"
32:
33: /*
34: * pcfs include files.
35: */
36: #include "bpb.h"
37: #include "pcfsmount.h"
38: #include "direntry.h"
39: #include "denode.h"
40: #include "fat.h"
41:
42: /*
43: * Fat cache stats.
44: */
45: int fc_fileextends; /* # of file extends */
46: int fc_lfcempty; /* # of time last file cluster cache entry
47: * was empty */
48: int fc_bmapcalls; /* # of times pcbmap was called */
49: #define LMMAX 20
50: int fc_lmdistance[LMMAX]; /* counters for how far off the last cluster
51: * mapped entry was. */
52: int fc_largedistance; /* off by more than LMMAX */
53:
54: /* Byte offset in FAT on filesystem pmp, cluster cn */
55: #define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
56:
57:
58: static void fatblock (pmp, ofs, bnp, sizep, bop)
59: struct pcfsmount *pmp;
60: u_long ofs;
61: u_long *bnp;
62: u_long *sizep;
63: u_long *bop;
64: {
65: u_long bn, size;
66:
67: bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
68: size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
69: * pmp->pm_BytesPerSec;
70: bn += pmp->pm_fatblk;
71: if (bnp)
72: *bnp = bn;
73: if (sizep)
74: *sizep = size;
75: if (bop)
76: *bop = ofs % pmp->pm_fatblocksize;
77: }
78:
79: /*
80: * Map the logical cluster number of a file into
81: * a physical disk sector that is filesystem relative.
82: * dep - address of denode representing the file of interest
83: * findcn - file relative cluster whose filesystem relative
84: * cluster number and/or block number are/is to be found
85: * bnp - address of where to place the file system relative
86: * block number. If this pointer is null then don't return
87: * this quantity.
88: * cnp - address of where to place the file system relative
89: * cluster number. If this pointer is null then don't return
90: * this quantity.
91: * NOTE:
92: * Either bnp or cnp must be non-null.
93: * This function has one side effect. If the requested
94: * file relative cluster is beyond the end of file, then
95: * the actual number of clusters in the file is returned
96: * in *cnp. This is useful for determining how long a
97: * directory is. If cnp is null, nothing is returned.
98: */
99: int
100: pcbmap(dep, findcn, bnp, cnp)
101: struct denode *dep;
102: u_long findcn; /* file relative cluster to get */
103: daddr_t *bnp; /* returned filesys relative blk number */
104: u_long *cnp; /* returned cluster number */
105: {
106: int error;
107: u_long i;
108: u_long cn;
109: u_long prevcn;
110: u_long byteoffset;
111: u_long bn;
112: u_long bo;
113: struct buf *bp = NULL;
114: u_long bp_bn = -1;
115: struct pcfsmount *pmp = dep->de_pmp;
116: u_long bsize;
117: int fat12 = FAT12(pmp); /* 12 bit fat */
118:
119: fc_bmapcalls++;
120:
121: /*
122: * If they don't give us someplace to return a value
123: * then don't bother doing anything.
124: */
125: if (bnp == NULL && cnp == NULL)
126: return 0;
127:
128: cn = dep->de_StartCluster;
129: /*
130: * The "file" that makes up the root directory is contiguous,
131: * permanently allocated, of fixed size, and is not made up
132: * of clusters. If the cluster number is beyond the end of
133: * the root directory, then return the number of clusters in
134: * the file.
135: */
136: if (cn == PCFSROOT) {
137: if (dep->de_Attributes & ATTR_DIRECTORY) {
138: if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) {
139: if (cnp)
140: *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
141: return E2BIG;
142: }
143: if (bnp)
144: *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
145: if (cnp)
146: *cnp = PCFSROOT;
147: return 0;
148: }
149: else { /* just an empty file */
150: if (cnp)
151: *cnp = 0;
152: return E2BIG;
153: }
154: }
155:
156: /*
157: * Rummage around in the fat cache, maybe we can avoid
158: * tromping thru every fat entry for the file.
159: * And, keep track of how far off the cache was from
160: * where we wanted to be.
161: */
162: i = 0;
163: fc_lookup(dep, findcn, &i, &cn);
164: if ((bn = findcn - i) >= LMMAX)
165: fc_largedistance++;
166: else
167: fc_lmdistance[bn]++;
168:
169: /*
170: * Handle all other files or directories the normal way.
171: */
172: for (; i < findcn; i++) {
173: if (PCFSEOF(cn))
174: goto hiteof;
175: byteoffset = FATOFS(pmp, cn);
176: fatblock(pmp, byteoffset, &bn, &bsize, &bo);
177: if (bn != bp_bn) {
178: if (bp)
179: brelse(bp);
180: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
181: if (error) {
182: brelse(bp);
183: return error;
184: }
185: bp_bn = bn;
186: }
187: prevcn = cn;
188: cn = getushort(&bp->b_un.b_addr[bo]);
189: if (fat12) {
190: if (prevcn & 1)
191: cn >>= 4;
192: cn &= 0x0fff;
193: /*
194: * Force the special cluster numbers in the range
195: * 0x0ff0-0x0fff to be the same as for 16 bit cluster
196: * numbers to let the rest of pcfs think it is always
197: * dealing with 16 bit fats.
198: */
199: if ((cn & 0x0ff0) == 0x0ff0)
200: cn |= 0xf000;
201: }
202: }
203:
204: if (!PCFSEOF(cn)) {
205: if (bp)
206: brelse(bp);
207: if (bnp)
208: *bnp = cntobn(pmp, cn);
209: if (cnp)
210: *cnp = cn;
211: fc_setcache(dep, FC_LASTMAP, i, cn);
212: return 0;
213: }
214:
215: hiteof:;
216: if (cnp)
217: *cnp = i;
218: if (bp)
219: brelse(bp);
220: /* update last file cluster entry in the fat cache */
221: fc_setcache(dep, FC_LASTFC, i-1, prevcn);
222: return E2BIG;
223: }
224:
225: /*
226: * Find the closest entry in the fat cache to the
227: * cluster we are looking for.
228: */
229: fc_lookup(dep, findcn, frcnp, fsrcnp)
230: struct denode *dep;
231: u_long findcn;
232: u_long *frcnp;
233: u_long *fsrcnp;
234: {
235: int i;
236: u_long cn;
237: struct fatcache *closest = 0;
238:
239: for (i = 0; i < FC_SIZE; i++) {
240: cn = dep->de_fc[i].fc_frcn;
241: if (cn != FCE_EMPTY && cn <= findcn) {
242: if (closest == 0 || cn > closest->fc_frcn)
243: closest = &dep->de_fc[i];
244: }
245: }
246: if (closest) {
247: *frcnp = closest->fc_frcn;
248: *fsrcnp = closest->fc_fsrcn;
249: }
250: }
251:
252: /*
253: * Purge the fat cache in denode dep of all entries
254: * relating to file relative cluster frcn and beyond.
255: */
256: fc_purge(dep, frcn)
257: struct denode *dep;
258: u_int frcn;
259: {
260: int i;
261: struct fatcache *fcp;
262:
263: fcp = dep->de_fc;
264: for (i = 0; i < FC_SIZE; i++, fcp++) {
265: if (fcp->fc_frcn != FCE_EMPTY && fcp->fc_frcn >= frcn)
266: fcp->fc_frcn = FCE_EMPTY;
267: }
268: }
269:
270: /*
271: * Once the first fat is updated the other copies of
272: * the fat must also be updated. This function does
273: * this.
274: * pmp - pcfsmount structure for filesystem to update
275: * bp - addr of modified fat block
276: * fatbn - block number relative to begin of filesystem
277: * of the modified fat block.
278: */
279: void
280: updateotherfats(pmp, bp, fatbn)
281: struct pcfsmount *pmp;
282: struct buf *bp;
283: u_long fatbn;
284: {
285: int i;
286: struct buf *bpn;
287:
288: #if defined(PCFSDEBUG)
289: printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n",
290: pmp, bp, fatbn);
291: #endif /* defined(PCFSDEBUG) */
292:
293: /*
294: * Now copy the block(s) of the modified fat to the other
295: * copies of the fat and write them out. This is faster
296: * than reading in the other fats and then writing them
297: * back out. This could tie up the fat for quite a while.
298: * Preventing others from accessing it. To prevent us
299: * from going after the fat quite so much we use delayed
300: * writes, unless they specfied "synchronous" when the
301: * filesystem was mounted. If synch is asked for then
302: * use bwrite()'s and really slow things down.
303: */
304: for (i = 1; i < pmp->pm_FATs; i++) {
305: fatbn += pmp->pm_FATsecs;
306: /* getblk() never fails */
307: bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount);
308: bcopy(bp->b_un.b_addr, bpn->b_un.b_addr,
309: bp->b_bcount);
310: if (pmp->pm_waitonfat)
311: bwrite(bpn);
312: else
313: bdwrite(bpn);
314: }
315: }
316:
317: /*
318: * Updating entries in 12 bit fats is a pain in the butt.
319: *
320: * The following picture shows where nibbles go when
321: * moving from a 12 bit cluster number into the appropriate
322: * bytes in the FAT.
323: *
324: * byte m byte m+1 byte m+2
325: * +----+----+ +----+----+ +----+----+
326: * | 0 1 | | 2 3 | | 4 5 | FAT bytes
327: * +----+----+ +----+----+ +----+----+
328: *
329: * +----+----+----+ +----+----+----+
330: * | 3 0 1 | | 4 5 2 |
331: * +----+----+----+ +----+----+----+
332: * cluster n cluster n+1
333: *
334: * Where n is even.
335: * m = n + (n >> 2)
336: *
337: * (Function no longer used)
338: */
339:
340:
341: extern inline void
342: usemap_alloc (struct pcfsmount *pmp, u_long cn)
343: {
344: pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8);
345: pmp->pm_freeclustercount--;
346: /* This assumes that the lowest available cluster was allocated */
347: pmp->pm_lookhere = cn + 1;
348: }
349:
350: extern inline void
351: usemap_free (struct pcfsmount *pmp, u_long cn)
352: {
353: pmp->pm_freeclustercount++;
354: pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8));
355: if (pmp->pm_lookhere > cn)
356: pmp->pm_lookhere = cn;
357: }
358:
359: int
360: clusterfree(pmp, cluster, oldcnp)
361: struct pcfsmount *pmp;
362: u_long cluster;
363: u_long *oldcnp;
364: {
365: int error;
366: u_long oldcn;
367:
368: error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE);
369: if (error == 0) {
370: /*
371: * If the cluster was successfully marked free, then update the count of
372: * free clusters, and turn off the "allocated" bit in the
373: * "in use" cluster bit map.
374: */
375: usemap_free(pmp, cluster);
376: if (oldcnp)
377: *oldcnp = oldcn;
378: }
379: return error;
380: }
381:
382: /*
383: * Get or Set or 'Get and Set' the cluster'th entry in the
384: * fat.
385: * function - whether to get or set a fat entry
386: * pmp - address of the pcfsmount structure for the
387: * filesystem whose fat is to be manipulated.
388: * cluster - which cluster is of interest
389: * oldcontents - address of a word that is to receive
390: * the contents of the cluster'th entry if this is
391: * a get function
392: * newcontents - the new value to be written into the
393: * cluster'th element of the fat if this is a set
394: * function.
395: *
396: * This function can also be used to free a cluster
397: * by setting the fat entry for a cluster to 0.
398: *
399: * All copies of the fat are updated if this is a set
400: * function.
401: * NOTE:
402: * If fatentry() marks a cluster as free it does not
403: * update the inusemap in the pcfsmount structure.
404: * This is left to the caller.
405: */
406: int
407: fatentry(function, pmp, cn, oldcontents, newcontents)
408: int function;
409: struct pcfsmount *pmp;
410: u_long cn;
411: u_long *oldcontents;
412: u_long newcontents;
413: {
414: int error;
415: u_long readcn;
416: u_long bn, bo, bsize, byteoffset;
417: struct buf *bp;
418: /*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
419: function, pmp, cluster, oldcontents, newcontents);*/
420:
421: #ifdef DIAGNOSTIC
422: /*
423: * Be sure they asked us to do something.
424: */
425: if ((function & (FAT_SET | FAT_GET)) == 0) {
426: printf("fatentry(): function code doesn't specify get or set\n");
427: return EINVAL;
428: }
429:
430: /*
431: * If they asked us to return a cluster number
432: * but didn't tell us where to put it, give them
433: * an error.
434: */
435: if ((function & FAT_GET) && oldcontents == NULL) {
436: printf("fatentry(): get function with no place to put result\n");
437: return EINVAL;
438: }
439: #endif
440:
441: /*
442: * Be sure the requested cluster is in the filesystem.
443: */
444: if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
445: return EINVAL;
446:
447: byteoffset = FATOFS(pmp, cn);
448: fatblock(pmp, byteoffset, &bn, &bsize, &bo);
449: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
450: if (error) {
451: brelse(bp);
452: return error;
453: }
454: if (function & FAT_GET) {
455: readcn = getushort(&bp->b_un.b_addr[bo]);
456: if (FAT12(pmp)) {
457: if (cn & 1)
458: readcn >>= 4;
459: readcn &= 0x0fff;
460: /* map certain 12 bit fat entries to 16 bit */
461: if ((readcn & 0x0ff0) == 0x0ff0)
462: readcn |= 0xf000;
463: }
464: *oldcontents = readcn;
465: }
466: if (function & FAT_SET) {
467: if (FAT12(pmp)) {
468: readcn = getushort(&bp->b_un.b_addr[bo]);
469: if (cn & 1) {
470: readcn &= 0x000f;
471: readcn |= (newcontents << 4);
472: }
473: else {
474: readcn &= 0xf000;
475: readcn |= (newcontents << 0);
476: }
477: putushort(&bp->b_un.b_addr[bo], readcn);
478: }
479: else
480: putushort(&bp->b_un.b_addr[bo], newcontents);
481: updateotherfats(pmp, bp, bn);
482: /*
483: * Write out the first fat last.
484: */
485: if (pmp->pm_waitonfat)
486: bwrite(bp);
487: else
488: bdwrite(bp);
489: bp = NULL;
490: pmp->pm_fmod++;
491: }
492: if (bp)
493: brelse(bp);
494: return 0;
495: }
496:
497: /*
498: * Allocate a free cluster.
499: * pmp -
500: * retcluster - put the allocated cluster's number here.
501: * fillwith - put this value into the fat entry for the
502: * allocated cluster.
503: */
504: int
505: clusteralloc(pmp, retcluster, fillwith)
506: struct pcfsmount *pmp;
507: u_long *retcluster;
508: u_long fillwith;
509: {
510: int error;
511: u_long cn;
512: u_long idx, max_idx, bit, map;
513:
514: max_idx = pmp->pm_maxcluster / 8;
515: for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) {
516: map = pmp->pm_inusemap[idx];
517: if (map != 0xff) {
518: for (bit = 0; bit < 8; bit++) {
519: if ((map & (1 << bit)) == 0) {
520: cn = idx * 8 + bit;
521: goto found_one;
522: }
523: }
524: }
525: }
526: return ENOSPC;
527:
528: found_one:;
529: error = fatentry(FAT_SET, pmp, cn, 0, fillwith);
530: if (error == 0) {
531: usemap_alloc(pmp, cn);
532: *retcluster = cn;
533: }
534: #if defined(PCFSDEBUG)
535: printf("clusteralloc(): allocated cluster %d\n", cn);
536: #endif /* defined(PCFSDEBUG) */
537: return error;
538: }
539:
540: /*
541: * Free a chain of clusters.
542: * pmp - address of the pcfs mount structure for the
543: * filesystem containing the cluster chain to be freed.
544: * startcluster - number of the 1st cluster in the chain
545: * of clusters to be freed.
546: */
547: int
548: freeclusterchain(pmp, startcluster)
549: struct pcfsmount *pmp;
550: u_long startcluster;
551: {
552: u_long nextcluster;
553: int error = 0;
554:
555: while (startcluster >= CLUST_FIRST && startcluster <= pmp->pm_maxcluster) {
556: error = clusterfree(pmp, startcluster, &nextcluster);
557: if (error) {
558: printf("freeclusterchain(): free failed, cluster %d\n",
559: startcluster);
560: break;
561: }
562: startcluster = nextcluster;
563: }
564: return error;
565: }
566:
567: /*
568: * Read in fat blocks looking for free clusters.
569: * For every free cluster found turn off its
570: * corresponding bit in the pm_inusemap.
571: */
572: int
573: fillinusemap(pmp)
574: struct pcfsmount *pmp;
575: {
576: struct buf *bp = NULL;
577: u_long cn, readcn;
578: int error;
579: int fat12 = FAT12(pmp);
580: u_long bn, bo, bsize, byteoffset;
581:
582: /*
583: * Mark all clusters in use, we mark the free ones in the
584: * fat scan loop further down.
585: */
586: for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++)
587: pmp->pm_inusemap[cn] = 0xff;
588:
589: /*
590: * Figure how many free clusters are in the filesystem
591: * by ripping thougth the fat counting the number of
592: * entries whose content is zero. These represent free
593: * clusters.
594: */
595: pmp->pm_freeclustercount = 0;
596: pmp->pm_lookhere = pmp->pm_maxcluster + 1;
597: for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
598: byteoffset = FATOFS(pmp, cn);
599: bo = byteoffset % pmp->pm_fatblocksize;
600: if (!bo || !bp) {
601: /* Read new FAT block */
602: if (bp)
603: brelse(bp);
604: fatblock(pmp, byteoffset, &bn, &bsize, NULL);
605: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
606: if (error) {
607: brelse(bp);
608: return error;
609: }
610: }
611: readcn = getushort(&bp->b_un.b_addr[bo]);
612: if (fat12) {
613: if (cn & 1)
614: readcn >>= 4;
615: readcn &= 0x0fff;
616: }
617:
618: if (readcn == 0)
619: usemap_free(pmp, cn);
620: }
621: brelse(bp);
622: return 0;
623: }
624:
625: /*
626: * Allocate a new cluster and chain it onto the end of the
627: * file.
628: * dep - the file to extend
629: * bpp - where to return the address of the buf header for the
630: * new file block
631: * ncp - where to put cluster number of the newly allocated file block
632: * If this pointer is 0, do not return the cluster number.
633: *
634: * NOTE:
635: * This function is not responsible for turning on the DEUPD
636: * bit if the de_flag field of the denode and it does not
637: * change the de_FileSize field. This is left for the caller
638: * to do.
639: */
640: int
641: extendfile(dep, bpp, ncp)
642: struct denode *dep;
643: struct buf **bpp;
644: u_int *ncp;
645: {
646: int error = 0;
647: u_long frcn;
648: u_long cn;
649: struct pcfsmount *pmp = dep->de_pmp;
650:
651: /*
652: * Don't try to extend the root directory
653: */
654: if (DETOV(dep)->v_flag & VROOT) {
655: printf("extendfile(): attempt to extend root directory\n");
656: return ENOSPC;
657: }
658:
659: /*
660: * If the "file's last cluster" cache entry is empty,
661: * and the file is not empty,
662: * then fill the cache entry by calling pcbmap().
663: */
664: fc_fileextends++;
665: if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
666: dep->de_StartCluster != 0) {
667: fc_lfcempty++;
668: error = pcbmap(dep, 0xffff, 0, &cn);
669: /* we expect it to return E2BIG */
670: if (error != E2BIG)
671: return error;
672: error = 0;
673: }
674:
675: /*
676: * Allocate another cluster and chain onto the end of the file.
677: * If the file is empty we make de_StartCluster point to the
678: * new block. Note that de_StartCluster being 0 is sufficient
679: * to be sure the file is empty since we exclude attempts to
680: * extend the root directory above, and the root dir is the
681: * only file with a startcluster of 0 that has blocks allocated
682: * (sort of).
683: */
684: if (error = clusteralloc(pmp, &cn, CLUST_EOFE))
685: return error;
686: if (dep->de_StartCluster == 0) {
687: dep->de_StartCluster = cn;
688: frcn = 0;
689: } else {
690: error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
691: 0, cn);
692: if (error) {
693: clusterfree(pmp, cn, NULL);
694: return error;
695: }
696:
697: frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
698: }
699:
700: /*
701: * Update the "last cluster of the file" entry in the denode's
702: * fat cache.
703: */
704: fc_setcache(dep, FC_LASTFC, frcn, cn);
705:
706: /*
707: * Get the buf header for the new block of the file.
708: */
709: if (dep->de_Attributes & ATTR_DIRECTORY)
710: *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn),
711: pmp->pm_bpcluster);
712: else
713: *bpp = getblk(DETOV(dep), frcn, pmp->pm_bpcluster);
714: clrbuf(*bpp);
715:
716: if (dep->de_Attributes & ATTR_DIRECTORY)
717: /* If we extend a directory, me must record the new size */
718: dep->de_FileSize = (frcn + 1) * pmp->pm_bpcluster;
719:
720: /*
721: * Give them the filesystem relative cluster number
722: * if they want it.
723: */
724: if (ncp)
725: *ncp = cn;
726: return 0;
727: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.