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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7a23d60 was 7a23d60, checked in by Jakub Jermar <jakub@…>, 15 years ago

Use convenience macros for accessing FAT boot sector in fat_ops.c as well.

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