]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fdos/fat.c
408fec76000f80d1793de6fca6e95e00053c9614
[karo-tx-uboot.git] / fs / fdos / fat.c
1 /*
2  * (C) Copyright 2002
3  * Stäubli Faverges - <www.staubli.com>
4  * Pierre AUBERT  p.aubert@staubli.com
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <config.h>
11 #include <malloc.h>
12
13 #include "dos.h"
14 #include "fdos.h"
15
16
17 /*-----------------------------------------------------------------------------
18  * fat_decode --
19  *-----------------------------------------------------------------------------
20  */
21 unsigned int fat_decode (Fs_t *fs, unsigned int num)
22 {
23     unsigned int start = num * 3 / 2;
24     unsigned char *address = fs -> fat_buf + start;
25
26     if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR))
27         return 1;
28
29     if (num & 1)
30         return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4);
31     else
32         return ((address [1] & 0xf) << 8) | (address [0] & 0xff );
33 }
34 /*-----------------------------------------------------------------------------
35  * check_fat --
36  *-----------------------------------------------------------------------------
37  */
38 static int check_fat (Fs_t *fs)
39 {
40     int i, f;
41
42     /* Cluster verification                                                  */
43     for (i = 3 ; i < fs -> num_clus; i++){
44         f = fat_decode (fs, i);
45         if (f < FAT12_LAST && f > fs -> num_clus){
46             /* Wrong cluster number detected                                 */
47             return (-1);
48         }
49     }
50     return (0);
51 }
52 /*-----------------------------------------------------------------------------
53  * read_one_fat --
54  *-----------------------------------------------------------------------------
55  */
56 static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat)
57 {
58     if (dev_read (fs -> fat_buf,
59                   (fs -> fat_start + nfat * fs -> fat_len),
60                   fs -> fat_len) < 0) {
61         return (-1);
62     }
63
64     if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) {
65         if ((fs -> fat_buf [0] != boot -> descr &&
66              (fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) ||
67             fs -> fat_buf [0] < MEDIA_STD){
68             /* Unknown Media                                                 */
69             return (-1);
70         }
71         if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){
72             /* FAT doesn't start with good values                            */
73             return (-1);
74         }
75     }
76
77     if (fs -> num_clus >= FAT12_MAX_NB) {
78         /* Too much clusters                                                 */
79         return (-1);
80     }
81
82     return check_fat (fs);
83 }
84 /*-----------------------------------------------------------------------------
85  * read_fat --
86  *-----------------------------------------------------------------------------
87  */
88 int read_fat (BootSector_t *boot, Fs_t *fs)
89 {
90     unsigned int buflen;
91     int i;
92
93     /* Allocate Fat Buffer                                                   */
94     buflen = fs -> fat_len * SZ_STD_SECTOR;
95     if (fs -> fat_buf) {
96         free (fs -> fat_buf);
97     }
98
99     if ((fs -> fat_buf = malloc (buflen)) == NULL) {
100         return (-1);
101     }
102
103     /* Try to read each Fat                                                  */
104     for (i = 0; i< fs -> nb_fat; i++){
105         if (read_one_fat (boot, fs, i) == 0) {
106             /* Fat is OK                                                     */
107             fs -> num_fat = i;
108             break;
109         }
110     }
111
112     if (i == fs -> nb_fat){
113         return (-1);
114     }
115
116     if (fs -> fat_len > (((fs -> num_clus + 2) *
117                           (FAT_BITS / 4) -1 ) / 2 /
118                          SZ_STD_SECTOR + 1)) {
119         return (-1);
120     }
121     return (0);
122 }