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