source: mainline/uspace/srv/fs/fat/fat_fat.c@ 875edff6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 875edff6 was 875edff6, checked in by Oleg Romanenko <romanenko.oleg@…>, 15 years ago

It is possible to mount FAT32 file system.
Changes:

  1. 32bit fat_cluster_t
  2. Change macros SF(bs) to add support FAT32 sectors per fat value
  3. New macros (FAT_CLST_SIZE) for determining size of FAT cluster (2 or 4 bytes)
  4. New macros (FAT_MASK) for determining necessary mask for cluster value depending on FAT type
  5. fat_get_cluster support FAT32 and correctly return cluster value
  6. Change fat_sanity_check() to add support FAT32. Wrapping explicit use of br→(value) with macros.

TODO need to wrap all explicit use of br→() with appropriated macros.

  • Property mode set to 100644
File size: 20.9 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file fat_fat.c
35 * @brief Functions that manipulate the File Allocation Tables.
36 */
37
38#include "fat_fat.h"
39#include "fat_dentry.h"
40#include "fat.h"
41#include "../../vfs/vfs.h"
42#include <libfs.h>
43#include <libblock.h>
44#include <errno.h>
45#include <byteorder.h>
46#include <align.h>
47#include <assert.h>
48#include <fibril_synch.h>
49#include <malloc.h>
50#include <mem.h>
51
52/*
53 * Convenience macros for computing some frequently used values from the
54 * primitive boot sector members.
55 */
56#define CLBN2PBN(bs, cl, bn) \
57 (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
58
59/**
60 * The fat_alloc_lock mutex protects all copies of the File Allocation Table
61 * during allocation of clusters. The lock does not have to be held durring
62 * deallocation of clusters.
63 */
64static FIBRIL_MUTEX_INITIALIZE(fat_alloc_lock);
65
66/** Walk the cluster chain.
67 *
68 * @param bs Buffer holding the boot sector for the file.
69 * @param devmap_handle Device handle of the device with the file.
70 * @param firstc First cluster to start the walk with.
71 * @param lastc If non-NULL, output argument hodling the last cluster
72 * number visited.
73 * @param numc If non-NULL, output argument holding the number of
74 * clusters seen during the walk.
75 * @param max_clusters Maximum number of clusters to visit.
76 *
77 * @return EOK on success or a negative error code.
78 */
79int
80fat_cluster_walk(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc,
81 fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
82{
83 uint16_t clusters = 0;
84 fat_cluster_t clst = firstc, clst_last1 = FAT_CLST_LAST1(bs);
85 fat_cluster_t clst_bad = FAT_CLST_BAD(bs);
86 int rc;
87
88 if (firstc == FAT_CLST_RES0) {
89 /* No space allocated to the file. */
90 if (lastc)
91 *lastc = firstc;
92 if (numc)
93 *numc = 0;
94 return EOK;
95 }
96
97 while (clst < clst_last1 && clusters < max_clusters) {
98 assert(clst >= FAT_CLST_FIRST);
99 if (lastc)
100 *lastc = clst; /* remember the last cluster number */
101
102 /* read FAT1 */
103 rc = fat_get_cluster(bs, devmap_handle, FAT1, clst, &clst);
104 if (rc != EOK)
105 return rc;
106
107 assert(clst != clst_bad);
108 clusters++;
109 }
110
111 if (lastc && clst < clst_last1)
112 *lastc = clst;
113 if (numc)
114 *numc = clusters;
115
116 return EOK;
117}
118
119/** Read block from file located on a FAT file system.
120 *
121 * @param block Pointer to a block pointer for storing result.
122 * @param bs Buffer holding the boot sector of the file system.
123 * @param nodep FAT node.
124 * @param bn Block number.
125 * @param flags Flags passed to libblock.
126 *
127 * @return EOK on success or a negative error code.
128 */
129int
130fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
131 aoff64_t bn, int flags)
132{
133 fat_cluster_t firstc = nodep->firstc;
134 fat_cluster_t currc;
135 aoff64_t relbn = bn;
136 int rc;
137
138 if (!nodep->size)
139 return ELIMIT;
140
141 if (nodep->firstc == FAT_CLST_ROOT)
142 goto fall_through;
143
144 if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
145 nodep->lastc_cached_valid) {
146 /*
147 * This is a request to read a block within the last cluster
148 * when fortunately we have the last cluster number cached.
149 */
150 return block_get(block, nodep->idx->devmap_handle,
151 CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
152 }
153
154 if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
155 /*
156 * We can start with the cluster cached by the previous call to
157 * fat_block_get().
158 */
159 firstc = nodep->currc_cached_value;
160 relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
161 }
162
163fall_through:
164 rc = _fat_block_get(block, bs, nodep->idx->devmap_handle, firstc,
165 &currc, relbn, flags);
166 if (rc != EOK)
167 return rc;
168
169 /*
170 * Update the "current" cluster cache.
171 */
172 nodep->currc_cached_valid = true;
173 nodep->currc_cached_bn = bn;
174 nodep->currc_cached_value = currc;
175
176 return rc;
177}
178
179/** Read block from file located on a FAT file system.
180 *
181 * @param block Pointer to a block pointer for storing result.
182 * @param bs Buffer holding the boot sector of the file system.
183 * @param devmap_handle Device handle of the file system.
184 * @param fcl First cluster used by the file. Can be zero if the file
185 * is empty.
186 * @param clp If not NULL, address where the cluster containing bn
187 * will be stored.
188 * stored
189 * @param bn Block number.
190 * @param flags Flags passed to libblock.
191 *
192 * @return EOK on success or a negative error code.
193 */
194int
195_fat_block_get(block_t **block, fat_bs_t *bs, devmap_handle_t devmap_handle,
196 fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
197{
198 uint16_t clusters;
199 unsigned max_clusters;
200 fat_cluster_t c;
201 int rc;
202
203 /*
204 * This function can only operate on non-zero length files.
205 */
206 if (fcl == FAT_CLST_RES0)
207 return ELIMIT;
208
209 if (fcl == FAT_CLST_ROOT) {
210 /* root directory special case */
211 assert(bn < RDS(bs));
212 rc = block_get(block, devmap_handle,
213 RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
214 return rc;
215 }
216
217 max_clusters = bn / SPC(bs);
218 rc = fat_cluster_walk(bs, devmap_handle, fcl, &c, &clusters, max_clusters);
219 if (rc != EOK)
220 return rc;
221 assert(clusters == max_clusters);
222
223 rc = block_get(block, devmap_handle, CLBN2PBN(bs, c, bn), flags);
224
225 if (clp)
226 *clp = c;
227
228 return rc;
229}
230
231/** Fill the gap between EOF and a new file position.
232 *
233 * @param bs Buffer holding the boot sector for nodep.
234 * @param nodep FAT node with the gap.
235 * @param mcl First cluster in an independent cluster chain that will
236 * be later appended to the end of the node's own cluster
237 * chain. If pos is still in the last allocated cluster,
238 * this argument is ignored.
239 * @param pos Position in the last node block.
240 *
241 * @return EOK on success or a negative error code.
242 */
243int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
244{
245 block_t *b;
246 aoff64_t o, boundary;
247 int rc;
248
249 boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));
250
251 /* zero out already allocated space */
252 for (o = nodep->size; o < pos && o < boundary;
253 o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
254 int flags = (o % BPS(bs) == 0) ?
255 BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
256 rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
257 if (rc != EOK)
258 return rc;
259 memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
260 b->dirty = true; /* need to sync node */
261 rc = block_put(b);
262 if (rc != EOK)
263 return rc;
264 }
265
266 if (o >= pos)
267 return EOK;
268
269 /* zero out the initial part of the new cluster chain */
270 for (o = boundary; o < pos; o += BPS(bs)) {
271 rc = _fat_block_get(&b, bs, nodep->idx->devmap_handle, mcl,
272 NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
273 if (rc != EOK)
274 return rc;
275 memset(b->data, 0, min(BPS(bs), pos - o));
276 b->dirty = true; /* need to sync node */
277 rc = block_put(b);
278 if (rc != EOK)
279 return rc;
280 }
281
282 return EOK;
283}
284
285/** Get cluster from the first FAT.
286 *
287 * @param bs Buffer holding the boot sector for the file system.
288 * @param devmap_handle Device handle for the file system.
289 * @param clst Cluster which to get.
290 * @param value Output argument holding the value of the cluster.
291 *
292 * @return EOK or a negative error code.
293 */
294int
295fat_get_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
296 fat_cluster_t clst, fat_cluster_t *value)
297{
298 block_t *b, *b1;
299 aoff64_t offset;
300 int rc;
301
302 assert(fatno < FATCNT(bs));
303
304 *value = 0;
305
306 if (FAT_IS_FAT12(bs))
307 offset = (clst + clst/2);
308 else
309 offset = (clst * FAT_CLST_SIZE(bs));
310
311 rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
312 offset / BPS(bs), BLOCK_FLAGS_NONE);
313 if (rc != EOK)
314 return rc;
315
316 /* This cluster access spans a sector boundary. Check only for FAT12 */
317 if (FAT_IS_FAT12(bs)) {
318 if ((offset % BPS(bs) + 1 == BPS(bs))) {
319 /* Is it last sector of FAT? */
320 if (offset / BPS(bs) < SF(bs)) {
321 /* No. Reading next sector */
322 rc = block_get(&b1, devmap_handle, 1 + RSCNT(bs) +
323 SF(bs)*fatno + offset / BPS(bs), BLOCK_FLAGS_NONE);
324 if (rc != EOK) {
325 block_put(b);
326 return rc;
327 }
328 /*
329 * Combining value with last byte of current sector and
330 * first byte of next sector
331 */
332 *value = *(uint8_t *)(b->data + BPS(bs) - 1);
333 *value |= *(uint8_t *)(b1->data);
334
335 rc = block_put(b1);
336 if (rc != EOK) {
337 block_put(b);
338 return rc;
339 }
340 }
341 else {
342 /* Yes. It is last sector of FAT */
343 block_put(b);
344 return ERANGE;
345 }
346 }
347
348 if (clst & 0x0001)
349 *value = (*value) >> 4;
350 else
351 *value = (*value) & FAT12_MASK;
352 }
353 else {
354 if (FAT_IS_FAT32(bs))
355 *value = *(uint32_t *)(b->data + offset % BPS(bs)) & FAT32_MASK;
356 else
357 *value = *(uint16_t *)(b->data + offset % BPS(bs));
358 }
359
360 *value = uint16_t_le2host(*value);
361 rc = block_put(b);
362
363 return rc;
364}
365
366/** Set cluster in one instance of FAT.
367 *
368 * @param bs Buffer holding the boot sector for the file system.
369 * @param devmap_handle Device handle for the file system.
370 * @param fatno Number of the FAT instance where to make the change.
371 * @param clst Cluster which is to be set.
372 * @param value Value to set the cluster with.
373 *
374 * @return EOK on success or a negative error code.
375 */
376int
377fat_set_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
378 fat_cluster_t clst, fat_cluster_t value)
379{
380 block_t *b, *b1;
381 aoff64_t offset;
382 fat_cluster_t *cp, temp;
383 int rc;
384 int spans = 0;
385
386 assert(fatno < FATCNT(bs));
387
388 if (FAT_IS_FAT12(bs))
389 offset = (clst + clst/2);
390 else
391 offset = (clst * FAT_CLST_SIZE(bs));
392
393 rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
394 offset / BPS(bs), BLOCK_FLAGS_NONE);
395 if (rc != EOK)
396 return rc;
397
398 /* This cluster access spans a sector boundary. Check only for FAT12 */
399 if (FAT_IS_FAT12(bs) && (offset % BPS(bs)+1 == BPS(bs))) {
400 /* Is it last sector of FAT? */
401 if (offset / BPS(bs) < SF(bs)) {
402 /* No. Reading next sector */
403 rc = block_get(&b1, devmap_handle, 1 + RSCNT(bs) +
404 SF(bs)*fatno + offset / BPS(bs), BLOCK_FLAGS_NONE);
405 if (rc != EOK) {
406 block_put(b);
407 return rc;
408 }
409 /*
410 * Combining value with last byte of current sector and
411 * first byte of next sector
412 */
413 spans=1;
414 cp = &temp;
415 *cp = *(uint8_t *)(b->data + BPS(bs) - 1);
416 *cp |= *(uint8_t *)(b1->data);
417 }
418 else {
419 /* Yes. It is last sector of fat */
420 block_put(b);
421 return ERANGE;
422 }
423 }
424 else
425 cp = (fat_cluster_t *)(b->data + offset % BPS(bs));
426
427 value = host2uint16_t_le(value);
428 if (FAT_IS_FAT12(bs)) {
429 if (clst & 0x0001) {
430 *cp &= 0x000f;
431 *cp |= value << 4;
432 }
433 else {
434 *cp &= 0xf000;
435 *cp |= value & 0x0fff;
436 }
437
438 if (spans)
439 {
440 *(uint8_t *)(b->data + BPS(bs) - 1) = cp[0];
441 *(uint8_t *)(b1->data) = cp[1];
442
443 b1->dirty = true;
444 rc = block_put(b1);
445 if (rc != EOK) {
446 block_put(b);
447 return rc;
448 }
449 }
450 }
451 else
452 *cp = value;
453
454 b->dirty = true; /* need to sync block */
455 rc = block_put(b);
456 return rc;
457}
458
459/** Replay the allocatoin of clusters in all shadow instances of FAT.
460 *
461 * @param bs Buffer holding the boot sector of the file system.
462 * @param devmap_handle Device handle of the file system.
463 * @param lifo Chain of allocated clusters.
464 * @param nclsts Number of clusters in the lifo chain.
465 *
466 * @return EOK on success or a negative error code.
467 */
468int fat_alloc_shadow_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle,
469 fat_cluster_t *lifo, unsigned nclsts)
470{
471 uint8_t fatno;
472 unsigned c;
473 fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
474 int rc;
475
476 for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
477 for (c = 0; c < nclsts; c++) {
478 rc = fat_set_cluster(bs, devmap_handle, fatno, lifo[c],
479 c == 0 ? clst_last1 : lifo[c - 1]);
480 if (rc != EOK)
481 return rc;
482 }
483 }
484
485 return EOK;
486}
487
488/** Allocate clusters in all copies of FAT.
489 *
490 * This function will attempt to allocate the requested number of clusters in
491 * all instances of the FAT. The FAT will be altered so that the allocated
492 * clusters form an independent chain (i.e. a chain which does not belong to any
493 * file yet).
494 *
495 * @param bs Buffer holding the boot sector of the file system.
496 * @param devmap_handle Device handle of the file system.
497 * @param nclsts Number of clusters to allocate.
498 * @param mcl Output parameter where the first cluster in the chain
499 * will be returned.
500 * @param lcl Output parameter where the last cluster in the chain
501 * will be returned.
502 *
503 * @return EOK on success, a negative error code otherwise.
504 */
505int
506fat_alloc_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned nclsts,
507 fat_cluster_t *mcl, fat_cluster_t *lcl)
508{
509 fat_cluster_t *lifo; /* stack for storing free cluster numbers */
510 unsigned found = 0; /* top of the free cluster number stack */
511 fat_cluster_t clst, value, clst_last1 = FAT_CLST_LAST1(bs);
512 int rc = EOK;
513
514 lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
515 if (!lifo)
516 return ENOMEM;
517 /*
518 * Search FAT1 for unused clusters.
519 */
520 fibril_mutex_lock(&fat_alloc_lock);
521 for (clst=FAT_CLST_FIRST; clst < CC(bs)+2 && found < nclsts; clst++) {
522 rc = fat_get_cluster(bs, devmap_handle, FAT1, clst, &value);
523 if (rc != EOK)
524 break;
525
526 if (value == FAT_CLST_RES0) {
527 /*
528 * The cluster is free. Put it into our stack
529 * of found clusters and mark it as non-free.
530 */
531 lifo[found] = clst;
532 rc = fat_set_cluster(bs, devmap_handle, FAT1, clst,
533 (found == 0) ? clst_last1 : lifo[found - 1]);
534 if (rc != EOK)
535 break;
536
537 found++;
538 }
539 }
540
541 if (rc == EOK && found == nclsts) {
542 rc = fat_alloc_shadow_clusters(bs, devmap_handle, lifo, nclsts);
543 if (rc == EOK) {
544 *mcl = lifo[found - 1];
545 *lcl = lifo[0];
546 free(lifo);
547 fibril_mutex_unlock(&fat_alloc_lock);
548 return EOK;
549 }
550 }
551
552 /* If something wrong - free the clusters */
553 if (found > 0) {
554 while (found--) {
555 rc = fat_set_cluster(bs, devmap_handle, FAT1, lifo[found],
556 FAT_CLST_RES0);
557 }
558 }
559
560 free(lifo);
561 fibril_mutex_unlock(&fat_alloc_lock);
562 return ENOSPC;
563}
564
565/** Free clusters forming a cluster chain in all copies of FAT.
566 *
567 * @param bs Buffer hodling the boot sector of the file system.
568 * @param devmap_handle Device handle of the file system.
569 * @param firstc First cluster in the chain which is to be freed.
570 *
571 * @return EOK on success or a negative return code.
572 */
573int
574fat_free_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc)
575{
576 unsigned fatno;
577 fat_cluster_t nextc, clst_bad = FAT_CLST_BAD(bs);
578 int rc;
579
580 /* Mark all clusters in the chain as free in all copies of FAT. */
581 while (firstc < FAT_CLST_LAST1(bs)) {
582 assert(firstc >= FAT_CLST_FIRST && firstc < clst_bad);
583 rc = fat_get_cluster(bs, devmap_handle, FAT1, firstc, &nextc);
584 if (rc != EOK)
585 return rc;
586 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
587 rc = fat_set_cluster(bs, devmap_handle, fatno, firstc,
588 FAT_CLST_RES0);
589 if (rc != EOK)
590 return rc;
591 }
592
593 firstc = nextc;
594 }
595
596 return EOK;
597}
598
599/** Append a cluster chain to the last file cluster in all FATs.
600 *
601 * @param bs Buffer holding the boot sector of the file system.
602 * @param nodep Node representing the file.
603 * @param mcl First cluster of the cluster chain to append.
604 * @param lcl Last cluster of the cluster chain to append.
605 *
606 * @return EOK on success or a negative error code.
607 */
608int
609fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
610 fat_cluster_t lcl)
611{
612 devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
613 fat_cluster_t lastc;
614 uint8_t fatno;
615 int rc;
616
617 if (nodep->firstc == FAT_CLST_RES0) {
618 /* No clusters allocated to the node yet. */
619 nodep->firstc = mcl;
620 nodep->dirty = true; /* need to sync node */
621 } else {
622 if (nodep->lastc_cached_valid) {
623 lastc = nodep->lastc_cached_value;
624 nodep->lastc_cached_valid = false;
625 } else {
626 rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
627 &lastc, NULL, (uint16_t) -1);
628 if (rc != EOK)
629 return rc;
630 }
631
632 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
633 rc = fat_set_cluster(bs, nodep->idx->devmap_handle,
634 fatno, lastc, mcl);
635 if (rc != EOK)
636 return rc;
637 }
638 }
639
640 nodep->lastc_cached_valid = true;
641 nodep->lastc_cached_value = lcl;
642
643 return EOK;
644}
645
646/** Chop off node clusters in all copies of FAT.
647 *
648 * @param bs Buffer holding the boot sector of the file system.
649 * @param nodep FAT node where the chopping will take place.
650 * @param lcl Last cluster which will remain in the node. If this
651 * argument is FAT_CLST_RES0, then all clusters will
652 * be chopped off.
653 *
654 * @return EOK on success or a negative return code.
655 */
656int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
657{
658 fat_cluster_t clst_last1 = FAT_CLST_LAST1(bs);
659 int rc;
660 devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
661
662 /*
663 * Invalidate cached cluster numbers.
664 */
665 nodep->lastc_cached_valid = false;
666 if (nodep->currc_cached_value != lcl)
667 nodep->currc_cached_valid = false;
668
669 if (lcl == FAT_CLST_RES0) {
670 /* The node will have zero size and no clusters allocated. */
671 rc = fat_free_clusters(bs, devmap_handle, nodep->firstc);
672 if (rc != EOK)
673 return rc;
674 nodep->firstc = FAT_CLST_RES0;
675 nodep->dirty = true; /* need to sync node */
676 } else {
677 fat_cluster_t nextc;
678 unsigned fatno;
679
680 rc = fat_get_cluster(bs, devmap_handle, FAT1, lcl, &nextc);
681 if (rc != EOK)
682 return rc;
683
684 /* Terminate the cluster chain in all copies of FAT. */
685 for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
686 rc = fat_set_cluster(bs, devmap_handle, fatno, lcl,
687 clst_last1);
688 if (rc != EOK)
689 return rc;
690 }
691
692 /* Free all following clusters. */
693 rc = fat_free_clusters(bs, devmap_handle, nextc);
694 if (rc != EOK)
695 return rc;
696 }
697
698 /*
699 * Update and re-enable the last cluster cache.
700 */
701 nodep->lastc_cached_valid = true;
702 nodep->lastc_cached_value = lcl;
703
704 return EOK;
705}
706
707int
708fat_zero_cluster(struct fat_bs *bs, devmap_handle_t devmap_handle, fat_cluster_t c)
709{
710 int i;
711 block_t *b;
712 int rc;
713
714 for (i = 0; i < SPC(bs); i++) {
715 rc = _fat_block_get(&b, bs, devmap_handle, c, NULL, i,
716 BLOCK_FLAGS_NOREAD);
717 if (rc != EOK)
718 return rc;
719 memset(b->data, 0, BPS(bs));
720 b->dirty = true;
721 rc = block_put(b);
722 if (rc != EOK)
723 return rc;
724 }
725
726 return EOK;
727}
728
729/** Perform basic sanity checks on the file system.
730 *
731 * Verify if values of boot sector fields are sane. Also verify media
732 * descriptor. This is used to rule out cases when a device obviously
733 * does not contain a fat file system.
734 */
735int fat_sanity_check(fat_bs_t *bs, devmap_handle_t devmap_handle)
736{
737 fat_cluster_t e0, e1;
738 unsigned fat_no;
739 int rc;
740
741 /* Check number of FATs. */
742 if (FATCNT(bs) == 0)
743 return ENOTSUP;
744
745 /* Check total number of sectors. */
746 if (TS(bs) == 0)
747 return ENOTSUP;
748
749 if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
750 bs->totsec16 != bs->totsec32)
751 return ENOTSUP;
752
753 /* Check media descriptor. Must be between 0xf0 and 0xff. */
754 if ((bs->mdesc & 0xf0) != 0xf0)
755 return ENOTSUP;
756
757 /* Check number of sectors per FAT. */
758 if (SF(bs) == 0)
759 return ENOTSUP;
760
761 /*
762 * Check that the root directory entries take up whole blocks.
763 * This check is rather strict, but it allows us to treat the root
764 * directory and non-root directories uniformly in some places.
765 * It can be removed provided that functions such as fat_read() are
766 * sanitized to support file systems with this property.
767 */
768 if (!FAT_IS_FAT32(bs) && (RDE(bs) * sizeof(fat_dentry_t)) % BPS(bs) != 0)
769 return ENOTSUP;
770
771 /* Check signature of each FAT. */
772 for (fat_no = 0; fat_no < FATCNT(bs); fat_no++) {
773 rc = fat_get_cluster(bs, devmap_handle, fat_no, 0, &e0);
774 if (rc != EOK)
775 return EIO;
776
777 rc = fat_get_cluster(bs, devmap_handle, fat_no, 1, &e1);
778 if (rc != EOK)
779 return EIO;
780
781 /* Check that first byte of FAT contains the media descriptor. */
782 if ((e0 & 0xff) != bs->mdesc)
783 return ENOTSUP;
784
785 /*
786 * Check that remaining bits of the first two entries are
787 * set to one.
788 */
789 if (!FAT_IS_FAT12(bs) && ((e0 >> 8) != (FAT_MASK(bs) >> 8) || e1 != FAT_MASK(bs)))
790 return ENOTSUP;
791 }
792
793 return EOK;
794}
795
796/**
797 * @}
798 */
Note: See TracBrowser for help on using the repository browser.