]>
Commit | Line | Data |
---|---|---|
71f95118 WD |
1 | /* |
2 | * fat.c | |
3 | * | |
4 | * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg | |
5 | * | |
6 | * 2002-07-28 - [email protected] - ported to ppcboot v1.1.6 | |
7 | * 2003-03-10 - [email protected] - ported to uboot | |
8 | * | |
9 | * See file CREDITS for list of people who contributed to this | |
10 | * project. | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of | |
15 | * the License, or (at your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with this program; if not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | * MA 02111-1307 USA | |
26 | */ | |
27 | ||
28 | #include <common.h> | |
29 | #include <config.h> | |
30 | #include <fat.h> | |
31 | #include <asm/byteorder.h> | |
7205e407 | 32 | #include <part.h> |
71f95118 | 33 | |
dd60d122 | 34 | #if defined(CONFIG_CMD_FAT) |
71f95118 WD |
35 | |
36 | /* | |
37 | * Convert a string to lowercase. | |
38 | */ | |
39 | static void | |
40 | downcase(char *str) | |
41 | { | |
42 | while (*str != '\0') { | |
43 | TOLOWER(*str); | |
44 | str++; | |
45 | } | |
46 | } | |
47 | ||
7205e407 WD |
48 | static block_dev_desc_t *cur_dev = NULL; |
49 | static unsigned long part_offset = 0; | |
50 | static int cur_part = 1; | |
51 | ||
52 | #define DOS_PART_TBL_OFFSET 0x1be | |
53 | #define DOS_PART_MAGIC_OFFSET 0x1fe | |
54 | #define DOS_FS_TYPE_OFFSET 0x36 | |
71f95118 WD |
55 | |
56 | int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) | |
57 | { | |
7205e407 WD |
58 | startblock += part_offset; |
59 | if (cur_dev == NULL) | |
60 | return -1; | |
61 | if (cur_dev->block_read) { | |
3e3b9569 PP |
62 | return cur_dev->block_read (cur_dev->dev |
63 | , startblock, getsize, (unsigned long *)bufptr); | |
71f95118 WD |
64 | } |
65 | return -1; | |
66 | } | |
67 | ||
68 | ||
69 | int | |
7205e407 | 70 | fat_register_device(block_dev_desc_t *dev_desc, int part_no) |
71f95118 | 71 | { |
7205e407 | 72 | unsigned char buffer[SECTOR_SIZE]; |
566a494f | 73 | disk_partition_t info; |
7205e407 WD |
74 | |
75 | if (!dev_desc->block_read) | |
76 | return -1; | |
566a494f | 77 | cur_dev = dev_desc; |
7205e407 WD |
78 | /* check if we have a MBR (on floppies we have only a PBR) */ |
79 | if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) { | |
80 | printf ("** Can't read from device %d **\n", dev_desc->dev); | |
81 | return -1; | |
82 | } | |
83 | if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || | |
84 | buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { | |
85 | /* no signature found */ | |
86 | return -1; | |
87 | } | |
77ddac94 | 88 | if(!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { |
7205e407 WD |
89 | /* ok, we assume we are on a PBR only */ |
90 | cur_part = 1; | |
91 | part_offset=0; | |
bf1060ea | 92 | } else { |
dd60d122 JL |
93 | #if (defined(CONFIG_CMD_IDE) || \ |
94 | defined(CONFIG_CMD_SCSI) || \ | |
95 | defined(CONFIG_CMD_USB) || \ | |
b0d8f5bf PP |
96 | (defined(CONFIG_MMC) && defined(CONFIG_LPC2292)) || \ |
97 | defined(CONFIG_SYSTEMACE) ) | |
bf1060ea WD |
98 | /* First we assume, there is a MBR */ |
99 | if (!get_partition_info (dev_desc, part_no, &info)) { | |
100 | part_offset = info.start; | |
101 | cur_part = part_no; | |
102 | } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { | |
103 | /* ok, we assume we are on a PBR only */ | |
104 | cur_part = 1; | |
105 | part_offset = 0; | |
106 | } else { | |
107 | printf ("** Partition %d not valid on device %d **\n", | |
108 | part_no, dev_desc->dev); | |
109 | return -1; | |
110 | } | |
7205e407 | 111 | #else |
bf1060ea WD |
112 | if(!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { |
113 | /* ok, we assume we are on a PBR only */ | |
114 | cur_part = 1; | |
115 | part_offset = 0; | |
116 | info.start = part_offset; | |
117 | } else { | |
118 | /* FIXME we need to determine the start block of the | |
119 | * partition where the DOS FS resides. This can be done | |
120 | * by using the get_partition_info routine. For this | |
121 | * purpose the libpart must be included. | |
122 | */ | |
123 | part_offset = 32; | |
124 | cur_part = 1; | |
125 | } | |
566a494f | 126 | #endif |
bf1060ea | 127 | } |
71f95118 WD |
128 | return 0; |
129 | } | |
130 | ||
131 | ||
132 | /* | |
133 | * Get the first occurence of a directory delimiter ('/' or '\') in a string. | |
134 | * Return index into string if found, -1 otherwise. | |
135 | */ | |
136 | static int | |
137 | dirdelim(char *str) | |
138 | { | |
139 | char *start = str; | |
140 | ||
141 | while (*str != '\0') { | |
142 | if (ISDIRDELIM(*str)) return str - start; | |
143 | str++; | |
144 | } | |
145 | return -1; | |
146 | } | |
147 | ||
148 | ||
149 | /* | |
150 | * Match volume_info fs_type strings. | |
151 | * Return 0 on match, -1 otherwise. | |
152 | */ | |
153 | static int | |
154 | compare_sign(char *str1, char *str2) | |
155 | { | |
156 | char *end = str1+SIGNLEN; | |
157 | ||
158 | while (str1 != end) { | |
159 | if (*str1 != *str2) { | |
160 | return -1; | |
161 | } | |
162 | str1++; | |
163 | str2++; | |
164 | } | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
169 | ||
170 | /* | |
171 | * Extract zero terminated short name from a directory entry. | |
172 | */ | |
173 | static void get_name (dir_entry *dirent, char *s_name) | |
174 | { | |
175 | char *ptr; | |
176 | ||
177 | memcpy (s_name, dirent->name, 8); | |
178 | s_name[8] = '\0'; | |
179 | ptr = s_name; | |
180 | while (*ptr && *ptr != ' ') | |
181 | ptr++; | |
182 | if (dirent->ext[0] && dirent->ext[0] != ' ') { | |
183 | *ptr = '.'; | |
184 | ptr++; | |
185 | memcpy (ptr, dirent->ext, 3); | |
186 | ptr[3] = '\0'; | |
187 | while (*ptr && *ptr != ' ') | |
188 | ptr++; | |
189 | } | |
190 | *ptr = '\0'; | |
191 | if (*s_name == DELETED_FLAG) | |
192 | *s_name = '\0'; | |
193 | else if (*s_name == aRING) | |
194 |