source: mainline/uspace/srv/fs/fat/fat_fat.c@ 97bc3ee

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

Full support for FAT12 file system. Correct creating directories and files. Fixing addressing issue.
Type of FAT (12,16,32) is determined only on the basis of the count of clusters(according to Microsoft FAT specification). I.e. FAT
with 4085 clusters or less will be determined as FAT12. FAT16 must contain more than 4085 clusters but less then 65525.

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