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

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

Improve code style for my changes. Adding macros for determining type of FAT and cluster value

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