]>
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 | } | |
dd60d122 JL |
88 | #if (defined(CONFIG_CMD_IDE) || \ |
89 | defined(CONFIG_CMD_SCSI) || \ | |
90 | defined(CONFIG_CMD_USB) || \ | |
02df4a27 AF |
91 | defined(CONFIG_MMC) || \ |
92 | defined(CONFIG_SYSTEMACE) ) | |
93 | /* First we assume, there is a MBR */ | |
94 | if (!get_partition_info (dev_desc, part_no, &info)) { | |
95 | part_offset = info.start; | |
96 | cur_part = part_no; | |
97 | } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { | |
98 | /* ok, we assume we are on a PBR only */ | |
99 | cur_part = 1; | |
100 | part_offset = 0; | |
101 | } else { | |
102 | printf ("** Partition %d not valid on device %d **\n", | |
bf1060ea | 103 | part_no, dev_desc->dev); |
02df4a27 AF |
104 | return -1; |
105 | } | |
106 | ||
7205e407 | 107 | #else |
02df4a27 AF |
108 | if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { |
109 | /* ok, we assume we are on a PBR only */ | |
110 | cur_part = 1; | |
111 | part_offset = 0; | |
112 | info.start = part_offset; | |
113 | } else { | |
114 | /* FIXME we need to determine the start block of the | |
115 | * partition where the DOS FS resides. This can be done | |
116 | * by using the get_partition_info routine. For this | |
117 | * purpose the libpart must be included. | |
118 | */ | |
119 | part_offset = 32; | |
120 | cur_part = 1; | |
bf1060ea | 121 | } |
02df4a27 | 122 | #endif |
71f95118 WD |
123 | return 0; |
124 | } | |
125 | ||
126 | ||
127 | /* | |
128 | * Get the first occurence of a directory delimiter ('/' or '\') in a string. | |
129 | * Return index into string if found, -1 otherwise. | |
130 | */ | |
131 | static int | |
132 | dirdelim(char *str) | |
133 | { | |
134 | char *start = str; | |
135 | ||
136 | while (*str != '\0') { | |
137 | if (ISDIRDELIM(*str)) return str - start; | |
138 | str++; | |
139 | } | |
140 | return -1; | |
141 | } | |
142 | ||
143 | ||
144 | /* | |
145 | * Match volume_info fs_type strings. | |
146 | * Return 0 on match, -1 otherwise. | |
147 | */ | |
148 | static int | |
149 | compare_sign(char *str1, char *str2) | |
150 | { | |
151 | char *end = str1+SIGNLEN; | |
152 | ||
153 | while (str1 != end) { | |
154 | if (*str1 != *str2) { | |
155 | return -1; | |
156 | } | |
157 | str1++; | |
158 | str2++; | |
159 | } | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
164 | ||
165 | /* | |
166 | * Extract zero terminated short name from a directory entry. | |
167 | */ | |
168 | static void get_name (dir_entry *dirent, char *s_name) | |
169 | { | |
170 | char *ptr; | |
171 | ||
172 | memcpy (s_name, dirent->name, 8); | |
173 | s_name[8] = '\0'; | |
174 | ptr = s_name; | |
175 | while (*ptr && *ptr != ' ') | |
176 | ptr++; | |
177 | if (dirent->ext[0] && dirent->ext[0] != ' ') { | |
178 | *ptr = '.'; | |
179 | ptr++; | |
180 | memcpy (ptr, dirent->ext, 3); | |
181 | ptr[3] = '\0'; | |
182 | while (*ptr && *ptr != ' ') | |
183 | ptr++; | |
184 | } | |
185 | *ptr = '\0'; | |
186 | if (*s_name == DELETED_FLAG) | |
187 | *s_name = '\0'; | |
188 | else if (*s_name == aRING) | |
189 |