Commit 1ad0b98a067a133c0e8a182649a76a4afd739594
Committed by
Tom Rini
1 parent
64553717bb
Exists in
v2017.01-smarct4x
and in
37 other branches
fat: Prepare API change for files greater than 2GB
Change the internal FAT functions to use loff_t for offsets. Signed-off-by: Suriyan Ramasami <suriyan.r@gmail.com> Acked-by: Simon Glass <sjg@chromium.org> [trini: Fix fs/fat/fat.c for min3 updates] Signed-off-by: Tom Rini <trini@ti.com>
Showing 7 changed files with 128 additions and 100 deletions Inline Diff
board/esd/common/auto_update.c
1 | /* | 1 | /* |
2 | * (C) Copyright 2003-2004 | 2 | * (C) Copyright 2003-2004 |
3 | * Gary Jennejohn, DENX Software Engineering, garyj@denx.de. | 3 | * Gary Jennejohn, DENX Software Engineering, garyj@denx.de. |
4 | * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com | 4 | * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com |
5 | * | 5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <common.h> | 9 | #include <common.h> |
10 | 10 | ||
11 | #include <command.h> | 11 | #include <command.h> |
12 | #include <image.h> | 12 | #include <image.h> |
13 | #include <asm/byteorder.h> | 13 | #include <asm/byteorder.h> |
14 | #include <fat.h> | 14 | #include <fat.h> |
15 | #include <flash.h> | 15 | #include <flash.h> |
16 | #include <part.h> | 16 | #include <part.h> |
17 | 17 | ||
18 | #include "auto_update.h" | 18 | #include "auto_update.h" |
19 | 19 | ||
20 | #ifdef CONFIG_AUTO_UPDATE | 20 | #ifdef CONFIG_AUTO_UPDATE |
21 | 21 | ||
22 | #if !defined(CONFIG_CMD_FAT) | 22 | #if !defined(CONFIG_CMD_FAT) |
23 | #error "must define CONFIG_CMD_FAT" | 23 | #error "must define CONFIG_CMD_FAT" |
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | extern au_image_t au_image[]; | 26 | extern au_image_t au_image[]; |
27 | extern int N_AU_IMAGES; | 27 | extern int N_AU_IMAGES; |
28 | 28 | ||
29 | /* where to load files into memory */ | 29 | /* where to load files into memory */ |
30 | #define LOAD_ADDR ((unsigned char *)0x100000) | 30 | #define LOAD_ADDR ((unsigned char *)0x100000) |
31 | #define MAX_LOADSZ 0x1c00000 | 31 | #define MAX_LOADSZ 0x1c00000 |
32 | 32 | ||
33 | /* externals */ | 33 | /* externals */ |
34 | extern int fat_register_device(block_dev_desc_t *, int); | ||
35 | extern int file_fat_detectfs(void); | ||
36 | extern long file_fat_read(const char *, void *, unsigned long); | ||
37 | long do_fat_read (const char *filename, void *buffer, | 34 | long do_fat_read (const char *filename, void *buffer, |
38 | unsigned long maxsize, int dols); | 35 | unsigned long maxsize, int dols); |
39 | 36 | ||
40 | extern block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE]; | 37 | extern block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE]; |
41 | 38 | ||
42 | int au_check_cksum_valid(int i, long nbytes) | 39 | int au_check_cksum_valid(int i, long nbytes) |
43 | { | 40 | { |
44 | image_header_t *hdr; | 41 | image_header_t *hdr; |
45 | 42 | ||
46 | hdr = (image_header_t *)LOAD_ADDR; | 43 | hdr = (image_header_t *)LOAD_ADDR; |
47 | #if defined(CONFIG_FIT) | 44 | #if defined(CONFIG_FIT) |
48 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { | 45 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { |
49 | puts ("Non legacy image format not supported\n"); | 46 | puts ("Non legacy image format not supported\n"); |
50 | return -1; | 47 | return -1; |
51 | } | 48 | } |
52 | #endif | 49 | #endif |
53 | 50 | ||
54 | if ((au_image[i].type == AU_FIRMWARE) && | 51 | if ((au_image[i].type == AU_FIRMWARE) && |
55 | (au_image[i].size != image_get_data_size (hdr))) { | 52 | (au_image[i].size != image_get_data_size (hdr))) { |
56 | printf ("Image %s has wrong size\n", au_image[i].name); | 53 | printf ("Image %s has wrong size\n", au_image[i].name); |
57 | return -1; | 54 | return -1; |
58 | } | 55 | } |
59 | 56 | ||
60 | if (nbytes != (image_get_image_size (hdr))) { | 57 | if (nbytes != (image_get_image_size (hdr))) { |
61 | printf ("Image %s bad total SIZE\n", au_image[i].name); | 58 | printf ("Image %s bad total SIZE\n", au_image[i].name); |
62 | return -1; | 59 | return -1; |
63 | } | 60 | } |
64 | 61 | ||
65 | /* check the data CRC */ | 62 | /* check the data CRC */ |
66 | if (!image_check_dcrc (hdr)) { | 63 | if (!image_check_dcrc (hdr)) { |
67 | printf ("Image %s bad data checksum\n", au_image[i].name); | 64 | printf ("Image %s bad data checksum\n", au_image[i].name); |
68 | return -1; | 65 | return -1; |
69 | } | 66 | } |
70 | return 0; | 67 | return 0; |
71 | } | 68 | } |
72 | 69 | ||
73 | int au_check_header_valid(int i, long nbytes) | 70 | int au_check_header_valid(int i, long nbytes) |
74 | { | 71 | { |
75 | image_header_t *hdr; | 72 | image_header_t *hdr; |
76 | 73 | ||
77 | hdr = (image_header_t *)LOAD_ADDR; | 74 | hdr = (image_header_t *)LOAD_ADDR; |
78 | #if defined(CONFIG_FIT) | 75 | #if defined(CONFIG_FIT) |
79 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { | 76 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { |
80 | puts ("Non legacy image format not supported\n"); | 77 | puts ("Non legacy image format not supported\n"); |
81 | return -1; | 78 | return -1; |
82 | } | 79 | } |
83 | #endif | 80 | #endif |
84 | 81 | ||
85 | /* check the easy ones first */ | 82 | /* check the easy ones first */ |
86 | if (nbytes < image_get_header_size ()) { | 83 | if (nbytes < image_get_header_size ()) { |
87 | printf ("Image %s bad header SIZE\n", au_image[i].name); | 84 | printf ("Image %s bad header SIZE\n", au_image[i].name); |
88 | return -1; | 85 | return -1; |
89 | } | 86 | } |
90 | if (!image_check_magic (hdr) || !image_check_arch (hdr, IH_ARCH_PPC)) { | 87 | if (!image_check_magic (hdr) || !image_check_arch (hdr, IH_ARCH_PPC)) { |
91 | printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name); | 88 | printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name); |
92 | return -1; | 89 | return -1; |
93 | } | 90 | } |
94 | if (!image_check_hcrc (hdr)) { | 91 | if (!image_check_hcrc (hdr)) { |
95 | printf ("Image %s bad header checksum\n", au_image[i].name); | 92 | printf ("Image %s bad header checksum\n", au_image[i].name); |
96 | return -1; | 93 | return -1; |
97 | } | 94 | } |
98 | 95 | ||
99 | /* check the type - could do this all in one gigantic if() */ | 96 | /* check the type - could do this all in one gigantic if() */ |
100 | if (((au_image[i].type & AU_TYPEMASK) == AU_FIRMWARE) && | 97 | if (((au_image[i].type & AU_TYPEMASK) == AU_FIRMWARE) && |
101 | !image_check_type (hdr, IH_TYPE_FIRMWARE)) { | 98 | !image_check_type (hdr, IH_TYPE_FIRMWARE)) { |
102 | printf ("Image %s wrong type\n", au_image[i].name); | 99 | printf ("Image %s wrong type\n", au_image[i].name); |
103 | return -1; | 100 | return -1; |
104 | } | 101 | } |
105 | if (((au_image[i].type & AU_TYPEMASK) == AU_SCRIPT) && | 102 | if (((au_image[i].type & AU_TYPEMASK) == AU_SCRIPT) && |
106 | !image_check_type (hdr, IH_TYPE_SCRIPT)) { | 103 | !image_check_type (hdr, IH_TYPE_SCRIPT)) { |
107 | printf ("Image %s wrong type\n", au_image[i].name); | 104 | printf ("Image %s wrong type\n", au_image[i].name); |
108 | return -1; | 105 | return -1; |
109 | } | 106 | } |
110 | 107 | ||
111 | return 0; | 108 | return 0; |
112 | } | 109 | } |
113 | 110 | ||
114 | int au_do_update(int i, long sz) | 111 | int au_do_update(int i, long sz) |
115 | { | 112 | { |
116 | image_header_t *hdr; | 113 | image_header_t *hdr; |
117 | char *addr; | 114 | char *addr; |
118 | long start, end; | 115 | long start, end; |
119 | int off, rc; | 116 | int off, rc; |
120 | uint nbytes; | 117 | uint nbytes; |
121 | int k; | 118 | int k; |
122 | 119 | ||
123 | hdr = (image_header_t *)LOAD_ADDR; | 120 | hdr = (image_header_t *)LOAD_ADDR; |
124 | #if defined(CONFIG_FIT) | 121 | #if defined(CONFIG_FIT) |
125 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { | 122 | if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { |
126 | puts ("Non legacy image format not supported\n"); | 123 | puts ("Non legacy image format not supported\n"); |
127 | return -1; | 124 | return -1; |
128 | } | 125 | } |
129 | #endif | 126 | #endif |
130 | 127 | ||
131 | switch (au_image[i].type & AU_TYPEMASK) { | 128 | switch (au_image[i].type & AU_TYPEMASK) { |
132 | case AU_SCRIPT: | 129 | case AU_SCRIPT: |
133 | printf("Executing script %s\n", au_image[i].name); | 130 | printf("Executing script %s\n", au_image[i].name); |
134 | 131 | ||
135 | /* execute a script */ | 132 | /* execute a script */ |
136 | if (image_check_type (hdr, IH_TYPE_SCRIPT)) { | 133 | if (image_check_type (hdr, IH_TYPE_SCRIPT)) { |
137 | addr = (char *)((char *)hdr + image_get_header_size ()); | 134 | addr = (char *)((char *)hdr + image_get_header_size ()); |
138 | /* stick a NULL at the end of the script, otherwise */ | 135 | /* stick a NULL at the end of the script, otherwise */ |
139 | /* parse_string_outer() runs off the end. */ | 136 | /* parse_string_outer() runs off the end. */ |
140 | addr[image_get_data_size (hdr)] = 0; | 137 | addr[image_get_data_size (hdr)] = 0; |
141 | addr += 8; | 138 | addr += 8; |
142 | 139 | ||
143 | /* | 140 | /* |
144 | * Replace cr/lf with ; | 141 | * Replace cr/lf with ; |
145 | */ | 142 | */ |
146 | k = 0; | 143 | k = 0; |
147 | while (addr[k] != 0) { | 144 | while (addr[k] != 0) { |
148 | if ((addr[k] == 10) || (addr[k] == 13)) { | 145 | if ((addr[k] == 10) || (addr[k] == 13)) { |
149 | addr[k] = ';'; | 146 | addr[k] = ';'; |
150 | } | 147 | } |
151 | k++; | 148 | k++; |
152 | } | 149 | } |
153 | 150 | ||
154 | run_command(addr, 0); | 151 | run_command(addr, 0); |
155 | return 0; | 152 | return 0; |
156 | } | 153 | } |
157 | 154 | ||
158 | break; | 155 | break; |
159 | 156 | ||
160 | case AU_FIRMWARE: | 157 | case AU_FIRMWARE: |
161 | case AU_NOR: | 158 | case AU_NOR: |
162 | case AU_NAND: | 159 | case AU_NAND: |
163 | start = au_image[i].start; | 160 | start = au_image[i].start; |
164 | end = au_image[i].start + au_image[i].size - 1; | 161 | end = au_image[i].start + au_image[i].size - 1; |
165 | 162 | ||
166 | /* | 163 | /* |
167 | * do not update firmware when image is already in flash. | 164 | * do not update firmware when image is already in flash. |
168 | */ | 165 | */ |
169 | if (au_image[i].type == AU_FIRMWARE) { | 166 | if (au_image[i].type == AU_FIRMWARE) { |
170 | char *orig = (char*)start; | 167 | char *orig = (char*)start; |
171 | char *new = (char *)((char *)hdr + | 168 | char *new = (char *)((char *)hdr + |
172 | image_get_header_size ()); | 169 | image_get_header_size ()); |
173 | nbytes = image_get_data_size (hdr); | 170 | nbytes = image_get_data_size (hdr); |
174 | 171 | ||
175 | while (--nbytes) { | 172 | while (--nbytes) { |
176 | if (*orig++ != *new++) { | 173 | if (*orig++ != *new++) { |
177 | break; | 174 | break; |
178 | } | 175 | } |
179 | } | 176 | } |
180 | if (!nbytes) { | 177 | if (!nbytes) { |
181 | printf ("Skipping firmware update - " | 178 | printf ("Skipping firmware update - " |
182 | "images are identical\n"); | 179 | "images are identical\n"); |
183 | break; | 180 | break; |
184 | } | 181 | } |
185 | } | 182 | } |
186 | 183 | ||
187 | /* unprotect the address range */ | 184 | /* unprotect the address range */ |
188 | if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || | 185 | if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || |
189 | (au_image[i].type == AU_FIRMWARE)) { | 186 | (au_image[i].type == AU_FIRMWARE)) { |
190 | flash_sect_protect (0, start, end); | 187 | flash_sect_protect (0, start, end); |
191 | } | 188 | } |
192 | 189 | ||
193 | /* | 190 | /* |
194 | * erase the address range. | 191 | * erase the address range. |
195 | */ | 192 | */ |
196 | if (au_image[i].type != AU_NAND) { | 193 | if (au_image[i].type != AU_NAND) { |
197 | printf ("Updating NOR FLASH with image %s\n", | 194 | printf ("Updating NOR FLASH with image %s\n", |
198 | au_image[i].name); | 195 | au_image[i].name); |
199 | debug ("flash_sect_erase(%lx, %lx);\n", start, end); | 196 | debug ("flash_sect_erase(%lx, %lx);\n", start, end); |
200 | flash_sect_erase (start, end); | 197 | flash_sect_erase (start, end); |
201 | } | 198 | } |
202 | 199 | ||
203 | udelay(10000); | 200 | udelay(10000); |
204 | 201 | ||
205 | /* strip the header - except for the kernel and ramdisk */ | 202 | /* strip the header - except for the kernel and ramdisk */ |
206 | if (au_image[i].type != AU_FIRMWARE) { | 203 | if (au_image[i].type != AU_FIRMWARE) { |
207 | addr = (char *)hdr; | 204 | addr = (char *)hdr; |
208 | off = image_get_header_size (); | 205 | off = image_get_header_size (); |
209 | nbytes = image_get_image_size (hdr); | 206 | nbytes = image_get_image_size (hdr); |
210 | } else { | 207 | } else { |
211 | addr = (char *)((char *)hdr + image_get_header_size ()); | 208 | addr = (char *)((char *)hdr + image_get_header_size ()); |
212 | off = 0; | 209 | off = 0; |
213 | nbytes = image_get_data_size (hdr); | 210 | nbytes = image_get_data_size (hdr); |
214 | } | 211 | } |
215 | 212 | ||
216 | /* | 213 | /* |
217 | * copy the data from RAM to FLASH | 214 | * copy the data from RAM to FLASH |
218 | */ | 215 | */ |
219 | if (au_image[i].type != AU_NAND) { | 216 | if (au_image[i].type != AU_NAND) { |
220 | debug ("flash_write(%p, %lx, %x)\n", | 217 | debug ("flash_write(%p, %lx, %x)\n", |
221 | addr, start, nbytes); | 218 | addr, start, nbytes); |
222 | rc = flash_write ((char *)addr, start, | 219 | rc = flash_write ((char *)addr, start, |
223 | (nbytes + 1) & ~1); | 220 | (nbytes + 1) & ~1); |
224 | } else { | 221 | } else { |
225 | rc = -1; | 222 | rc = -1; |
226 | } | 223 | } |
227 | if (rc != 0) { | 224 | if (rc != 0) { |
228 | printf ("Flashing failed due to error %d\n", rc); | 225 | printf ("Flashing failed due to error %d\n", rc); |
229 | return -1; | 226 | return -1; |
230 | } | 227 | } |
231 | 228 | ||
232 | /* | 229 | /* |
233 | * check the dcrc of the copy | 230 | * check the dcrc of the copy |
234 | */ | 231 | */ |
235 | if (au_image[i].type != AU_NAND) { | 232 | if (au_image[i].type != AU_NAND) { |
236 | rc = crc32 (0, (uchar *)(start + off), | 233 | rc = crc32 (0, (uchar *)(start + off), |
237 | image_get_data_size (hdr)); | 234 | image_get_data_size (hdr)); |
238 | } | 235 | } |
239 | if (rc != image_get_dcrc (hdr)) { | 236 | if (rc != image_get_dcrc (hdr)) { |
240 | printf ("Image %s Bad Data Checksum After COPY\n", | 237 | printf ("Image %s Bad Data Checksum After COPY\n", |
241 | au_image[i].name); | 238 | au_image[i].name); |
242 | return -1; | 239 | return -1; |
243 | } | 240 | } |
244 | 241 | ||
245 | /* protect the address range */ | 242 | /* protect the address range */ |
246 | /* this assumes that ONLY the firmware is protected! */ | 243 | /* this assumes that ONLY the firmware is protected! */ |
247 | if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || | 244 | if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || |
248 | (au_image[i].type == AU_FIRMWARE)) { | 245 | (au_image[i].type == AU_FIRMWARE)) { |
249 | flash_sect_protect (1, start, end); | 246 | flash_sect_protect (1, start, end); |
250 | } | 247 | } |
251 | 248 | ||
252 | break; | 249 | break; |
253 | 250 | ||
254 | default: | 251 | default: |
255 | printf("Wrong image type selected!\n"); | 252 | printf("Wrong image type selected!\n"); |
256 | } | 253 | } |
257 | 254 | ||
258 | return 0; | 255 | return 0; |
259 | } | 256 | } |
260 | 257 | ||
261 | static void process_macros (const char *input, char *output) | 258 | static void process_macros (const char *input, char *output) |
262 | { | 259 | { |
263 | char c, prev; | 260 | char c, prev; |
264 | const char *varname_start = NULL; | 261 | const char *varname_start = NULL; |
265 | int inputcnt = strlen (input); | 262 | int inputcnt = strlen (input); |
266 | int outputcnt = CONFIG_SYS_CBSIZE; | 263 | int outputcnt = CONFIG_SYS_CBSIZE; |
267 | int state = 0; /* 0 = waiting for '$' */ | 264 | int state = 0; /* 0 = waiting for '$' */ |
268 | /* 1 = waiting for '(' or '{' */ | 265 | /* 1 = waiting for '(' or '{' */ |
269 | /* 2 = waiting for ')' or '}' */ | 266 | /* 2 = waiting for ')' or '}' */ |
270 | /* 3 = waiting for ''' */ | 267 | /* 3 = waiting for ''' */ |
271 | #ifdef DEBUG_PARSER | 268 | #ifdef DEBUG_PARSER |
272 | char *output_start = output; | 269 | char *output_start = output; |
273 | 270 | ||
274 | printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", | 271 | printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", |
275 | strlen(input), input); | 272 | strlen(input), input); |
276 | #endif | 273 | #endif |
277 | 274 | ||
278 | prev = '\0'; /* previous character */ | 275 | prev = '\0'; /* previous character */ |
279 | 276 | ||
280 | while (inputcnt && outputcnt) { | 277 | while (inputcnt && outputcnt) { |
281 | c = *input++; | 278 | c = *input++; |
282 | inputcnt--; | 279 | inputcnt--; |
283 | 280 | ||
284 | if (state != 3) { | 281 | if (state != 3) { |
285 | /* remove one level of escape characters */ | 282 | /* remove one level of escape characters */ |
286 | if ((c == '\\') && (prev != '\\')) { | 283 | if ((c == '\\') && (prev != '\\')) { |
287 | if (inputcnt-- == 0) | 284 | if (inputcnt-- == 0) |
288 | break; | 285 | break; |
289 | prev = c; | 286 | prev = c; |
290 | c = *input++; | 287 | c = *input++; |
291 | } | 288 | } |
292 | } | 289 | } |
293 | 290 | ||
294 | switch (state) { | 291 | switch (state) { |
295 | case 0: /* Waiting for (unescaped) $ */ | 292 | case 0: /* Waiting for (unescaped) $ */ |
296 | if ((c == '\'') && (prev != '\\')) { | 293 | if ((c == '\'') && (prev != '\\')) { |
297 | state = 3; | 294 | state = 3; |
298 | break; | 295 | break; |
299 | } | 296 | } |
300 | if ((c == '$') && (prev != '\\')) { | 297 | if ((c == '$') && (prev != '\\')) { |
301 | state++; | 298 | state++; |
302 | } else { | 299 | } else { |
303 | *(output++) = c; | 300 | *(output++) = c; |
304 | outputcnt--; | 301 | outputcnt--; |
305 | } | 302 | } |
306 | break; | 303 | break; |
307 | case 1: /* Waiting for ( */ | 304 | case 1: /* Waiting for ( */ |
308 | if (c == '(' || c == '{') { | 305 | if (c == '(' || c == '{') { |
309 | state++; | 306 | state++; |
310 | varname_start = input; | 307 | varname_start = input; |
311 | } else { | 308 | } else { |
312 | state = 0; | 309 | state = 0; |
313 | *(output++) = '$'; | 310 | *(output++) = '$'; |
314 | outputcnt--; | 311 | outputcnt--; |
315 | 312 | ||
316 | if (outputcnt) { | 313 | if (outputcnt) { |
317 | *(output++) = c; | 314 | *(output++) = c; |
318 | outputcnt--; | 315 | outputcnt--; |
319 | } | 316 | } |
320 | } | 317 | } |
321 | break; | 318 | break; |
322 | case 2: /* Waiting for ) */ | 319 | case 2: /* Waiting for ) */ |
323 | if (c == ')' || c == '}') { | 320 | if (c == ')' || c == '}') { |
324 | int i; | 321 | int i; |
325 | char envname[CONFIG_SYS_CBSIZE], *envval; | 322 | char envname[CONFIG_SYS_CBSIZE], *envval; |
326 | /* Varname # of chars */ | 323 | /* Varname # of chars */ |
327 | int envcnt = input - varname_start - 1; | 324 | int envcnt = input - varname_start - 1; |
328 | 325 | ||
329 | /* Get the varname */ | 326 | /* Get the varname */ |
330 | for (i = 0; i < envcnt; i++) { | 327 | for (i = 0; i < envcnt; i++) { |
331 | envname[i] = varname_start[i]; | 328 | envname[i] = varname_start[i]; |
332 | } | 329 | } |
333 | envname[i] = 0; | 330 | envname[i] = 0; |
334 | 331 | ||
335 | /* Get its value */ | 332 | /* Get its value */ |
336 | envval = getenv (envname); | 333 | envval = getenv (envname); |
337 | 334 | ||
338 | /* Copy into the line if it exists */ | 335 | /* Copy into the line if it exists */ |
339 | if (envval != NULL) | 336 | if (envval != NULL) |
340 | while ((*envval) && outputcnt) { | 337 | while ((*envval) && outputcnt) { |
341 | *(output++) = *(envval++); | 338 | *(output++) = *(envval++); |
342 | outputcnt--; | 339 | outputcnt--; |
343 | } | 340 | } |
344 | /* Look for another '$' */ | 341 | /* Look for another '$' */ |
345 | state = 0; | 342 | state = 0; |
346 | } | 343 | } |
347 | break; | 344 | break; |
348 | case 3: /* Waiting for ' */ | 345 | case 3: /* Waiting for ' */ |
349 | if ((c == '\'') && (prev != '\\')) { | 346 | if ((c == '\'') && (prev != '\\')) { |
350 | state = 0; | 347 | state = 0; |
351 | } else { | 348 | } else { |
352 | *(output++) = c; | 349 | *(output++) = c; |
353 | outputcnt--; | 350 | outputcnt--; |
354 | } | 351 | } |
355 | break; | 352 | break; |
356 | } | 353 | } |
357 | prev = c; | 354 | prev = c; |
358 | } | 355 | } |
359 | 356 | ||
360 | if (outputcnt) | 357 | if (outputcnt) |
361 | *output = 0; | 358 | *output = 0; |
362 | 359 | ||
363 | #ifdef DEBUG_PARSER | 360 | #ifdef DEBUG_PARSER |
364 | printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", | 361 | printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", |
365 | strlen (output_start), output_start); | 362 | strlen (output_start), output_start); |
366 | #endif | 363 | #endif |
367 | } | 364 | } |
368 | 365 | ||
369 | /* | 366 | /* |
370 | * this is called from board_init() after the hardware has been set up | 367 | * this is called from board_init() after the hardware has been set up |
371 | * and is usable. That seems like a good time to do this. | 368 | * and is usable. That seems like a good time to do this. |
372 | * Right now the return value is ignored. | 369 | * Right now the return value is ignored. |
373 | */ | 370 | */ |
374 | int do_auto_update(void) | 371 | int do_auto_update(void) |
375 | { | 372 | { |
376 | block_dev_desc_t *stor_dev = NULL; | 373 | block_dev_desc_t *stor_dev = NULL; |
377 | long sz; | 374 | long sz; |
378 | int i, res, old_ctrlc; | 375 | int i, res, old_ctrlc; |
379 | char buffer[32]; | 376 | char buffer[32]; |
380 | char str[80]; | 377 | char str[80]; |
381 | int n; | 378 | int n; |
382 | 379 | ||
383 | if (ide_dev_desc[0].type != DEV_TYPE_UNKNOWN) { | 380 | if (ide_dev_desc[0].type != DEV_TYPE_UNKNOWN) { |
384 | stor_dev = get_dev ("ide", 0); | 381 | stor_dev = get_dev ("ide", 0); |
385 | if (stor_dev == NULL) { | 382 | if (stor_dev == NULL) { |
386 | debug ("ide: unknown device\n"); | 383 | debug ("ide: unknown device\n"); |
387 | return -1; | 384 | return -1; |
388 | } | 385 | } |
389 | } | 386 | } |
390 | 387 | ||
391 | if (fat_register_device (stor_dev, 1) != 0) { | 388 | if (fat_register_device (stor_dev, 1) != 0) { |
392 | debug ("Unable to register ide disk 0:1\n"); | 389 | debug ("Unable to register ide disk 0:1\n"); |
393 | return -1; | 390 | return -1; |
394 | } | 391 | } |
395 | 392 | ||
396 | /* | 393 | /* |
397 | * Check if magic file is present | 394 | * Check if magic file is present |
398 | */ | 395 | */ |
399 | if ((n = do_fat_read (AU_MAGIC_FILE, buffer, | 396 | if ((n = do_fat_read (AU_MAGIC_FILE, buffer, |
400 | sizeof(buffer), LS_NO)) <= 0) { | 397 | sizeof(buffer), LS_NO)) <= 0) { |
401 | debug ("No auto_update magic file (n=%d)\n", n); | 398 | debug ("No auto_update magic file (n=%d)\n", n); |
402 | return -1; | 399 | return -1; |
403 | } | 400 | } |
404 | 401 | ||
405 | #ifdef CONFIG_AUTO_UPDATE_SHOW | 402 | #ifdef CONFIG_AUTO_UPDATE_SHOW |
406 | board_auto_update_show (1); | 403 | board_auto_update_show (1); |
407 | #endif | 404 | #endif |
408 | puts("\nAutoUpdate Disk detected! Trying to update system...\n"); | 405 | puts("\nAutoUpdate Disk detected! Trying to update system...\n"); |
409 | 406 | ||
410 | /* make sure that we see CTRL-C and save the old state */ | 407 | /* make sure that we see CTRL-C and save the old state */ |
411 | old_ctrlc = disable_ctrlc (0); | 408 | old_ctrlc = disable_ctrlc (0); |
412 | 409 | ||
413 | /* just loop thru all the possible files */ | 410 | /* just loop thru all the possible files */ |
414 | for (i = 0; i < N_AU_IMAGES; i++) { | 411 | for (i = 0; i < N_AU_IMAGES; i++) { |
415 | /* | 412 | /* |
416 | * Try to expand the environment var in the fname | 413 | * Try to expand the environment var in the fname |
417 | */ | 414 | */ |
418 | process_macros (au_image[i].name, str); | 415 | process_macros (au_image[i].name, str); |
419 | strcpy (au_image[i].name, str); | 416 | strcpy (au_image[i].name, str); |
420 | 417 | ||
421 | printf("Reading %s ...", au_image[i].name); | 418 | printf("Reading %s ...", au_image[i].name); |
422 | /* just read the header */ | 419 | /* just read the header */ |
423 | sz = do_fat_read (au_image[i].name, LOAD_ADDR, | 420 | sz = do_fat_read (au_image[i].name, LOAD_ADDR, |
424 | image_get_header_size (), LS_NO); | 421 | image_get_header_size (), LS_NO); |
425 | debug ("read %s sz %ld hdr %d\n", | 422 | debug ("read %s sz %ld hdr %d\n", |
426 | au_image[i].name, sz, image_get_header_size ()); | 423 | au_image[i].name, sz, image_get_header_size ()); |
427 | if (sz <= 0 || sz < image_get_header_size ()) { | 424 | if (sz <= 0 || sz < image_get_header_size ()) { |
428 | puts(" not found\n"); | 425 | puts(" not found\n"); |
429 | continue; | 426 | continue; |
430 | } | 427 | } |
431 | if (au_check_header_valid (i, sz) < 0) { | 428 | if (au_check_header_valid (i, sz) < 0) { |
432 | puts(" header not valid\n"); | 429 | puts(" header not valid\n"); |
433 | continue; | 430 | continue; |
434 | } | 431 | } |
435 | sz = do_fat_read (au_image[i].name, LOAD_ADDR, | 432 | sz = do_fat_read (au_image[i].name, LOAD_ADDR, |
436 | MAX_LOADSZ, LS_NO); | 433 | MAX_LOADSZ, LS_NO); |
437 | debug ("read %s sz %ld hdr %d\n", | 434 | debug ("read %s sz %ld hdr %d\n", |
438 | au_image[i].name, sz, image_get_header_size ()); | 435 | au_image[i].name, sz, image_get_header_size ()); |
439 | if (sz <= 0 || sz <= image_get_header_size ()) { | 436 | if (sz <= 0 || sz <= image_get_header_size ()) { |
440 | puts(" not found\n"); | 437 | puts(" not found\n"); |
441 | continue; | 438 | continue; |
442 | } | 439 | } |
443 | if (au_check_cksum_valid (i, sz) < 0) { | 440 | if (au_check_cksum_valid (i, sz) < 0) { |
444 | puts(" checksum not valid\n"); | 441 | puts(" checksum not valid\n"); |
445 | continue; | 442 | continue; |
446 | } | 443 | } |
447 | puts(" done\n"); | 444 | puts(" done\n"); |
448 | 445 | ||
449 | do { | 446 | do { |
450 | res = au_do_update (i, sz); | 447 | res = au_do_update (i, sz); |
451 | /* let the user break out of the loop */ | 448 | /* let the user break out of the loop */ |
452 | if (ctrlc() || had_ctrlc ()) { | 449 | if (ctrlc() || had_ctrlc ()) { |
453 | clear_ctrlc (); | 450 | clear_ctrlc (); |
454 | break; | 451 | break; |
455 | } | 452 | } |
456 | } while (res < 0); | 453 | } while (res < 0); |
457 | } | 454 | } |
458 | 455 | ||
459 | /* restore the old state */ | 456 | /* restore the old state */ |
460 | disable_ctrlc (old_ctrlc); | 457 | disable_ctrlc (old_ctrlc); |
461 | 458 | ||
462 | puts("AutoUpdate finished\n\n"); | 459 | puts("AutoUpdate finished\n\n"); |
463 | #ifdef CONFIG_AUTO_UPDATE_SHOW | 460 | #ifdef CONFIG_AUTO_UPDATE_SHOW |
464 | board_auto_update_show (0); | 461 | board_auto_update_show (0); |
465 | #endif | 462 | #endif |
466 | 463 | ||
467 | return 0; | 464 | return 0; |
468 | } | 465 | } |
469 | 466 | ||
470 | int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 467 | int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
471 | { | 468 | { |
472 | do_auto_update(); | 469 | do_auto_update(); |
473 | 470 | ||
474 | return 0; | 471 | return 0; |
475 | } | 472 | } |
476 | U_BOOT_CMD( | 473 | U_BOOT_CMD( |
477 | autoupd, 1, 1, auto_update, | 474 | autoupd, 1, 1, auto_update, |
478 | "Automatically update images", | 475 | "Automatically update images", |
479 | "" | 476 | "" |
480 | ); | 477 | ); |
481 | #endif /* CONFIG_AUTO_UPDATE */ | 478 | #endif /* CONFIG_AUTO_UPDATE */ |
482 | 479 |
common/cmd_fat.c
1 | /* | 1 | /* |
2 | * (C) Copyright 2002 | 2 | * (C) Copyright 2002 |
3 | * Richard Jones, rjones@nexus-tech.net | 3 | * Richard Jones, rjones@nexus-tech.net |
4 | * | 4 | * |
5 | * SPDX-License-Identifier: GPL-2.0+ | 5 | * SPDX-License-Identifier: GPL-2.0+ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | /* | 8 | /* |
9 | * Boot support | 9 | * Boot support |
10 | */ | 10 | */ |
11 | #include <common.h> | 11 | #include <common.h> |
12 | #include <command.h> | 12 | #include <command.h> |
13 | #include <s_record.h> | 13 | #include <s_record.h> |
14 | #include <net.h> | 14 | #include <net.h> |
15 | #include <ata.h> | 15 | #include <ata.h> |
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | #include <part.h> | 17 | #include <part.h> |
18 | #include <fat.h> | 18 | #include <fat.h> |
19 | #include <fs.h> | 19 | #include <fs.h> |
20 | 20 | ||
21 | int do_fat_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 21 | int do_fat_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
22 | { | 22 | { |
23 | return do_size(cmdtp, flag, argc, argv, FS_TYPE_FAT); | 23 | return do_size(cmdtp, flag, argc, argv, FS_TYPE_FAT); |
24 | } | 24 | } |
25 | 25 | ||
26 | U_BOOT_CMD( | 26 | U_BOOT_CMD( |
27 | fatsize, 4, 0, do_fat_size, | 27 | fatsize, 4, 0, do_fat_size, |
28 | "determine a file's size", | 28 | "determine a file's size", |
29 | "<interface> <dev[:part]> <filename>\n" | 29 | "<interface> <dev[:part]> <filename>\n" |
30 | " - Find file 'filename' from 'dev' on 'interface'\n" | 30 | " - Find file 'filename' from 'dev' on 'interface'\n" |
31 | " and determine its size." | 31 | " and determine its size." |
32 | ); | 32 | ); |
33 | 33 | ||
34 | int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 34 | int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
35 | { | 35 | { |
36 | return do_load(cmdtp, flag, argc, argv, FS_TYPE_FAT); | 36 | return do_load(cmdtp, flag, argc, argv, FS_TYPE_FAT); |
37 | } | 37 | } |
38 | 38 | ||
39 | 39 | ||
40 | U_BOOT_CMD( | 40 | U_BOOT_CMD( |
41 | fatload, 7, 0, do_fat_fsload, | 41 | fatload, 7, 0, do_fat_fsload, |
42 | "load binary file from a dos filesystem", | 42 | "load binary file from a dos filesystem", |
43 | "<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n" | 43 | "<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]\n" |
44 | " - Load binary file 'filename' from 'dev' on 'interface'\n" | 44 | " - Load binary file 'filename' from 'dev' on 'interface'\n" |
45 | " to address 'addr' from dos filesystem.\n" | 45 | " to address 'addr' from dos filesystem.\n" |
46 | " 'pos' gives the file position to start loading from.\n" | 46 | " 'pos' gives the file position to start loading from.\n" |
47 | " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n" | 47 | " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n" |
48 | " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n" | 48 | " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n" |
49 | " the load stops on end of file.\n" | 49 | " the load stops on end of file.\n" |
50 | " If either 'pos' or 'bytes' are not aligned to\n" | 50 | " If either 'pos' or 'bytes' are not aligned to\n" |
51 | " ARCH_DMA_MINALIGN then a misaligned buffer warning will\n" | 51 | " ARCH_DMA_MINALIGN then a misaligned buffer warning will\n" |
52 | " be printed and performance will suffer for the load." | 52 | " be printed and performance will suffer for the load." |
53 | ); | 53 | ); |
54 | 54 | ||
55 | static int do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 55 | static int do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
56 | { | 56 | { |
57 | return do_ls(cmdtp, flag, argc, argv, FS_TYPE_FAT); | 57 | return do_ls(cmdtp, flag, argc, argv, FS_TYPE_FAT); |
58 | } | 58 | } |
59 | 59 | ||
60 | U_BOOT_CMD( | 60 | U_BOOT_CMD( |
61 | fatls, 4, 1, do_fat_ls, | 61 | fatls, 4, 1, do_fat_ls, |
62 | "list files in a directory (default /)", | 62 | "list files in a directory (default /)", |
63 | "<interface> [<dev[:part]>] [directory]\n" | 63 | "<interface> [<dev[:part]>] [directory]\n" |
64 | " - list files from 'dev' on 'interface' in a 'directory'" | 64 | " - list files from 'dev' on 'interface' in a 'directory'" |
65 | ); | 65 | ); |
66 | 66 | ||
67 | static int do_fat_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, | 67 | static int do_fat_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, |
68 | char * const argv[]) | 68 | char * const argv[]) |
69 | { | 69 | { |
70 | int dev, part; | 70 | int dev, part; |
71 | block_dev_desc_t *dev_desc; | 71 | block_dev_desc_t *dev_desc; |
72 | disk_partition_t info; | 72 | disk_partition_t info; |
73 | 73 | ||
74 | if (argc < 2) { | 74 | if (argc < 2) { |
75 | printf("usage: fatinfo <interface> [<dev[:part]>]\n"); | 75 | printf("usage: fatinfo <interface> [<dev[:part]>]\n"); |
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); | 79 | part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); |
80 | if (part < 0) | 80 | if (part < 0) |
81 | return 1; | 81 | return 1; |
82 | 82 | ||
83 | dev = dev_desc->dev; | 83 | dev = dev_desc->dev; |
84 | if (fat_set_blk_dev(dev_desc, &info) != 0) { | 84 | if (fat_set_blk_dev(dev_desc, &info) != 0) { |
85 | printf("\n** Unable to use %s %d:%d for fatinfo **\n", | 85 | printf("\n** Unable to use %s %d:%d for fatinfo **\n", |
86 | argv[1], dev, part); | 86 | argv[1], dev, part); |
87 | return 1; | 87 | return 1; |
88 | } | 88 | } |
89 | return file_fat_detectfs(); | 89 | return file_fat_detectfs(); |
90 | } | 90 | } |
91 | 91 | ||
92 | U_BOOT_CMD( | 92 | U_BOOT_CMD( |
93 | fatinfo, 3, 1, do_fat_fsinfo, | 93 | fatinfo, 3, 1, do_fat_fsinfo, |
94 | "print information about filesystem", | 94 | "print information about filesystem", |
95 | "<interface> [<dev[:part]>]\n" | 95 | "<interface> [<dev[:part]>]\n" |
96 | " - print information about filesystem from 'dev' on 'interface'" | 96 | " - print information about filesystem from 'dev' on 'interface'" |
97 | ); | 97 | ); |
98 | 98 | ||
99 | #ifdef CONFIG_FAT_WRITE | 99 | #ifdef CONFIG_FAT_WRITE |
100 | static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, | 100 | static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, |
101 | int argc, char * const argv[]) | 101 | int argc, char * const argv[]) |
102 | { | 102 | { |
103 | long size; | 103 | loff_t size; |
104 | int ret; | ||
104 | unsigned long addr; | 105 | unsigned long addr; |
105 | unsigned long count; | 106 | unsigned long count; |
106 | block_dev_desc_t *dev_desc = NULL; | 107 | block_dev_desc_t *dev_desc = NULL; |
107 | disk_partition_t info; | 108 | disk_partition_t info; |
108 | int dev = 0; | 109 | int dev = 0; |
109 | int part = 1; | 110 | int part = 1; |
110 | void *buf; | 111 | void *buf; |
111 | 112 | ||
112 | if (argc < 5) | 113 | if (argc < 5) |
113 | return cmd_usage(cmdtp); | 114 | return cmd_usage(cmdtp); |
114 | 115 | ||
115 | part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); | 116 | part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); |
116 | if (part < 0) | 117 | if (part < 0) |
117 | return 1; | 118 | return 1; |
118 | 119 | ||
119 | dev = dev_desc->dev; | 120 | dev = dev_desc->dev; |
120 | 121 | ||
121 | if (fat_set_blk_dev(dev_desc, &info) != 0) { | 122 | if (fat_set_blk_dev(dev_desc, &info) != 0) { |
122 | printf("\n** Unable to use %s %d:%d for fatwrite **\n", | 123 | printf("\n** Unable to use %s %d:%d for fatwrite **\n", |
123 | argv[1], dev, part); | 124 | argv[1], dev, part); |
124 | return 1; | 125 | return 1; |
125 | } | 126 | } |
126 | addr = simple_strtoul(argv[3], NULL, 16); | 127 | addr = simple_strtoul(argv[3], NULL, 16); |
127 | count = simple_strtoul(argv[5], NULL, 16); | 128 | count = simple_strtoul(argv[5], NULL, 16); |
128 | 129 | ||
129 | buf = map_sysmem(addr, count); | 130 | buf = map_sysmem(addr, count); |
130 | size = file_fat_write(argv[4], buf, count); | 131 | ret = file_fat_write(argv[4], buf, 0, count, &size); |
131 | unmap_sysmem(buf); | 132 | unmap_sysmem(buf); |
132 | if (size == -1) { | 133 | if (ret < 0) { |
133 | printf("\n** Unable to write \"%s\" from %s %d:%d **\n", | 134 | printf("\n** Unable to write \"%s\" from %s %d:%d **\n", |
134 | argv[4], argv[1], dev, part); | 135 | argv[4], argv[1], dev, part); |
135 | return 1; | 136 | return 1; |
136 | } | 137 | } |
137 | 138 | ||
138 | printf("%ld bytes written\n", size); | 139 | printf("%llu bytes written\n", size); |
139 | 140 | ||
140 | return 0; | 141 | return 0; |
141 | } | 142 | } |
142 | 143 | ||
143 | U_BOOT_CMD( | 144 | U_BOOT_CMD( |
144 | fatwrite, 6, 0, do_fat_fswrite, | 145 | fatwrite, 6, 0, do_fat_fswrite, |
145 | "write file into a dos filesystem", | 146 | "write file into a dos filesystem", |
146 | "<interface> <dev[:part]> <addr> <filename> <bytes>\n" | 147 | "<interface> <dev[:part]> <addr> <filename> <bytes>\n" |
147 | " - write file 'filename' from the address 'addr' in RAM\n" | 148 | " - write file 'filename' from the address 'addr' in RAM\n" |
148 | " to 'dev' on 'interface'" | 149 | " to 'dev' on 'interface'" |
149 | ); | 150 | ); |
150 | #endif | 151 | #endif |
151 | 152 |
common/env_fat.c
1 | /* | 1 | /* |
2 | * (c) Copyright 2011 by Tigris Elektronik GmbH | 2 | * (c) Copyright 2011 by Tigris Elektronik GmbH |
3 | * | 3 | * |
4 | * Author: | 4 | * Author: |
5 | * Maximilian Schwerin <mvs@tigris.de> | 5 | * Maximilian Schwerin <mvs@tigris.de> |
6 | * | 6 | * |
7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <common.h> | 10 | #include <common.h> |
11 | 11 | ||
12 | #include <command.h> | 12 | #include <command.h> |
13 | #include <environment.h> | 13 | #include <environment.h> |
14 | #include <linux/stddef.h> | 14 | #include <linux/stddef.h> |
15 | #include <malloc.h> | 15 | #include <malloc.h> |
16 | #include <search.h> | 16 | #include <search.h> |
17 | #include <errno.h> | 17 | #include <errno.h> |
18 | #include <fat.h> | 18 | #include <fat.h> |
19 | #include <mmc.h> | 19 | #include <mmc.h> |
20 | 20 | ||
21 | char *env_name_spec = "FAT"; | 21 | char *env_name_spec = "FAT"; |
22 | 22 | ||
23 | env_t *env_ptr; | 23 | env_t *env_ptr; |
24 | 24 | ||
25 | DECLARE_GLOBAL_DATA_PTR; | 25 | DECLARE_GLOBAL_DATA_PTR; |
26 | 26 | ||
27 | int env_init(void) | 27 | int env_init(void) |
28 | { | 28 | { |
29 | /* use default */ | 29 | /* use default */ |
30 | gd->env_addr = (ulong)&default_environment[0]; | 30 | gd->env_addr = (ulong)&default_environment[0]; |
31 | gd->env_valid = 1; | 31 | gd->env_valid = 1; |
32 | 32 | ||
33 | return 0; | 33 | return 0; |
34 | } | 34 | } |
35 | 35 | ||
36 | #ifdef CONFIG_CMD_SAVEENV | 36 | #ifdef CONFIG_CMD_SAVEENV |
37 | int saveenv(void) | 37 | int saveenv(void) |
38 | { | 38 | { |
39 | env_t env_new; | 39 | env_t env_new; |
40 | block_dev_desc_t *dev_desc = NULL; | 40 | block_dev_desc_t *dev_desc = NULL; |
41 | disk_partition_t info; | 41 | disk_partition_t info; |
42 | int dev, part; | 42 | int dev, part; |
43 | int err; | 43 | int err; |
44 | loff_t size; | ||
44 | 45 | ||
45 | err = env_export(&env_new); | 46 | err = env_export(&env_new); |
46 | if (err) | 47 | if (err) |
47 | return err; | 48 | return err; |
48 | 49 | ||
49 | part = get_device_and_partition(FAT_ENV_INTERFACE, | 50 | part = get_device_and_partition(FAT_ENV_INTERFACE, |
50 | FAT_ENV_DEVICE_AND_PART, | 51 | FAT_ENV_DEVICE_AND_PART, |
51 | &dev_desc, &info, 1); | 52 | &dev_desc, &info, 1); |
52 | if (part < 0) | 53 | if (part < 0) |
53 | return 1; | 54 | return 1; |
54 | 55 | ||
55 | dev = dev_desc->dev; | 56 | dev = dev_desc->dev; |
56 | if (fat_set_blk_dev(dev_desc, &info) != 0) { | 57 | if (fat_set_blk_dev(dev_desc, &info) != 0) { |
57 | printf("\n** Unable to use %s %d:%d for saveenv **\n", | 58 | printf("\n** Unable to use %s %d:%d for saveenv **\n", |
58 | FAT_ENV_INTERFACE, dev, part); | 59 | FAT_ENV_INTERFACE, dev, part); |
59 | return 1; | 60 | return 1; |
60 | } | 61 | } |
61 | 62 | ||
62 | err = file_fat_write(FAT_ENV_FILE, (void *)&env_new, sizeof(env_t)); | 63 | err = file_fat_write(FAT_ENV_FILE, (void *)&env_new, 0, sizeof(env_t), |
64 | &size); | ||
63 | if (err == -1) { | 65 | if (err == -1) { |
64 | printf("\n** Unable to write \"%s\" from %s%d:%d **\n", | 66 | printf("\n** Unable to write \"%s\" from %s%d:%d **\n", |
65 | FAT_ENV_FILE, FAT_ENV_INTERFACE, dev, part); | 67 | FAT_ENV_FILE, FAT_ENV_INTERFACE, dev, part); |
66 | return 1; | 68 | return 1; |
67 | } | 69 | } |
68 | 70 | ||
69 | puts("done\n"); | 71 | puts("done\n"); |
70 | return 0; | 72 | return 0; |
71 | } | 73 | } |
72 | #endif /* CONFIG_CMD_SAVEENV */ | 74 | #endif /* CONFIG_CMD_SAVEENV */ |
73 | 75 | ||
74 | void env_relocate_spec(void) | 76 | void env_relocate_spec(void) |
75 | { | 77 | { |
76 | ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); | 78 | ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); |
77 | block_dev_desc_t *dev_desc = NULL; | 79 | block_dev_desc_t *dev_desc = NULL; |
78 | disk_partition_t info; | 80 | disk_partition_t info; |
79 | int dev, part; | 81 | int dev, part; |
80 | int err; | 82 | int err; |
81 | 83 | ||
82 | part = get_device_and_partition(FAT_ENV_INTERFACE, | 84 | part = get_device_and_partition(FAT_ENV_INTERFACE, |
83 | FAT_ENV_DEVICE_AND_PART, | 85 | FAT_ENV_DEVICE_AND_PART, |
84 | &dev_desc, &info, 1); | 86 | &dev_desc, &info, 1); |
85 | if (part < 0) | 87 | if (part < 0) |
86 | goto err_env_relocate; | 88 | goto err_env_relocate; |
87 | 89 | ||
88 | dev = dev_desc->dev; | 90 | dev = dev_desc->dev; |
89 | if (fat_set_blk_dev(dev_desc, &info) != 0) { | 91 | if (fat_set_blk_dev(dev_desc, &info) != 0) { |
90 | printf("\n** Unable to use %s %d:%d for loading the env **\n", | 92 | printf("\n** Unable to use %s %d:%d for loading the env **\n", |
91 | FAT_ENV_INTERFACE, dev, part); | 93 | FAT_ENV_INTERFACE, dev, part); |
92 | goto err_env_relocate; | 94 | goto err_env_relocate; |
93 | } | 95 | } |
94 | 96 | ||
95 | err = file_fat_read(FAT_ENV_FILE, buf, CONFIG_ENV_SIZE); | 97 | err = file_fat_read(FAT_ENV_FILE, buf, CONFIG_ENV_SIZE); |
96 | if (err == -1) { | 98 | if (err == -1) { |
97 | printf("\n** Unable to read \"%s\" from %s%d:%d **\n", | 99 | printf("\n** Unable to read \"%s\" from %s%d:%d **\n", |
98 | FAT_ENV_FILE, FAT_ENV_INTERFACE, dev, part); | 100 | FAT_ENV_FILE, FAT_ENV_INTERFACE, dev, part); |
99 | goto err_env_relocate; | 101 | goto err_env_relocate; |
100 | } | 102 | } |
101 | 103 | ||
102 | env_import(buf, 1); | 104 | env_import(buf, 1); |
103 | return; | 105 | return; |
104 | 106 | ||
105 | err_env_relocate: | 107 | err_env_relocate: |
106 | set_default_env(NULL); | 108 | set_default_env(NULL); |
107 | } | 109 | } |
108 | 110 |
fs/fat/fat.c
1 | /* | 1 | /* |
2 | * fat.c | 2 | * fat.c |
3 | * | 3 | * |
4 | * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg | 4 | * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg |
5 | * | 5 | * |
6 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 | 6 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 |
7 | * 2003-03-10 - kharris@nexus-tech.net - ported to uboot | 7 | * 2003-03-10 - kharris@nexus-tech.net - ported to uboot |
8 | * | 8 | * |
9 | * SPDX-License-Identifier: GPL-2.0+ | 9 | * SPDX-License-Identifier: GPL-2.0+ |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <common.h> | 12 | #include <common.h> |
13 | #include <config.h> | 13 | #include <config.h> |
14 | #include <exports.h> | 14 | #include <exports.h> |
15 | #include <fat.h> | 15 | #include <fat.h> |
16 | #include <asm/byteorder.h> | 16 | #include <asm/byteorder.h> |
17 | #include <part.h> | 17 | #include <part.h> |
18 | #include <malloc.h> | 18 | #include <malloc.h> |
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
21 | 21 | ||
22 | #ifdef CONFIG_SUPPORT_VFAT | 22 | #ifdef CONFIG_SUPPORT_VFAT |
23 | static const int vfat_enabled = 1; | 23 | static const int vfat_enabled = 1; |
24 | #else | 24 | #else |
25 | static const int vfat_enabled = 0; | 25 | static const int vfat_enabled = 0; |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Convert a string to lowercase. | 29 | * Convert a string to lowercase. |
30 | */ | 30 | */ |
31 | static void downcase(char *str) | 31 | static void downcase(char *str) |
32 | { | 32 | { |
33 | while (*str != '\0') { | 33 | while (*str != '\0') { |
34 | *str = tolower(*str); | 34 | *str = tolower(*str); |
35 | str++; | 35 | str++; |
36 | } | 36 | } |
37 | } | 37 | } |
38 | 38 | ||
39 | static block_dev_desc_t *cur_dev; | 39 | static block_dev_desc_t *cur_dev; |
40 | static disk_partition_t cur_part_info; | 40 | static disk_partition_t cur_part_info; |
41 | 41 | ||
42 | #define DOS_BOOT_MAGIC_OFFSET 0x1fe | 42 | #define DOS_BOOT_MAGIC_OFFSET 0x1fe |
43 | #define DOS_FS_TYPE_OFFSET 0x36 | 43 | #define DOS_FS_TYPE_OFFSET 0x36 |
44 | #define DOS_FS32_TYPE_OFFSET 0x52 | 44 | #define DOS_FS32_TYPE_OFFSET 0x52 |
45 | 45 | ||
46 | static int disk_read(__u32 block, __u32 nr_blocks, void *buf) | 46 | static int disk_read(__u32 block, __u32 nr_blocks, void *buf) |
47 | { | 47 | { |
48 | if (!cur_dev || !cur_dev->block_read) | 48 | if (!cur_dev || !cur_dev->block_read) |
49 | return -1; | 49 | return -1; |
50 | 50 | ||
51 | return cur_dev->block_read(cur_dev->dev, | 51 | return cur_dev->block_read(cur_dev->dev, |
52 | cur_part_info.start + block, nr_blocks, buf); | 52 | cur_part_info.start + block, nr_blocks, buf); |
53 | } | 53 | } |
54 | 54 | ||
55 | int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info) | 55 | int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info) |
56 | { | 56 | { |
57 | ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); | 57 | ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); |
58 | 58 | ||
59 | cur_dev = dev_desc; | 59 | cur_dev = dev_desc; |
60 | cur_part_info = *info; | 60 | cur_part_info = *info; |
61 | 61 | ||
62 | /* Make sure it has a valid FAT header */ | 62 | /* Make sure it has a valid FAT header */ |
63 | if (disk_read(0, 1, buffer) != 1) { | 63 | if (disk_read(0, 1, buffer) != 1) { |
64 | cur_dev = NULL; | 64 | cur_dev = NULL; |
65 | return -1; | 65 | return -1; |
66 | } | 66 | } |
67 | 67 | ||
68 | /* Check if it's actually a DOS volume */ | 68 | /* Check if it's actually a DOS volume */ |
69 | if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { | 69 | if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { |
70 | cur_dev = NULL; | 70 | cur_dev = NULL; |
71 | return -1; | 71 | return -1; |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Check for FAT12/FAT16/FAT32 filesystem */ | 74 | /* Check for FAT12/FAT16/FAT32 filesystem */ |
75 | if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) | 75 | if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) |
76 | return 0; | 76 | return 0; |
77 | if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) | 77 | if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) |
78 | return 0; | 78 | return 0; |
79 | 79 | ||
80 | cur_dev = NULL; | 80 | cur_dev = NULL; |
81 | return -1; | 81 | return -1; |
82 | } | 82 | } |
83 | 83 | ||
84 | int fat_register_device(block_dev_desc_t *dev_desc, int part_no) | 84 | int fat_register_device(block_dev_desc_t *dev_desc, int part_no) |
85 | { | 85 | { |
86 | disk_partition_t info; | 86 | disk_partition_t info; |
87 | 87 | ||
88 | /* First close any currently found FAT filesystem */ | 88 | /* First close any currently found FAT filesystem */ |
89 | cur_dev = NULL; | 89 | cur_dev = NULL; |
90 | 90 | ||
91 | /* Read the partition table, if present */ | 91 | /* Read the partition table, if present */ |
92 | if (get_partition_info(dev_desc, part_no, &info)) { | 92 | if (get_partition_info(dev_desc, part_no, &info)) { |
93 | if (part_no != 0) { | 93 | if (part_no != 0) { |
94 | printf("** Partition %d not valid on device %d **\n", | 94 | printf("** Partition %d not valid on device %d **\n", |
95 | part_no, dev_desc->dev); | 95 | part_no, dev_desc->dev); |
96 | return -1; | 96 | return -1; |
97 | } | 97 | } |
98 | 98 | ||
99 | info.start = 0; | 99 | info.start = 0; |
100 | info.size = dev_desc->lba; | 100 | info.size = dev_desc->lba; |
101 | info.blksz = dev_desc->blksz; | 101 | info.blksz = dev_desc->blksz; |
102 | info.name[0] = 0; | 102 | info.name[0] = 0; |
103 | info.type[0] = 0; | 103 | info.type[0] = 0; |
104 | info.bootable = 0; | 104 | info.bootable = 0; |
105 | #ifdef CONFIG_PARTITION_UUIDS | 105 | #ifdef CONFIG_PARTITION_UUIDS |
106 | info.uuid[0] = 0; | 106 | info.uuid[0] = 0; |
107 | #endif | 107 | #endif |
108 | } | 108 | } |
109 | 109 | ||
110 | return fat_set_blk_dev(dev_desc, &info); | 110 | return fat_set_blk_dev(dev_desc, &info); |
111 | } | 111 | } |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * Get the first occurence of a directory delimiter ('/' or '\') in a string. | 114 | * Get the first occurence of a directory delimiter ('/' or '\') in a string. |
115 | * Return index into string if found, -1 otherwise. | 115 | * Return index into string if found, -1 otherwise. |
116 | */ | 116 | */ |
117 | static int dirdelim(char *str) | 117 | static int dirdelim(char *str) |
118 | { | 118 | { |
119 | char *start = str; | 119 | char *start = str; |
120 | 120 | ||
121 | while (*str != '\0') { | 121 | while (*str != '\0') { |
122 | if (ISDIRDELIM(*str)) | 122 | if (ISDIRDELIM(*str)) |
123 | return str - start; | 123 | return str - start; |
124 | str++; | 124 | str++; |
125 | } | 125 | } |
126 | return -1; | 126 | return -1; |
127 | } | 127 | } |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * Extract zero terminated short name from a directory entry. | 130 | * Extract zero terminated short name from a directory entry. |
131 | */ | 131 | */ |
132 | static void get_name(dir_entry *dirent, char *s_name) | 132 | static void get_name(dir_entry *dirent, char *s_name) |
133 | { | 133 | { |
134 | char *ptr; | 134 | char *ptr; |
135 | 135 | ||
136 | memcpy(s_name, dirent->name, 8); | 136 | memcpy(s_name, dirent->name, 8); |
137 | s_name[8] = '\0'; | 137 | s_name[8] = '\0'; |
138 | ptr = s_name; | 138 | ptr = s_name; |
139 | while (*ptr && *ptr != ' ') | 139 | while (*ptr && *ptr != ' ') |
140 | ptr++; | 140 | ptr++; |
141 | if (dirent->ext[0] && dirent->ext[0] != ' ') { | 141 | if (dirent->ext[0] && dirent->ext[0] != ' ') { |
142 | *ptr = '.'; | 142 | *ptr = '.'; |
143 | ptr++; | 143 | ptr++; |
144 | memcpy(ptr, dirent->ext, 3); | 144 | memcpy(ptr, dirent->ext, 3); |
145 | ptr[3] = '\0'; | 145 | ptr[3] = '\0'; |
146 | while (*ptr && *ptr != ' ') | 146 | while (*ptr && *ptr != ' ') |
147 | ptr++; | 147 | ptr++; |
148 | } | 148 | } |
149 | *ptr = '\0'; | 149 | *ptr = '\0'; |
150 | if (*s_name == DELETED_FLAG) | 150 | if (*s_name == DELETED_FLAG) |
151 | *s_name = '\0'; | 151 | *s_name = '\0'; |
152 | else if (*s_name == aRING) | 152 | else if (*s_name == aRING) |
153 | *s_name = DELETED_FLAG; | 153 | *s_name = DELETED_FLAG; |
154 | downcase(s_name); | 154 | downcase(s_name); |
155 | } | 155 | } |
156 | 156 | ||
157 | /* | 157 | /* |
158 | * Get the entry at index 'entry' in a FAT (12/16/32) table. | 158 | * Get the entry at index 'entry' in a FAT (12/16/32) table. |
159 | * On failure 0x00 is returned. | 159 | * On failure 0x00 is returned. |
160 | */ | 160 | */ |
161 | static __u32 get_fatent(fsdata *mydata, __u32 entry) | 161 | static __u32 get_fatent(fsdata *mydata, __u32 entry) |
162 | { | 162 | { |
163 | __u32 bufnum; | 163 | __u32 bufnum; |
164 | __u32 off16, offset; | 164 | __u32 off16, offset; |
165 | __u32 ret = 0x00; | 165 | __u32 ret = 0x00; |
166 | __u16 val1, val2; | 166 | __u16 val1, val2; |
167 | 167 | ||
168 | switch (mydata->fatsize) { | 168 | switch (mydata->fatsize) { |
169 | case 32: | 169 | case 32: |
170 | bufnum = entry / FAT32BUFSIZE; | 170 | bufnum = entry / FAT32BUFSIZE; |
171 | offset = entry - bufnum * FAT32BUFSIZE; | 171 | offset = entry - bufnum * FAT32BUFSIZE; |
172 | break; | 172 | break; |
173 | case 16: | 173 | case 16: |
174 | bufnum = entry / FAT16BUFSIZE; | 174 | bufnum = entry / FAT16BUFSIZE; |
175 | offset = entry - bufnum * FAT16BUFSIZE; | 175 | offset = entry - bufnum * FAT16BUFSIZE; |
176 | break; | 176 | break; |
177 | case 12: | 177 | case 12: |
178 | bufnum = entry / FAT12BUFSIZE; | 178 | bufnum = entry / FAT12BUFSIZE; |
179 | offset = entry - bufnum * FAT12BUFSIZE; | 179 | offset = entry - bufnum * FAT12BUFSIZE; |
180 | break; | 180 | break; |
181 | 181 | ||
182 | default: | 182 | default: |
183 | /* Unsupported FAT size */ | 183 | /* Unsupported FAT size */ |
184 | return ret; | 184 | return ret; |
185 | } | 185 | } |
186 | 186 | ||
187 | debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", | 187 | debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", |
188 | mydata->fatsize, entry, entry, offset, offset); | 188 | mydata->fatsize, entry, entry, offset, offset); |
189 | 189 | ||
190 | /* Read a new block of FAT entries into the cache. */ | 190 | /* Read a new block of FAT entries into the cache. */ |
191 | if (bufnum != mydata->fatbufnum) { | 191 | if (bufnum != mydata->fatbufnum) { |
192 | __u32 getsize = FATBUFBLOCKS; | 192 | __u32 getsize = FATBUFBLOCKS; |
193 | __u8 *bufptr = mydata->fatbuf; | 193 | __u8 *bufptr = mydata->fatbuf; |
194 | __u32 fatlength = mydata->fatlength; | 194 | __u32 fatlength = mydata->fatlength; |
195 | __u32 startblock = bufnum * FATBUFBLOCKS; | 195 | __u32 startblock = bufnum * FATBUFBLOCKS; |
196 | 196 | ||
197 | if (startblock + getsize > fatlength) | 197 | if (startblock + getsize > fatlength) |
198 | getsize = fatlength - startblock; | 198 | getsize = fatlength - startblock; |
199 | 199 | ||
200 | startblock += mydata->fat_sect; /* Offset from start of disk */ | 200 | startblock += mydata->fat_sect; /* Offset from start of disk */ |
201 | 201 | ||
202 | if (disk_read(startblock, getsize, bufptr) < 0) { | 202 | if (disk_read(startblock, getsize, bufptr) < 0) { |
203 | debug("Error reading FAT blocks\n"); | 203 | debug("Error reading FAT blocks\n"); |
204 | return ret; | 204 | return ret; |
205 | } | 205 | } |
206 | mydata->fatbufnum = bufnum; | 206 | mydata->fatbufnum = bufnum; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* Get the actual entry from the table */ | 209 | /* Get the actual entry from the table */ |
210 | switch (mydata->fatsize) { | 210 | switch (mydata->fatsize) { |
211 | case 32: | 211 | case 32: |
212 | ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); | 212 | ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); |
213 | break; | 213 | break; |
214 | case 16: | 214 | case 16: |
215 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); | 215 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); |
216 | break; | 216 | break; |
217 | case 12: | 217 | case 12: |
218 | off16 = (offset * 3) / 4; | 218 | off16 = (offset * 3) / 4; |
219 | 219 | ||
220 | switch (offset & 0x3) { | 220 | switch (offset & 0x3) { |
221 | case 0: | 221 | case 0: |
222 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); | 222 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); |
223 | ret &= 0xfff; | 223 | ret &= 0xfff; |
224 | break; | 224 | break; |
225 | case 1: | 225 | case 1: |
226 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 226 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
227 | val1 &= 0xf000; | 227 | val1 &= 0xf000; |
228 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); | 228 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); |
229 | val2 &= 0x00ff; | 229 | val2 &= 0x00ff; |
230 | ret = (val2 << 4) | (val1 >> 12); | 230 | ret = (val2 << 4) | (val1 >> 12); |
231 | break; | 231 | break; |
232 | case 2: | 232 | case 2: |
233 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 233 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
234 | val1 &= 0xff00; | 234 | val1 &= 0xff00; |
235 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); | 235 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); |
236 | val2 &= 0x000f; | 236 | val2 &= 0x000f; |
237 | ret = (val2 << 8) | (val1 >> 8); | 237 | ret = (val2 << 8) | (val1 >> 8); |
238 | break; | 238 | break; |
239 | case 3: | 239 | case 3: |
240 | ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 240 | ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
241 | ret = (ret & 0xfff0) >> 4; | 241 | ret = (ret & 0xfff0) >> 4; |
242 | break; | 242 | break; |
243 | default: | 243 | default: |
244 | break; | 244 | break; |
245 | } | 245 | } |
246 | break; | 246 | break; |
247 | } | 247 | } |
248 | debug("FAT%d: ret: %08x, offset: %04x\n", | 248 | debug("FAT%d: ret: %08x, offset: %04x\n", |
249 | mydata->fatsize, ret, offset); | 249 | mydata->fatsize, ret, offset); |
250 | 250 | ||
251 | return ret; | 251 | return ret; |
252 | } | 252 | } |
253 | 253 | ||
254 | /* | 254 | /* |
255 | * Read at most 'size' bytes from the specified cluster into 'buffer'. | 255 | * Read at most 'size' bytes from the specified cluster into 'buffer'. |
256 | * Return 0 on success, -1 otherwise. | 256 | * Return 0 on success, -1 otherwise. |
257 | */ | 257 | */ |
258 | static int | 258 | static int |
259 | get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) | 259 | get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) |
260 | { | 260 | { |
261 | __u32 idx = 0; | 261 | __u32 idx = 0; |
262 | __u32 startsect; | 262 | __u32 startsect; |
263 | int ret; | 263 | int ret; |
264 | 264 | ||
265 | if (clustnum > 0) { | 265 | if (clustnum > 0) { |
266 | startsect = mydata->data_begin + | 266 | startsect = mydata->data_begin + |
267 | clustnum * mydata->clust_size; | 267 | clustnum * mydata->clust_size; |
268 | } else { | 268 | } else { |
269 | startsect = mydata->rootdir_sect; | 269 | startsect = mydata->rootdir_sect; |
270 | } | 270 | } |
271 | 271 | ||
272 | debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); | 272 | debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); |
273 | 273 | ||
274 | if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { | 274 | if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { |
275 | ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); | 275 | ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); |
276 | 276 | ||
277 | printf("FAT: Misaligned buffer address (%p)\n", buffer); | 277 | printf("FAT: Misaligned buffer address (%p)\n", buffer); |
278 | 278 | ||
279 | while (size >= mydata->sect_size) { | 279 | while (size >= mydata->sect_size) { |
280 | ret = disk_read(startsect++, 1, tmpbuf); | 280 | ret = disk_read(startsect++, 1, tmpbuf); |
281 | if (ret != 1) { | 281 | if (ret != 1) { |
282 | debug("Error reading data (got %d)\n", ret); | 282 | debug("Error reading data (got %d)\n", ret); |
283 | return -1; | 283 | return -1; |
284 | } | 284 | } |
285 | 285 | ||
286 | memcpy(buffer, tmpbuf, mydata->sect_size); | 286 | memcpy(buffer, tmpbuf, mydata->sect_size); |
287 | buffer += mydata->sect_size; | 287 | buffer += mydata->sect_size; |
288 | size -= mydata->sect_size; | 288 | size -= mydata->sect_size; |
289 | } | 289 | } |
290 | } else { | 290 | } else { |
291 | idx = size / mydata->sect_size; | 291 | idx = size / mydata->sect_size; |
292 | ret = disk_read(startsect, idx, buffer); | 292 | ret = disk_read(startsect, idx, buffer); |
293 | if (ret != idx) { | 293 | if (ret != idx) { |
294 | debug("Error reading data (got %d)\n", ret); | 294 | debug("Error reading data (got %d)\n", ret); |
295 | return -1; | 295 | return -1; |
296 | } | 296 | } |
297 | startsect += idx; | 297 | startsect += idx; |
298 | idx *= mydata->sect_size; | 298 | idx *= mydata->sect_size; |
299 | buffer += idx; | 299 | buffer += idx; |
300 | size -= idx; | 300 | size -= idx; |
301 | } | 301 | } |
302 | if (size) { | 302 | if (size) { |
303 | ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); | 303 | ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); |
304 | 304 | ||
305 | ret = disk_read(startsect, 1, tmpbuf); | 305 | ret = disk_read(startsect, 1, tmpbuf); |
306 | if (ret != 1) { | 306 | if (ret != 1) { |
307 | debug("Error reading data (got %d)\n", ret); | 307 | debug("Error reading data (got %d)\n", ret); |
308 | return -1; | 308 | return -1; |
309 | } | 309 | } |
310 | 310 | ||
311 | memcpy(buffer, tmpbuf, size); | 311 | memcpy(buffer, tmpbuf, size); |
312 | } | 312 | } |
313 | 313 | ||
314 | return 0; | 314 | return 0; |
315 | } | 315 | } |
316 | 316 | ||
317 | /* | 317 | /* |
318 | * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr' | 318 | * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr' |
319 | * into 'buffer'. | 319 | * into 'buffer'. |
320 | * Return the number of bytes read or -1 on fatal errors. | 320 | * Update the number of bytes read in *gotsize or return -1 on fatal errors. |
321 | */ | 321 | */ |
322 | __u8 get_contents_vfatname_block[MAX_CLUSTSIZE] | 322 | __u8 get_contents_vfatname_block[MAX_CLUSTSIZE] |
323 | __aligned(ARCH_DMA_MINALIGN); | 323 | __aligned(ARCH_DMA_MINALIGN); |
324 | 324 | ||
325 | static long | 325 | static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, |
326 | get_contents(fsdata *mydata, dir_entry *dentptr, unsigned long pos, | 326 | __u8 *buffer, loff_t maxsize, loff_t *gotsize) |
327 | __u8 *buffer, unsigned long maxsize) | ||
328 | { | 327 | { |
329 | unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; | 328 | loff_t filesize = FAT2CPU32(dentptr->size); |
330 | unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | 329 | unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; |
331 | __u32 curclust = START(dentptr); | 330 | __u32 curclust = START(dentptr); |
332 | __u32 endclust, newclust; | 331 | __u32 endclust, newclust; |
333 | unsigned long actsize; | 332 | loff_t actsize; |
334 | 333 | ||
335 | debug("Filesize: %ld bytes\n", filesize); | 334 | *gotsize = 0; |
335 | debug("Filesize: %llu bytes\n", filesize); | ||
336 | 336 | ||
337 | if (pos >= filesize) { | 337 | if (pos >= filesize) { |
338 | debug("Read position past EOF: %lu\n", pos); | 338 | debug("Read position past EOF: %llu\n", pos); |
339 | return gotsize; | 339 | return 0; |
340 | } | 340 | } |
341 | 341 | ||
342 | if (maxsize > 0 && filesize > pos + maxsize) | 342 | if (maxsize > 0 && filesize > pos + maxsize) |
343 | filesize = pos + maxsize; | 343 | filesize = pos + maxsize; |
344 | 344 | ||
345 | debug("%ld bytes\n", filesize); | 345 | debug("%llu bytes\n", filesize); |
346 | 346 | ||
347 | actsize = bytesperclust; | 347 | actsize = bytesperclust; |
348 | 348 | ||
349 | /* go to cluster at pos */ | 349 | /* go to cluster at pos */ |
350 | while (actsize <= pos) { | 350 | while (actsize <= pos) { |
351 | curclust = get_fatent(mydata, curclust); | 351 | curclust = get_fatent(mydata, curclust); |
352 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 352 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
353 | debug("curclust: 0x%x\n", curclust); | 353 | debug("curclust: 0x%x\n", curclust); |
354 | debug("Invalid FAT entry\n"); | 354 | debug("Invalid FAT entry\n"); |
355 | return gotsize; | 355 | return 0; |
356 | } | 356 | } |
357 | actsize += bytesperclust; | 357 | actsize += bytesperclust; |
358 | } | 358 | } |
359 | 359 | ||
360 | /* actsize > pos */ | 360 | /* actsize > pos */ |
361 | actsize -= bytesperclust; | 361 | actsize -= bytesperclust; |
362 | filesize -= actsize; | 362 | filesize -= actsize; |
363 | pos -= actsize; | 363 | pos -= actsize; |
364 | 364 | ||
365 | /* align to beginning of next cluster if any */ | 365 | /* align to beginning of next cluster if any */ |
366 | if (pos) { | 366 | if (pos) { |
367 | actsize = min(filesize, (unsigned long)bytesperclust); | 367 | actsize = min(filesize, (loff_t)bytesperclust); |
368 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, | 368 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, |
369 | (int)actsize) != 0) { | 369 | (int)actsize) != 0) { |
370 | printf("Error reading cluster\n"); | 370 | printf("Error reading cluster\n"); |
371 | return -1; | 371 | return -1; |
372 | } | 372 | } |
373 | filesize -= actsize; | 373 | filesize -= actsize; |
374 | actsize -= pos; | 374 | actsize -= pos; |
375 | memcpy(buffer, get_contents_vfatname_block + pos, actsize); | 375 | memcpy(buffer, get_contents_vfatname_block + pos, actsize); |
376 | gotsize += actsize; | 376 | *gotsize += actsize; |
377 | if (!filesize) | 377 | if (!filesize) |
378 | return gotsize; | 378 | return 0; |
379 | buffer += actsize; | 379 | buffer += actsize; |
380 | 380 | ||
381 | curclust = get_fatent(mydata, curclust); | 381 | curclust = get_fatent(mydata, curclust); |
382 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 382 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
383 | debug("curclust: 0x%x\n", curclust); | 383 | debug("curclust: 0x%x\n", curclust); |
384 | debug("Invalid FAT entry\n"); | 384 | debug("Invalid FAT entry\n"); |
385 | return gotsize; | 385 | return 0; |
386 | } | 386 | } |
387 | } | 387 | } |
388 | 388 | ||
389 | actsize = bytesperclust; | 389 | actsize = bytesperclust; |
390 | endclust = curclust; | 390 | endclust = curclust; |
391 | 391 | ||
392 | do { | 392 | do { |
393 | /* search for consecutive clusters */ | 393 | /* search for consecutive clusters */ |
394 | while (actsize < filesize) { | 394 | while (actsize < filesize) { |
395 | newclust = get_fatent(mydata, endclust); | 395 | newclust = get_fatent(mydata, endclust); |
396 | if ((newclust - 1) != endclust) | 396 | if ((newclust - 1) != endclust) |
397 | goto getit; | 397 | goto getit; |
398 | if (CHECK_CLUST(newclust, mydata->fatsize)) { | 398 | if (CHECK_CLUST(newclust, mydata->fatsize)) { |
399 | debug("curclust: 0x%x\n", newclust); | 399 | debug("curclust: 0x%x\n", newclust); |
400 | debug("Invalid FAT entry\n"); | 400 | debug("Invalid FAT entry\n"); |
401 | return gotsize; | 401 | return 0; |
402 | } | 402 | } |
403 | endclust = newclust; | 403 | endclust = newclust; |
404 | actsize += bytesperclust; | 404 | actsize += bytesperclust; |
405 | } | 405 | } |
406 | 406 | ||
407 | /* get remaining bytes */ | 407 | /* get remaining bytes */ |
408 | actsize = filesize; | 408 | actsize = filesize; |
409 | if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { | 409 | if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
410 | printf("Error reading cluster\n"); | 410 | printf("Error reading cluster\n"); |
411 | return -1; | 411 | return -1; |
412 | } | 412 | } |
413 | gotsize += actsize; | 413 | *gotsize += actsize; |
414 | return gotsize; | 414 | return 0; |
415 | getit: | 415 | getit: |
416 | if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { | 416 | if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
417 | printf("Error reading cluster\n"); | 417 | printf("Error reading cluster\n"); |
418 | return -1; | 418 | return -1; |
419 | } | 419 | } |
420 | gotsize += (int)actsize; | 420 | *gotsize += (int)actsize; |
421 | filesize -= actsize; | 421 | filesize -= actsize; |
422 | buffer += actsize; | 422 | buffer += actsize; |
423 | 423 | ||
424 | curclust = get_fatent(mydata, endclust); | 424 | curclust = get_fatent(mydata, endclust); |
425 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 425 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
426 | debug("curclust: 0x%x\n", curclust); | 426 | debug("curclust: 0x%x\n", curclust); |
427 | printf("Invalid FAT entry\n"); | 427 | printf("Invalid FAT entry\n"); |
428 | return gotsize; | 428 | return 0; |
429 | } | 429 | } |
430 | actsize = bytesperclust; | 430 | actsize = bytesperclust; |
431 | endclust = curclust; | 431 | endclust = curclust; |
432 | } while (1); | 432 | } while (1); |
433 | } | 433 | } |
434 | 434 | ||
435 | /* | 435 | /* |
436 | * Extract the file name information from 'slotptr' into 'l_name', | 436 | * Extract the file name information from 'slotptr' into 'l_name', |
437 | * starting at l_name[*idx]. | 437 | * starting at l_name[*idx]. |
438 | * Return 1 if terminator (zero byte) is found, 0 otherwise. | 438 | * Return 1 if terminator (zero byte) is found, 0 otherwise. |
439 | */ | 439 | */ |
440 | static int slot2str(dir_slot *slotptr, char *l_name, int *idx) | 440 | static int slot2str(dir_slot *slotptr, char *l_name, int *idx) |
441 | { | 441 | { |
442 | int j; | 442 | int j; |
443 | 443 | ||
444 | for (j = 0; j <= 8; j += 2) { | 444 | for (j = 0; j <= 8; j += 2) { |
445 | l_name[*idx] = slotptr->name0_4[j]; | 445 | l_name[*idx] = slotptr->name0_4[j]; |
446 | if (l_name[*idx] == 0x00) | 446 | if (l_name[*idx] == 0x00) |
447 | return 1; | 447 | return 1; |
448 | (*idx)++; | 448 | (*idx)++; |
449 | } | 449 | } |
450 | for (j = 0; j <= 10; j += 2) { | 450 | for (j = 0; j <= 10; j += 2) { |
451 | l_name[*idx] = slotptr->name5_10[j]; | 451 | l_name[*idx] = slotptr->name5_10[j]; |
452 | if (l_name[*idx] == 0x00) | 452 | if (l_name[*idx] == 0x00) |
453 | return 1; | 453 | return 1; |
454 | (*idx)++; | 454 | (*idx)++; |
455 | } | 455 | } |
456 | for (j = 0; j <= 2; j += 2) { | 456 | for (j = 0; j <= 2; j += 2) { |
457 | l_name[*idx] = slotptr->name11_12[j]; | 457 | l_name[*idx] = slotptr->name11_12[j]; |
458 | if (l_name[*idx] == 0x00) | 458 | if (l_name[*idx] == 0x00) |
459 | return 1; | 459 | return 1; |
460 | (*idx)++; | 460 | (*idx)++; |
461 | } | 461 | } |
462 | 462 | ||
463 | return 0; | 463 | return 0; |
464 | } | 464 | } |
465 | 465 | ||
466 | /* | 466 | /* |
467 | * Extract the full long filename starting at 'retdent' (which is really | 467 | * Extract the full long filename starting at 'retdent' (which is really |
468 | * a slot) into 'l_name'. If successful also copy the real directory entry | 468 | * a slot) into 'l_name'. If successful also copy the real directory entry |
469 | * into 'retdent' | 469 | * into 'retdent' |
470 | * Return 0 on success, -1 otherwise. | 470 | * Return 0 on success, -1 otherwise. |
471 | */ | 471 | */ |
472 | static int | 472 | static int |
473 | get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, | 473 | get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, |
474 | dir_entry *retdent, char *l_name) | 474 | dir_entry *retdent, char *l_name) |
475 | { | 475 | { |
476 | dir_entry *realdent; | 476 | dir_entry *realdent; |
477 | dir_slot *slotptr = (dir_slot *)retdent; | 477 | dir_slot *slotptr = (dir_slot *)retdent; |
478 | __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? | 478 | __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? |
479 | PREFETCH_BLOCKS : | 479 | PREFETCH_BLOCKS : |
480 | mydata->clust_size); | 480 | mydata->clust_size); |
481 | __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; | 481 | __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; |
482 | int idx = 0; | 482 | int idx = 0; |
483 | 483 | ||
484 | if (counter > VFAT_MAXSEQ) { | 484 | if (counter > VFAT_MAXSEQ) { |
485 | debug("Error: VFAT name is too long\n"); | 485 | debug("Error: VFAT name is too long\n"); |
486 | return -1; | 486 | return -1; |
487 | } | 487 | } |
488 | 488 | ||
489 | while ((__u8 *)slotptr < buflimit) { | 489 | while ((__u8 *)slotptr < buflimit) { |
490 | if (counter == 0) | 490 | if (counter == 0) |
491 | break; | 491 | break; |
492 | if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) | 492 | if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) |
493 | return -1; | 493 | return -1; |
494 | slotptr++; | 494 | slotptr++; |
495 | counter--; | 495 | counter--; |
496 | } | 496 | } |
497 | 497 | ||
498 | if ((__u8 *)slotptr >= buflimit) { | 498 | if ((__u8 *)slotptr >= buflimit) { |
499 | dir_slot *slotptr2; | 499 | dir_slot *slotptr2; |
500 | 500 | ||
501 | if (curclust == 0) | 501 | if (curclust == 0) |
502 | return -1; | 502 | return -1; |
503 | curclust = get_fatent(mydata, curclust); | 503 | curclust = get_fatent(mydata, curclust); |
504 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 504 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
505 | debug("curclust: 0x%x\n", curclust); | 505 | debug("curclust: 0x%x\n", curclust); |
506 | printf("Invalid FAT entry\n"); | 506 | printf("Invalid FAT entry\n"); |
507 | return -1; | 507 | return -1; |
508 | } | 508 | } |
509 | 509 | ||
510 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, | 510 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, |
511 | mydata->clust_size * mydata->sect_size) != 0) { | 511 | mydata->clust_size * mydata->sect_size) != 0) { |
512 | debug("Error: reading directory block\n"); | 512 | debug("Error: reading directory block\n"); |
513 | return -1; | 513 | return -1; |
514 | } | 514 | } |
515 | 515 | ||
516 | slotptr2 = (dir_slot *)get_contents_vfatname_block; | 516 | slotptr2 = (dir_slot *)get_contents_vfatname_block; |
517 | while (counter > 0) { | 517 | while (counter > 0) { |
518 | if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) | 518 | if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) |
519 | & 0xff) != counter) | 519 | & 0xff) != counter) |
520 | return -1; | 520 | return -1; |
521 | slotptr2++; | 521 | slotptr2++; |
522 | counter--; | 522 | counter--; |
523 | } | 523 | } |
524 | 524 | ||
525 | /* Save the real directory entry */ | 525 | /* Save the real directory entry */ |
526 | realdent = (dir_entry *)slotptr2; | 526 | realdent = (dir_entry *)slotptr2; |
527 | while ((__u8 *)slotptr2 > get_contents_vfatname_block) { | 527 | while ((__u8 *)slotptr2 > get_contents_vfatname_block) { |
528 | slotptr2--; | 528 | slotptr2--; |
529 | slot2str(slotptr2, l_name, &idx); | 529 | slot2str(slotptr2, l_name, &idx); |
530 | } | 530 | } |
531 | } else { | 531 | } else { |
532 | /* Save the real directory entry */ | 532 | /* Save the real directory entry */ |
533 | realdent = (dir_entry *)slotptr; | 533 | realdent = (dir_entry *)slotptr; |
534 | } | 534 | } |
535 | 535 | ||
536 | do { | 536 | do { |
537 | slotptr--; | 537 | slotptr--; |
538 | if (slot2str(slotptr, l_name, &idx)) | 538 | if (slot2str(slotptr, l_name, &idx)) |
539 | break; | 539 | break; |
540 | } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); | 540 | } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); |
541 | 541 | ||
542 | l_name[idx] = '\0'; | 542 | l_name[idx] = '\0'; |
543 | if (*l_name == DELETED_FLAG) | 543 | if (*l_name == DELETED_FLAG) |
544 | *l_name = '\0'; | 544 | *l_name = '\0'; |
545 | else if (*l_name == aRING) | 545 | else if (*l_name == aRING) |
546 | *l_name = DELETED_FLAG; | 546 | *l_name = DELETED_FLAG; |
547 | downcase(l_name); | 547 | downcase(l_name); |
548 | 548 | ||
549 | /* Return the real directory entry */ | 549 | /* Return the real directory entry */ |
550 | memcpy(retdent, realdent, sizeof(dir_entry)); | 550 | memcpy(retdent, realdent, sizeof(dir_entry)); |
551 | 551 | ||
552 | return 0; | 552 | return 0; |
553 | } | 553 | } |
554 | 554 | ||
555 | /* Calculate short name checksum */ | 555 | /* Calculate short name checksum */ |
556 | static __u8 mkcksum(const char name[8], const char ext[3]) | 556 | static __u8 mkcksum(const char name[8], const char ext[3]) |
557 | { | 557 | { |
558 | int i; | 558 | int i; |
559 | 559 | ||
560 | __u8 ret = 0; | 560 | __u8 ret = 0; |
561 | 561 | ||
562 | for (i = 0; i < 8; i++) | 562 | for (i = 0; i < 8; i++) |
563 | ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i]; | 563 | ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i]; |
564 | for (i = 0; i < 3; i++) | 564 | for (i = 0; i < 3; i++) |
565 | ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i]; | 565 | ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i]; |
566 | 566 | ||
567 | return ret; | 567 | return ret; |
568 | } | 568 | } |
569 | 569 | ||
570 | /* | 570 | /* |
571 | * Get the directory entry associated with 'filename' from the directory | 571 | * Get the directory entry associated with 'filename' from the directory |
572 | * starting at 'startsect' | 572 | * starting at 'startsect' |
573 | */ | 573 | */ |
574 | __u8 get_dentfromdir_block[MAX_CLUSTSIZE] | 574 | __u8 get_dentfromdir_block[MAX_CLUSTSIZE] |
575 | __aligned(ARCH_DMA_MINALIGN); | 575 | __aligned(ARCH_DMA_MINALIGN); |
576 | 576 | ||
577 | static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, | 577 | static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, |
578 | char *filename, dir_entry *retdent, | 578 | char *filename, dir_entry *retdent, |
579 | int dols) | 579 | int dols) |
580 | { | 580 | { |
581 | __u16 prevcksum = 0xffff; | 581 | __u16 prevcksum = 0xffff; |
582 | __u32 curclust = START(retdent); | 582 | __u32 curclust = START(retdent); |
583 | int files = 0, dirs = 0; | 583 | int files = 0, dirs = 0; |
584 | 584 | ||
585 | debug("get_dentfromdir: %s\n", filename); | 585 | debug("get_dentfromdir: %s\n", filename); |
586 | 586 | ||
587 | while (1) { | 587 | while (1) { |
588 | dir_entry *dentptr; | 588 | dir_entry *dentptr; |
589 | 589 | ||
590 | int i; | 590 | int i; |
591 | 591 | ||
592 | if (get_cluster(mydata, curclust, get_dentfromdir_block, | 592 | if (get_cluster(mydata, curclust, get_dentfromdir_block, |
593 | mydata->clust_size * mydata->sect_size) != 0) { | 593 | mydata->clust_size * mydata->sect_size) != 0) { |
594 | debug("Error: reading directory block\n"); | 594 | debug("Error: reading directory block\n"); |
595 | return NULL; | 595 | return NULL; |
596 | } | 596 | } |
597 | 597 | ||
598 | dentptr = (dir_entry *)get_dentfromdir_block; | 598 | dentptr = (dir_entry *)get_dentfromdir_block; |
599 | 599 | ||
600 | for (i = 0; i < DIRENTSPERCLUST; i++) { | 600 | for (i = 0; i < DIRENTSPERCLUST; i++) { |
601 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; | 601 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; |
602 | 602 | ||
603 | l_name[0] = '\0'; | 603 | l_name[0] = '\0'; |
604 | if (dentptr->name[0] == DELETED_FLAG) { | 604 | if (dentptr->name[0] == DELETED_FLAG) { |
605 | dentptr++; | 605 | dentptr++; |
606 | continue; | 606 | continue; |
607 | } | 607 | } |
608 | if ((dentptr->attr & ATTR_VOLUME)) { | 608 | if ((dentptr->attr & ATTR_VOLUME)) { |
609 | if (vfat_enabled && | 609 | if (vfat_enabled && |
610 | (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && | 610 | (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && |
611 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { | 611 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { |
612 | prevcksum = ((dir_slot *)dentptr)->alias_checksum; | 612 | prevcksum = ((dir_slot *)dentptr)->alias_checksum; |
613 | get_vfatname(mydata, curclust, | 613 | get_vfatname(mydata, curclust, |
614 | get_dentfromdir_block, | 614 | get_dentfromdir_block, |
615 | dentptr, l_name); | 615 | dentptr, l_name); |
616 | if (dols) { | 616 | if (dols) { |
617 | int isdir; | 617 | int isdir; |
618 | char dirc; | 618 | char dirc; |
619 | int doit = 0; | 619 | int doit = 0; |
620 | 620 | ||
621 | isdir = (dentptr->attr & ATTR_DIR); | 621 | isdir = (dentptr->attr & ATTR_DIR); |
622 | 622 | ||
623 | if (isdir) { | 623 | if (isdir) { |
624 | dirs++; | 624 | dirs++; |
625 | dirc = '/'; | 625 | dirc = '/'; |
626 | doit = 1; | 626 | doit = 1; |
627 | } else { | 627 | } else { |
628 | dirc = ' '; | 628 | dirc = ' '; |
629 | if (l_name[0] != 0) { | 629 | if (l_name[0] != 0) { |
630 | files++; | 630 | files++; |
631 | doit = 1; | 631 | doit = 1; |
632 | } | 632 | } |
633 | } | 633 | } |
634 | if (doit) { | 634 | if (doit) { |
635 | if (dirc == ' ') { | 635 | if (dirc == ' ') { |
636 | printf(" %8ld %s%c\n", | 636 | printf(" %8u %s%c\n", |
637 | (long)FAT2CPU32(dentptr->size), | 637 | FAT2CPU32(dentptr->size), |
638 | l_name, | 638 | l_name, |
639 | dirc); | 639 | dirc); |
640 | } else { | 640 | } else { |
641 | printf(" %s%c\n", | 641 | printf(" %s%c\n", |
642 | l_name, | 642 | l_name, |
643 | dirc); | 643 | dirc); |
644 | } | 644 | } |
645 | } | 645 | } |
646 | dentptr++; | 646 | dentptr++; |
647 | continue; | 647 | continue; |
648 | } | 648 | } |
649 | debug("vfatname: |%s|\n", l_name); | 649 | debug("vfatname: |%s|\n", l_name); |
650 | } else { | 650 | } else { |
651 | /* Volume label or VFAT entry */ | 651 | /* Volume label or VFAT entry */ |
652 | dentptr++; | 652 | dentptr++; |
653 | continue; | 653 | continue; |
654 | } | 654 | } |
655 | } | 655 | } |
656 | if (dentptr->name[0] == 0) { | 656 | if (dentptr->name[0] == 0) { |
657 | if (dols) { | 657 | if (dols) { |
658 | printf("\n%d file(s), %d dir(s)\n\n", | 658 | printf("\n%d file(s), %d dir(s)\n\n", |
659 | files, dirs); | 659 | files, dirs); |
660 | } | 660 | } |
661 | debug("Dentname == NULL - %d\n", i); | 661 | debug("Dentname == NULL - %d\n", i); |
662 | return NULL; | 662 | return NULL; |
663 | } | 663 | } |
664 | if (vfat_enabled) { | 664 | if (vfat_enabled) { |
665 | __u8 csum = mkcksum(dentptr->name, dentptr->ext); | 665 | __u8 csum = mkcksum(dentptr->name, dentptr->ext); |
666 | if (dols && csum == prevcksum) { | 666 | if (dols && csum == prevcksum) { |
667 | prevcksum = 0xffff; | 667 | prevcksum = 0xffff; |
668 | dentptr++; | 668 | dentptr++; |
669 | continue; | 669 | continue; |
670 | } | 670 | } |
671 | } | 671 | } |
672 | 672 | ||
673 | get_name(dentptr, s_name); | 673 | get_name(dentptr, s_name); |
674 | if (dols) { | 674 | if (dols) { |
675 | int isdir = (dentptr->attr & ATTR_DIR); | 675 | int isdir = (dentptr->attr & ATTR_DIR); |
676 | char dirc; | 676 | char dirc; |
677 | int doit = 0; | 677 | int doit = 0; |
678 | 678 | ||
679 | if (isdir) { | 679 | if (isdir) { |
680 | dirs++; | 680 | dirs++; |
681 | dirc = '/'; | 681 | dirc = '/'; |
682 | doit = 1; | 682 | doit = 1; |
683 | } else { | 683 | } else { |
684 | dirc = ' '; | 684 | dirc = ' '; |
685 | if (s_name[0] != 0) { | 685 | if (s_name[0] != 0) { |
686 | files++; | 686 | files++; |
687 | doit = 1; | 687 | doit = 1; |
688 | } | 688 | } |
689 | } | 689 | } |
690 | 690 | ||
691 | if (doit) { | 691 | if (doit) { |
692 | if (dirc == ' ') { | 692 | if (dirc == ' ') { |
693 | printf(" %8ld %s%c\n", | 693 | printf(" %8u %s%c\n", |
694 | (long)FAT2CPU32(dentptr->size), | 694 | FAT2CPU32(dentptr->size), |
695 | s_name, dirc); | 695 | s_name, dirc); |
696 | } else { | 696 | } else { |
697 | printf(" %s%c\n", | 697 | printf(" %s%c\n", |
698 | s_name, dirc); | 698 | s_name, dirc); |
699 | } | 699 | } |
700 | } | 700 | } |
701 | 701 | ||
702 | dentptr++; | 702 | dentptr++; |
703 | continue; | 703 | continue; |
704 | } | 704 | } |
705 | 705 | ||
706 | if (strcmp(filename, s_name) | 706 | if (strcmp(filename, s_name) |
707 | && strcmp(filename, l_name)) { | 707 | && strcmp(filename, l_name)) { |
708 | debug("Mismatch: |%s|%s|\n", s_name, l_name); | 708 | debug("Mismatch: |%s|%s|\n", s_name, l_name); |
709 | dentptr++; | 709 | dentptr++; |
710 | continue; | 710 | continue; |
711 | } | 711 | } |
712 | 712 | ||
713 | memcpy(retdent, dentptr, sizeof(dir_entry)); | 713 | memcpy(retdent, dentptr, sizeof(dir_entry)); |
714 | 714 | ||
715 | debug("DentName: %s", s_name); | 715 | debug("DentName: %s", s_name); |
716 | debug(", start: 0x%x", START(dentptr)); | 716 | debug(", start: 0x%x", START(dentptr)); |
717 | debug(", size: 0x%x %s\n", | 717 | debug(", size: 0x%x %s\n", |
718 | FAT2CPU32(dentptr->size), | 718 | FAT2CPU32(dentptr->size), |
719 | (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); | 719 | (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); |
720 | 720 | ||
721 | return retdent; | 721 | return retdent; |
722 | } | 722 | } |
723 | 723 | ||
724 | curclust = get_fatent(mydata, curclust); | 724 | curclust = get_fatent(mydata, curclust); |
725 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 725 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
726 | debug("curclust: 0x%x\n", curclust); | 726 | debug("curclust: 0x%x\n", curclust); |
727 | printf("Invalid FAT entry\n"); | 727 | printf("Invalid FAT entry\n"); |
728 | return NULL; | 728 | return NULL; |
729 | } | 729 | } |
730 | } | 730 | } |
731 | 731 | ||
732 | return NULL; | 732 | return NULL; |
733 | } | 733 | } |
734 | 734 | ||
735 | /* | 735 | /* |
736 | * Read boot sector and volume info from a FAT filesystem | 736 | * Read boot sector and volume info from a FAT filesystem |
737 | */ | 737 | */ |
738 | static int | 738 | static int |
739 | read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) | 739 | read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) |
740 | { | 740 | { |
741 | __u8 *block; | 741 | __u8 *block; |
742 | volume_info *vistart; | 742 | volume_info *vistart; |
743 | int ret = 0; | 743 | int ret = 0; |
744 | 744 | ||
745 | if (cur_dev == NULL) { | 745 | if (cur_dev == NULL) { |
746 | debug("Error: no device selected\n"); | 746 | debug("Error: no device selected\n"); |
747 | return -1; | 747 | return -1; |
748 | } | 748 | } |
749 | 749 | ||
750 | block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz); | 750 | block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz); |
751 | if (block == NULL) { | 751 | if (block == NULL) { |
752 | debug("Error: allocating block\n"); | 752 | debug("Error: allocating block\n"); |
753 | return -1; | 753 | return -1; |
754 | } | 754 | } |
755 | 755 | ||
756 | if (disk_read(0, 1, block) < 0) { | 756 | if (disk_read(0, 1, block) < 0) { |
757 | debug("Error: reading block\n"); | 757 | debug("Error: reading block\n"); |
758 | goto fail; | 758 | goto fail; |
759 | } | 759 | } |
760 | 760 | ||
761 | memcpy(bs, block, sizeof(boot_sector)); | 761 | memcpy(bs, block, sizeof(boot_sector)); |
762 | bs->reserved = FAT2CPU16(bs->reserved); | 762 | bs->reserved = FAT2CPU16(bs->reserved); |
763 | bs->fat_length = FAT2CPU16(bs->fat_length); | 763 | bs->fat_length = FAT2CPU16(bs->fat_length); |
764 | bs->secs_track = FAT2CPU16(bs->secs_track); | 764 | bs->secs_track = FAT2CPU16(bs->secs_track); |
765 | bs->heads = FAT2CPU16(bs->heads); | 765 | bs->heads = FAT2CPU16(bs->heads); |
766 | bs->total_sect = FAT2CPU32(bs->total_sect); | 766 | bs->total_sect = FAT2CPU32(bs->total_sect); |
767 | 767 | ||
768 | /* FAT32 entries */ | 768 | /* FAT32 entries */ |
769 | if (bs->fat_length == 0) { | 769 | if (bs->fat_length == 0) { |
770 | /* Assume FAT32 */ | 770 | /* Assume FAT32 */ |
771 | bs->fat32_length = FAT2CPU32(bs->fat32_length); | 771 | bs->fat32_length = FAT2CPU32(bs->fat32_length); |
772 | bs->flags = FAT2CPU16(bs->flags); | 772 | bs->flags = FAT2CPU16(bs->flags); |
773 | bs->root_cluster = FAT2CPU32(bs->root_cluster); | 773 | bs->root_cluster = FAT2CPU32(bs->root_cluster); |
774 | bs->info_sector = FAT2CPU16(bs->info_sector); | 774 | bs->info_sector = FAT2CPU16(bs->info_sector); |
775 | bs->backup_boot = FAT2CPU16(bs->backup_boot); | 775 | bs->backup_boot = FAT2CPU16(bs->backup_boot); |
776 | vistart = (volume_info *)(block + sizeof(boot_sector)); | 776 | vistart = (volume_info *)(block + sizeof(boot_sector)); |
777 | *fatsize = 32; | 777 | *fatsize = 32; |
778 | } else { | 778 | } else { |
779 | vistart = (volume_info *)&(bs->fat32_length); | 779 | vistart = (volume_info *)&(bs->fat32_length); |
780 | *fatsize = 0; | 780 | *fatsize = 0; |
781 | } | 781 | } |
782 | memcpy(volinfo, vistart, sizeof(volume_info)); | 782 | memcpy(volinfo, vistart, sizeof(volume_info)); |
783 | 783 | ||
784 | if (*fatsize == 32) { | 784 | if (*fatsize == 32) { |
785 | if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) | 785 | if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) |
786 | goto exit; | 786 | goto exit; |
787 | } else { | 787 | } else { |
788 | if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { | 788 | if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { |
789 | *fatsize = 12; | 789 | *fatsize = 12; |
790 | goto exit; | 790 | goto exit; |
791 | } | 791 | } |
792 | if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { | 792 | if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { |
793 | *fatsize = 16; | 793 | *fatsize = 16; |
794 | goto exit; | 794 | goto exit; |
795 | } | 795 | } |
796 | } | 796 | } |
797 | 797 | ||
798 | debug("Error: broken fs_type sign\n"); | 798 | debug("Error: broken fs_type sign\n"); |
799 | fail: | 799 | fail: |
800 | ret = -1; | 800 | ret = -1; |
801 | exit: | 801 | exit: |
802 | free(block); | 802 | free(block); |
803 | return ret; | 803 | return ret; |
804 | } | 804 | } |
805 | 805 | ||
806 | __u8 do_fat_read_at_block[MAX_CLUSTSIZE] | 806 | __u8 do_fat_read_at_block[MAX_CLUSTSIZE] |
807 | __aligned(ARCH_DMA_MINALIGN); | 807 | __aligned(ARCH_DMA_MINALIGN); |
808 | 808 | ||
809 | long | 809 | int do_fat_read_at(const char *filename, loff_t pos, void *buffer, |
810 | do_fat_read_at(const char *filename, unsigned long pos, void *buffer, | 810 | loff_t maxsize, int dols, int dogetsize, loff_t *size) |
811 | unsigned long maxsize, int dols, int dogetsize) | ||
812 | { | 811 | { |
813 | char fnamecopy[2048]; | 812 | char fnamecopy[2048]; |
814 | boot_sector bs; | 813 | boot_sector bs; |
815 | volume_info volinfo; | 814 | volume_info volinfo; |
816 | fsdata datablock; | 815 | fsdata datablock; |
817 | fsdata *mydata = &datablock; | 816 | fsdata *mydata = &datablock; |
818 | dir_entry *dentptr = NULL; | 817 | dir_entry *dentptr = NULL; |
819 | __u16 prevcksum = 0xffff; | 818 | __u16 prevcksum = 0xffff; |
820 | char *subname = ""; | 819 | char *subname = ""; |
821 | __u32 cursect; | 820 | __u32 cursect; |
822 | int idx, isdir = 0; | 821 | int idx, isdir = 0; |
823 | int files = 0, dirs = 0; | 822 | int files = 0, dirs = 0; |
824 | long ret = -1; | 823 | int ret = -1; |
825 | int firsttime; | 824 | int firsttime; |
826 | __u32 root_cluster = 0; | 825 | __u32 root_cluster = 0; |
827 | int rootdir_size = 0; | 826 | int rootdir_size = 0; |
828 | int j; | 827 | int j; |
829 | 828 | ||
830 | if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { | 829 | if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { |
831 | debug("Error: reading boot sector\n"); | 830 | debug("Error: reading boot sector\n"); |
832 | return -1; | 831 | return -1; |
833 | } | 832 | } |
834 | 833 | ||
835 | if (mydata->fatsize == 32) { | 834 | if (mydata->fatsize == 32) { |
836 | root_cluster = bs.root_cluster; | 835 | root_cluster = bs.root_cluster; |
837 | mydata->fatlength = bs.fat32_length; | 836 | mydata->fatlength = bs.fat32_length; |
838 | } else { | 837 | } else { |
839 | mydata->fatlength = bs.fat_length; | 838 | mydata->fatlength = bs.fat_length; |
840 | } | 839 | } |
841 | 840 | ||
842 | mydata->fat_sect = bs.reserved; | 841 | mydata->fat_sect = bs.reserved; |
843 | 842 | ||
844 | cursect = mydata->rootdir_sect | 843 | cursect = mydata->rootdir_sect |
845 | = mydata->fat_sect + mydata->fatlength * bs.fats; | 844 | = mydata->fat_sect + mydata->fatlength * bs.fats; |
846 | 845 | ||
847 | mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; | 846 | mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; |
848 | mydata->clust_size = bs.cluster_size; | 847 | mydata->clust_size = bs.cluster_size; |
849 | if (mydata->sect_size != cur_part_info.blksz) { | 848 | if (mydata->sect_size != cur_part_info.blksz) { |
850 | printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n", | 849 | printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n", |
851 | mydata->sect_size, cur_part_info.blksz); | 850 | mydata->sect_size, cur_part_info.blksz); |
852 | return -1; | 851 | return -1; |
853 | } | 852 | } |
854 | 853 | ||
855 | if (mydata->fatsize == 32) { | 854 | if (mydata->fatsize == 32) { |
856 | mydata->data_begin = mydata->rootdir_sect - | 855 | mydata->data_begin = mydata->rootdir_sect - |
857 | (mydata->clust_size * 2); | 856 | (mydata->clust_size * 2); |
858 | } else { | 857 | } else { |
859 | rootdir_size = ((bs.dir_entries[1] * (int)256 + | 858 | rootdir_size = ((bs.dir_entries[1] * (int)256 + |
860 | bs.dir_entries[0]) * | 859 | bs.dir_entries[0]) * |
861 | sizeof(dir_entry)) / | 860 | sizeof(dir_entry)) / |
862 | mydata->sect_size; | 861 | mydata->sect_size; |
863 | mydata->data_begin = mydata->rootdir_sect + | 862 | mydata->data_begin = mydata->rootdir_sect + |
864 | rootdir_size - | 863 | rootdir_size - |
865 | (mydata->clust_size * 2); | 864 | (mydata->clust_size * 2); |
866 | } | 865 | } |
867 | 866 | ||
868 | mydata->fatbufnum = -1; | 867 | mydata->fatbufnum = -1; |
869 | mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); | 868 | mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); |
870 | if (mydata->fatbuf == NULL) { | 869 | if (mydata->fatbuf == NULL) { |
871 | debug("Error: allocating memory\n"); | 870 | debug("Error: allocating memory\n"); |
872 | return -1; | 871 | return -1; |
873 | } | 872 | } |
874 | 873 | ||
875 | if (vfat_enabled) | 874 | if (vfat_enabled) |
876 | debug("VFAT Support enabled\n"); | 875 | debug("VFAT Support enabled\n"); |
877 | 876 | ||
878 | debug("FAT%d, fat_sect: %d, fatlength: %d\n", | 877 | debug("FAT%d, fat_sect: %d, fatlength: %d\n", |
879 | mydata->fatsize, mydata->fat_sect, mydata->fatlength); | 878 | mydata->fatsize, mydata->fat_sect, mydata->fatlength); |
880 | debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" | 879 | debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" |
881 | "Data begins at: %d\n", | 880 | "Data begins at: %d\n", |
882 | root_cluster, | 881 | root_cluster, |
883 | mydata->rootdir_sect, | 882 | mydata->rootdir_sect, |
884 | mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); | 883 | mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); |
885 | debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, | 884 | debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, |
886 | mydata->clust_size); | 885 | mydata->clust_size); |
887 | 886 | ||
888 | /* "cwd" is always the root... */ | 887 | /* "cwd" is always the root... */ |
889 | while (ISDIRDELIM(*filename)) | 888 | while (ISDIRDELIM(*filename)) |
890 | filename++; | 889 | filename++; |
891 | 890 | ||
892 | /* Make a copy of the filename and convert it to lowercase */ | 891 | /* Make a copy of the filename and convert it to lowercase */ |
893 | strcpy(fnamecopy, filename); | 892 | strcpy(fnamecopy, filename); |
894 | downcase(fnamecopy); | 893 | downcase(fnamecopy); |
895 | 894 | ||
896 | if (*fnamecopy == '\0') { | 895 | if (*fnamecopy == '\0') { |
897 | if (!dols) | 896 | if (!dols) |
898 | goto exit; | 897 | goto exit; |
899 | 898 | ||
900 | dols = LS_ROOT; | 899 | dols = LS_ROOT; |
901 | } else if ((idx = dirdelim(fnamecopy)) >= 0) { | 900 | } else if ((idx = dirdelim(fnamecopy)) >= 0) { |
902 | isdir = 1; | 901 | isdir = 1; |
903 | fnamecopy[idx] = '\0'; | 902 | fnamecopy[idx] = '\0'; |
904 | subname = fnamecopy + idx + 1; | 903 | subname = fnamecopy + idx + 1; |
905 | 904 | ||
906 | /* Handle multiple delimiters */ | 905 | /* Handle multiple delimiters */ |
907 | while (ISDIRDELIM(*subname)) | 906 | while (ISDIRDELIM(*subname)) |
908 | subname++; | 907 | subname++; |
909 | } else if (dols) { | 908 | } else if (dols) { |
910 | isdir = 1; | 909 | isdir = 1; |
911 | } | 910 | } |
912 | 911 | ||
913 | j = 0; | 912 | j = 0; |
914 | while (1) { | 913 | while (1) { |
915 | int i; | 914 | int i; |
916 | 915 | ||
917 | if (j == 0) { | 916 | if (j == 0) { |
918 | debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%zd\n", | 917 | debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%zd\n", |
919 | cursect, mydata->clust_size, DIRENTSPERBLOCK); | 918 | cursect, mydata->clust_size, DIRENTSPERBLOCK); |
920 | 919 | ||
921 | if (disk_read(cursect, | 920 | if (disk_read(cursect, |
922 | (mydata->fatsize == 32) ? | 921 | (mydata->fatsize == 32) ? |
923 | (mydata->clust_size) : | 922 | (mydata->clust_size) : |
924 | PREFETCH_BLOCKS, | 923 | PREFETCH_BLOCKS, |
925 | do_fat_read_at_block) < 0) { | 924 | do_fat_read_at_block) < 0) { |
926 | debug("Error: reading rootdir block\n"); | 925 | debug("Error: reading rootdir block\n"); |
927 | goto exit; | 926 | goto exit; |
928 | } | 927 | } |
929 | 928 | ||
930 | dentptr = (dir_entry *) do_fat_read_at_block; | 929 | dentptr = (dir_entry *) do_fat_read_at_block; |
931 | } | 930 | } |
932 | 931 | ||
933 | for (i = 0; i < DIRENTSPERBLOCK; i++) { | 932 | for (i = 0; i < DIRENTSPERBLOCK; i++) { |
934 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; | 933 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; |
935 | __u8 csum; | 934 | __u8 csum; |
936 | 935 | ||
937 | l_name[0] = '\0'; | 936 | l_name[0] = '\0'; |
938 | if (dentptr->name[0] == DELETED_FLAG) { | 937 | if (dentptr->name[0] == DELETED_FLAG) { |
939 | dentptr++; | 938 | dentptr++; |
940 | continue; | 939 | continue; |
941 | } | 940 | } |
942 | 941 | ||
943 | if (vfat_enabled) | 942 | if (vfat_enabled) |
944 | csum = mkcksum(dentptr->name, dentptr->ext); | 943 | csum = mkcksum(dentptr->name, dentptr->ext); |
945 | 944 | ||
946 | if (dentptr->attr & ATTR_VOLUME) { | 945 | if (dentptr->attr & ATTR_VOLUME) { |
947 | if (vfat_enabled && | 946 | if (vfat_enabled && |
948 | (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && | 947 | (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && |
949 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { | 948 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { |
950 | prevcksum = | 949 | prevcksum = |
951 | ((dir_slot *)dentptr)->alias_checksum; | 950 | ((dir_slot *)dentptr)->alias_checksum; |
952 | 951 | ||
953 | get_vfatname(mydata, | 952 | get_vfatname(mydata, |
954 | root_cluster, | 953 | root_cluster, |
955 | do_fat_read_at_block, | 954 | do_fat_read_at_block, |
956 | dentptr, l_name); | 955 | dentptr, l_name); |
957 | 956 | ||
958 | if (dols == LS_ROOT) { | 957 | if (dols == LS_ROOT) { |
959 | char dirc; | 958 | char dirc; |
960 | int doit = 0; | 959 | int doit = 0; |
961 | int isdir = | 960 | int isdir = |
962 | (dentptr->attr & ATTR_DIR); | 961 | (dentptr->attr & ATTR_DIR); |
963 | 962 | ||
964 | if (isdir) { | 963 | if (isdir) { |
965 | dirs++; | 964 | dirs++; |
966 | dirc = '/'; | 965 | dirc = '/'; |
967 | doit = 1; | 966 | doit = 1; |
968 | } else { | 967 | } else { |
969 | dirc = ' '; | 968 | dirc = ' '; |
970 | if (l_name[0] != 0) { | 969 | if (l_name[0] != 0) { |
971 | files++; | 970 | files++; |
972 | doit = 1; | 971 | doit = 1; |
973 | } | 972 | } |
974 | } | 973 | } |
975 | if (doit) { | 974 | if (doit) { |
976 | if (dirc == ' ') { | 975 | if (dirc == ' ') { |
977 | printf(" %8ld %s%c\n", | 976 | printf(" %8u %s%c\n", |
978 | (long)FAT2CPU32(dentptr->size), | 977 | FAT2CPU32(dentptr->size), |
979 | l_name, | 978 | l_name, |
980 | dirc); | 979 | dirc); |
981 | } else { | 980 | } else { |
982 | printf(" %s%c\n", | 981 | printf(" %s%c\n", |
983 | l_name, | 982 | l_name, |
984 | dirc); | 983 | dirc); |
985 | } | 984 | } |
986 | } | 985 | } |
987 | dentptr++; | 986 | dentptr++; |
988 | continue; | 987 | continue; |
989 | } | 988 | } |
990 | debug("Rootvfatname: |%s|\n", | 989 | debug("Rootvfatname: |%s|\n", |
991 | l_name); | 990 | l_name); |
992 | } else { | 991 | } else { |
993 | /* Volume label or VFAT entry */ | 992 | /* Volume label or VFAT entry */ |
994 | dentptr++; | 993 | dentptr++; |
995 | continue; | 994 | continue; |
996 | } | 995 | } |
997 | } else if (dentptr->name[0] == 0) { | 996 | } else if (dentptr->name[0] == 0) { |
998 | debug("RootDentname == NULL - %d\n", i); | 997 | debug("RootDentname == NULL - %d\n", i); |
999 | if (dols == LS_ROOT) { | 998 | if (dols == LS_ROOT) { |
1000 | printf("\n%d file(s), %d dir(s)\n\n", | 999 | printf("\n%d file(s), %d dir(s)\n\n", |
1001 | files, dirs); | 1000 | files, dirs); |
1002 | ret = 0; | 1001 | ret = 0; |
1003 | } | 1002 | } |
1004 | goto exit; | 1003 | goto exit; |
1005 | } | 1004 | } |
1006 | else if (vfat_enabled && | 1005 | else if (vfat_enabled && |
1007 | dols == LS_ROOT && csum == prevcksum) { | 1006 | dols == LS_ROOT && csum == prevcksum) { |
1008 | prevcksum = 0xffff; | 1007 | prevcksum = 0xffff; |
1009 | dentptr++; | 1008 | dentptr++; |
1010 | continue; | 1009 | continue; |
1011 | } | 1010 | } |
1012 | 1011 | ||
1013 | get_name(dentptr, s_name); | 1012 | get_name(dentptr, s_name); |
1014 | 1013 | ||
1015 | if (dols == LS_ROOT) { | 1014 | if (dols == LS_ROOT) { |
1016 | int isdir = (dentptr->attr & ATTR_DIR); | 1015 | int isdir = (dentptr->attr & ATTR_DIR); |
1017 | char dirc; | 1016 | char dirc; |
1018 | int doit = 0; | 1017 | int doit = 0; |
1019 | 1018 | ||
1020 | if (isdir) { | 1019 | if (isdir) { |
1021 | dirc = '/'; | 1020 | dirc = '/'; |
1022 | if (s_name[0] != 0) { | 1021 | if (s_name[0] != 0) { |
1023 | dirs++; | 1022 | dirs++; |
1024 | doit = 1; | 1023 | doit = 1; |
1025 | } | 1024 | } |
1026 | } else { | 1025 | } else { |
1027 | dirc = ' '; | 1026 | dirc = ' '; |
1028 | if (s_name[0] != 0) { | 1027 | if (s_name[0] != 0) { |
1029 | files++; | 1028 | files++; |
1030 | doit = 1; | 1029 | doit = 1; |
1031 | } | 1030 | } |
1032 | } | 1031 | } |
1033 | if (doit) { | 1032 | if (doit) { |
1034 | if (dirc == ' ') { | 1033 | if (dirc == ' ') { |
1035 | printf(" %8ld %s%c\n", | 1034 | printf(" %8u %s%c\n", |
1036 | (long)FAT2CPU32(dentptr->size), | 1035 | FAT2CPU32(dentptr->size), |
1037 | s_name, dirc); | 1036 | s_name, dirc); |
1038 | } else { | 1037 | } else { |
1039 | printf(" %s%c\n", | 1038 | printf(" %s%c\n", |
1040 | s_name, dirc); | 1039 | s_name, dirc); |
1041 | } | 1040 | } |
1042 | } | 1041 | } |
1043 | dentptr++; | 1042 | dentptr++; |
1044 | continue; | 1043 | continue; |
1045 | } | 1044 | } |
1046 | 1045 | ||
1047 | if (strcmp(fnamecopy, s_name) | 1046 | if (strcmp(fnamecopy, s_name) |
1048 | && strcmp(fnamecopy, l_name)) { | 1047 | && strcmp(fnamecopy, l_name)) { |
1049 | debug("RootMismatch: |%s|%s|\n", s_name, | 1048 | debug("RootMismatch: |%s|%s|\n", s_name, |
1050 | l_name); | 1049 | l_name); |
1051 | dentptr++; | 1050 | dentptr++; |
1052 | continue; | 1051 | continue; |
1053 | } | 1052 | } |
1054 | 1053 | ||
1055 | if (isdir && !(dentptr->attr & ATTR_DIR)) | 1054 | if (isdir && !(dentptr->attr & ATTR_DIR)) |
1056 | goto exit; | 1055 | goto exit; |
1057 | 1056 | ||
1058 | debug("RootName: %s", s_name); | 1057 | debug("RootName: %s", s_name); |
1059 | debug(", start: 0x%x", START(dentptr)); | 1058 | debug(", start: 0x%x", START(dentptr)); |
1060 | debug(", size: 0x%x %s\n", | 1059 | debug(", size: 0x%x %s\n", |
1061 | FAT2CPU32(dentptr->size), | 1060 | FAT2CPU32(dentptr->size), |
1062 | isdir ? "(DIR)" : ""); | 1061 | isdir ? "(DIR)" : ""); |
1063 | 1062 | ||
1064 | goto rootdir_done; /* We got a match */ | 1063 | goto rootdir_done; /* We got a match */ |
1065 | } | 1064 | } |
1066 | debug("END LOOP: j=%d clust_size=%d\n", j, | 1065 | debug("END LOOP: j=%d clust_size=%d\n", j, |
1067 | mydata->clust_size); | 1066 | mydata->clust_size); |
1068 | 1067 | ||
1069 | /* | 1068 | /* |
1070 | * On FAT32 we must fetch the FAT entries for the next | 1069 | * On FAT32 we must fetch the FAT entries for the next |
1071 | * root directory clusters when a cluster has been | 1070 | * root directory clusters when a cluster has been |
1072 | * completely processed. | 1071 | * completely processed. |
1073 | */ | 1072 | */ |
1074 | ++j; | 1073 | ++j; |
1075 | int rootdir_end = 0; | 1074 | int rootdir_end = 0; |
1076 | if (mydata->fatsize == 32) { | 1075 | if (mydata->fatsize == 32) { |
1077 | if (j == mydata->clust_size) { | 1076 | if (j == mydata->clust_size) { |
1078 | int nxtsect = 0; | 1077 | int nxtsect = 0; |
1079 | int nxt_clust = 0; | 1078 | int nxt_clust = 0; |
1080 | 1079 | ||
1081 | nxt_clust = get_fatent(mydata, root_cluster); | 1080 | nxt_clust = get_fatent(mydata, root_cluster); |
1082 | rootdir_end = CHECK_CLUST(nxt_clust, 32); | 1081 | rootdir_end = CHECK_CLUST(nxt_clust, 32); |
1083 | 1082 | ||
1084 | nxtsect = mydata->data_begin + | 1083 | nxtsect = mydata->data_begin + |
1085 | (nxt_clust * mydata->clust_size); | 1084 | (nxt_clust * mydata->clust_size); |
1086 | 1085 | ||
1087 | root_cluster = nxt_clust; | 1086 | root_cluster = nxt_clust; |
1088 | 1087 | ||
1089 | cursect = nxtsect; | 1088 | cursect = nxtsect; |
1090 | j = 0; | 1089 | j = 0; |
1091 | } | 1090 | } |
1092 | } else { | 1091 | } else { |
1093 | if (j == PREFETCH_BLOCKS) | 1092 | if (j == PREFETCH_BLOCKS) |
1094 | j = 0; | 1093 | j = 0; |
1095 | 1094 | ||
1096 | rootdir_end = (++cursect - mydata->rootdir_sect >= | 1095 | rootdir_end = (++cursect - mydata->rootdir_sect >= |
1097 | rootdir_size); | 1096 | rootdir_size); |
1098 | } | 1097 | } |
1099 | 1098 | ||
1100 | /* If end of rootdir reached */ | 1099 | /* If end of rootdir reached */ |
1101 | if (rootdir_end) { | 1100 | if (rootdir_end) { |
1102 | if (dols == LS_ROOT) { | 1101 | if (dols == LS_ROOT) { |
1103 | printf("\n%d file(s), %d dir(s)\n\n", | 1102 | printf("\n%d file(s), %d dir(s)\n\n", |
1104 | files, dirs); | 1103 | files, dirs); |
1105 | ret = 0; | 1104 | *size = 0; |
1106 | } | 1105 | } |
1107 | goto exit; | 1106 | goto exit; |
1108 | } | 1107 | } |
1109 | } | 1108 | } |
1110 | rootdir_done: | 1109 | rootdir_done: |
1111 | 1110 | ||
1112 | firsttime = 1; | 1111 | firsttime = 1; |
1113 | 1112 | ||
1114 | while (isdir) { | 1113 | while (isdir) { |
1115 | int startsect = mydata->data_begin | 1114 | int startsect = mydata->data_begin |
1116 | + START(dentptr) * mydata->clust_size; | 1115 | + START(dentptr) * mydata->clust_size; |
1117 | dir_entry dent; | 1116 | dir_entry dent; |
1118 | char *nextname = NULL; | 1117 | char *nextname = NULL; |
1119 | 1118 | ||
1120 | dent = *dentptr; | 1119 | dent = *dentptr; |
1121 | dentptr = &dent; | 1120 | dentptr = &dent; |
1122 | 1121 | ||
1123 | idx = dirdelim(subname); | 1122 | idx = dirdelim(subname); |
1124 | 1123 | ||
1125 | if (idx >= 0) { | 1124 | if (idx >= 0) { |
1126 | subname[idx] = '\0'; | 1125 | subname[idx] = '\0'; |
1127 | nextname = subname + idx + 1; | 1126 | nextname = subname + idx + 1; |
1128 | /* Handle multiple delimiters */ | 1127 | /* Handle multiple delimiters */ |
1129 | while (ISDIRDELIM(*nextname)) | 1128 | while (ISDIRDELIM(*nextname)) |
1130 | nextname++; | 1129 | nextname++; |
1131 | if (dols && *nextname == '\0') | 1130 | if (dols && *nextname == '\0') |
1132 | firsttime = 0; | 1131 | firsttime = 0; |
1133 | } else { | 1132 | } else { |
1134 | if (dols && firsttime) { | 1133 | if (dols && firsttime) { |
1135 | firsttime = 0; | 1134 | firsttime = 0; |
1136 | } else { | 1135 | } else { |
1137 | isdir = 0; | 1136 | isdir = 0; |
1138 | } | 1137 | } |
1139 | } | 1138 | } |
1140 | 1139 | ||
1141 | if (get_dentfromdir(mydata, startsect, subname, dentptr, | 1140 | if (get_dentfromdir(mydata, startsect, subname, dentptr, |
1142 | isdir ? 0 : dols) == NULL) { | 1141 | isdir ? 0 : dols) == NULL) { |
1143 | if (dols && !isdir) | 1142 | if (dols && !isdir) |
1144 | ret = 0; | 1143 | *size = 0; |
1145 | goto exit; | 1144 | goto exit; |
1146 | } | 1145 | } |
1147 | 1146 | ||
1148 | if (isdir && !(dentptr->attr & ATTR_DIR)) | 1147 | if (isdir && !(dentptr->attr & ATTR_DIR)) |
1149 | goto exit; | 1148 | goto exit; |
1150 | 1149 | ||
1151 | if (idx >= 0) | 1150 | if (idx >= 0) |
1152 | subname = nextname; | 1151 | subname = nextname; |
1153 | } | 1152 | } |
1154 | 1153 | ||
1155 | if (dogetsize) | 1154 | if (dogetsize) { |
1156 | ret = FAT2CPU32(dentptr->size); | 1155 | *size = FAT2CPU32(dentptr->size); |
1157 | else | 1156 | ret = 0; |
1158 | ret = get_contents(mydata, dentptr, pos, buffer, maxsize); | 1157 | } else { |
1159 | debug("Size: %d, got: %ld\n", FAT2CPU32(dentptr->size), ret); | 1158 | ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size); |
1159 | } | ||
1160 | debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size); | ||
1160 | 1161 | ||
1161 | exit: | 1162 | exit: |
1162 | free(mydata->fatbuf); | 1163 | free(mydata->fatbuf); |
1163 | return ret; | 1164 | return ret; |
1164 | } | 1165 | } |
1165 | 1166 | ||
1166 | long | 1167 | int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols, |
1167 | do_fat_read(const char *filename, void *buffer, unsigned long maxsize, int dols) | 1168 | loff_t *actread) |
1168 | { | 1169 | { |
1169 | return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0); | 1170 | return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread); |
1170 | } | 1171 | } |
1171 | 1172 | ||
1172 | int file_fat_detectfs(void) | 1173 | int file_fat_detectfs(void) |
1173 | { | 1174 | { |
1174 | boot_sector bs; | 1175 | boot_sector bs; |
1175 | volume_info volinfo; | 1176 | volume_info volinfo; |
1176 | int fatsize; | 1177 | int fatsize; |
1177 | char vol_label[12]; | 1178 | char vol_label[12]; |
1178 | 1179 | ||
1179 | if (cur_dev == NULL) { | 1180 | if (cur_dev == NULL) { |
1180 | printf("No current device\n"); | 1181 | printf("No current device\n"); |
1181 | return 1; | 1182 | return 1; |
1182 | } | 1183 | } |
1183 | 1184 | ||
1184 | #if defined(CONFIG_CMD_IDE) || \ | 1185 | #if defined(CONFIG_CMD_IDE) || \ |
1185 | defined(CONFIG_CMD_SATA) || \ | 1186 | defined(CONFIG_CMD_SATA) || \ |
1186 | defined(CONFIG_CMD_SCSI) || \ | 1187 | defined(CONFIG_CMD_SCSI) || \ |
1187 | defined(CONFIG_CMD_USB) || \ | 1188 | defined(CONFIG_CMD_USB) || \ |
1188 | defined(CONFIG_MMC) | 1189 | defined(CONFIG_MMC) |
1189 | printf("Interface: "); | 1190 | printf("Interface: "); |
1190 | switch (cur_dev->if_type) { | 1191 | switch (cur_dev->if_type) { |
1191 | case IF_TYPE_IDE: | 1192 | case IF_TYPE_IDE: |
1192 | printf("IDE"); | 1193 | printf("IDE"); |
1193 | break; | 1194 | break; |
1194 | case IF_TYPE_SATA: | 1195 | case IF_TYPE_SATA: |
1195 | printf("SATA"); | 1196 | printf("SATA"); |
1196 | break; | 1197 | break; |
1197 | case IF_TYPE_SCSI: | 1198 | case IF_TYPE_SCSI: |
1198 | printf("SCSI"); | 1199 | printf("SCSI"); |
1199 | break; | 1200 | break; |
1200 | case IF_TYPE_ATAPI: | 1201 | case IF_TYPE_ATAPI: |
1201 | printf("ATAPI"); | 1202 | printf("ATAPI"); |
1202 | break; | 1203 | break; |
1203 | case IF_TYPE_USB: | 1204 | case IF_TYPE_USB: |
1204 | printf("USB"); | 1205 | printf("USB"); |
1205 | break; | 1206 | break; |
1206 | case IF_TYPE_DOC: | 1207 | case IF_TYPE_DOC: |
1207 | printf("DOC"); | 1208 | printf("DOC"); |
1208 | break; | 1209 | break; |
1209 | case IF_TYPE_MMC: | 1210 | case IF_TYPE_MMC: |
1210 | printf("MMC"); | 1211 | printf("MMC"); |
1211 | break; | 1212 | break; |
1212 | default: | 1213 | default: |
1213 | printf("Unknown"); | 1214 | printf("Unknown"); |
1214 | } | 1215 | } |
1215 | 1216 | ||
1216 | printf("\n Device %d: ", cur_dev->dev); | 1217 | printf("\n Device %d: ", cur_dev->dev); |
1217 | dev_print(cur_dev); | 1218 | dev_print(cur_dev); |
1218 | #endif | 1219 | #endif |
1219 | 1220 | ||
1220 | if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { | 1221 | if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { |
1221 | printf("\nNo valid FAT fs found\n"); | 1222 | printf("\nNo valid FAT fs found\n"); |
1222 | return 1; | 1223 | return 1; |
1223 | } | 1224 | } |
1224 | 1225 | ||
1225 | memcpy(vol_label, volinfo.volume_label, 11); | 1226 | memcpy(vol_label, volinfo.volume_label, 11); |
1226 | vol_label[11] = '\0'; | 1227 | vol_label[11] = '\0'; |
1227 | volinfo.fs_type[5] = '\0'; | 1228 | volinfo.fs_type[5] = '\0'; |
1228 | 1229 | ||
1229 | printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); | 1230 | printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); |
1230 | 1231 | ||
1231 | return 0; | 1232 | return 0; |
1232 | } | 1233 | } |
1233 | 1234 | ||
1234 | int file_fat_ls(const char *dir) | 1235 | int file_fat_ls(const char *dir) |
1235 | { | 1236 | { |
1236 | return do_fat_read(dir, NULL, 0, LS_YES); | 1237 | loff_t size; |
1238 | |||
1239 | return do_fat_read(dir, NULL, 0, LS_YES, &size); | ||
1237 | } | 1240 | } |
1238 | 1241 | ||
1239 | int fat_exists(const char *filename) | 1242 | int fat_exists(const char *filename) |
1240 | { | 1243 | { |
1241 | int sz; | 1244 | int ret; |
1242 | sz = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1); | 1245 | loff_t size; |
1243 | return sz >= 0; | 1246 | |
1247 | ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size); | ||
1248 | return ret == 0; | ||
1244 | } | 1249 | } |
1245 | 1250 | ||
1246 | int fat_size(const char *filename) | 1251 | int fat_size(const char *filename) |
1247 | { | 1252 | { |
1248 | return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1); | 1253 | loff_t size; |
1254 | int ret; | ||
1255 | |||
1256 | ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size); | ||
1257 | if (ret) | ||
1258 | return ret; | ||
1259 | else | ||
1260 | return size; | ||
1249 | } | 1261 | } |
1250 | 1262 | ||
1251 | long file_fat_read_at(const char *filename, unsigned long pos, void *buffer, | 1263 | int file_fat_read_at(const char *filename, loff_t pos, void *buffer, |
1252 | unsigned long maxsize) | 1264 | loff_t maxsize, loff_t *actread) |
1253 | { | 1265 | { |
1254 | printf("reading %s\n", filename); | 1266 | printf("reading %s\n", filename); |
1255 | return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0); | 1267 | return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0, |
1268 | actread); | ||
1256 | } | 1269 | } |
1257 | 1270 | ||
1258 | long file_fat_read(const char *filename, void *buffer, unsigned long maxsize) | 1271 | int file_fat_read(const char *filename, void *buffer, int maxsize) |
1259 | { | 1272 | { |
1260 | return file_fat_read_at(filename, 0, buffer, maxsize); | 1273 | loff_t actread; |
1274 | int ret; | ||
1275 | |||
1276 | ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread); | ||
1277 | if (ret) | ||
1278 | return ret; | ||
1279 | else | ||
1280 | return actread; | ||
1261 | } | 1281 | } |
1262 | 1282 | ||
1263 | int fat_read_file(const char *filename, void *buf, int offset, int len) | 1283 | int fat_read_file(const char *filename, void *buf, int offset, int len) |
1264 | { | 1284 | { |
1265 | int len_read; | 1285 | int ret; |
1286 | loff_t actread; | ||
1266 | 1287 | ||
1267 | len_read = file_fat_read_at(filename, offset, buf, len); | 1288 | ret = file_fat_read_at(filename, offset, buf, len, &actread); |
1268 | if (len_read == -1) { | 1289 | if (ret) { |
1269 | printf("** Unable to read file %s **\n", filename); | 1290 | printf("** Unable to read file %s **\n", filename); |
1270 | return -1; | 1291 | return ret; |
1271 | } | 1292 | } |
1272 | 1293 | ||
1273 | return len_read; | 1294 | return actread; |
1274 | } | 1295 | } |
1275 | 1296 | ||
1276 | void fat_close(void) | 1297 | void fat_close(void) |
1277 | { | 1298 | { |
fs/fat/fat_write.c
1 | /* | 1 | /* |
2 | * fat_write.c | 2 | * fat_write.c |
3 | * | 3 | * |
4 | * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim | 4 | * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim |
5 | * | 5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <common.h> | 9 | #include <common.h> |
10 | #include <command.h> | 10 | #include <command.h> |
11 | #include <config.h> | 11 | #include <config.h> |
12 | #include <fat.h> | 12 | #include <fat.h> |
13 | #include <asm/byteorder.h> | 13 | #include <asm/byteorder.h> |
14 | #include <part.h> | 14 | #include <part.h> |
15 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
16 | #include "fat.c" | 16 | #include "fat.c" |
17 | 17 | ||
18 | static void uppercase(char *str, int len) | 18 | static void uppercase(char *str, int len) |
19 | { | 19 | { |
20 | int i; | 20 | int i; |
21 | 21 | ||
22 | for (i = 0; i < len; i++) { | 22 | for (i = 0; i < len; i++) { |
23 | *str = toupper(*str); | 23 | *str = toupper(*str); |
24 | str++; | 24 | str++; |
25 | } | 25 | } |
26 | } | 26 | } |
27 | 27 | ||
28 | static int total_sector; | 28 | static int total_sector; |
29 | static int disk_write(__u32 block, __u32 nr_blocks, void *buf) | 29 | static int disk_write(__u32 block, __u32 nr_blocks, void *buf) |
30 | { | 30 | { |
31 | if (!cur_dev || !cur_dev->block_write) | 31 | if (!cur_dev || !cur_dev->block_write) |
32 | return -1; | 32 | return -1; |
33 | 33 | ||
34 | if (cur_part_info.start + block + nr_blocks > | 34 | if (cur_part_info.start + block + nr_blocks > |
35 | cur_part_info.start + total_sector) { | 35 | cur_part_info.start + total_sector) { |
36 | printf("error: overflow occurs\n"); | 36 | printf("error: overflow occurs\n"); |
37 | return -1; | 37 | return -1; |
38 | } | 38 | } |
39 | 39 | ||
40 | return cur_dev->block_write(cur_dev->dev, | 40 | return cur_dev->block_write(cur_dev->dev, |
41 | cur_part_info.start + block, nr_blocks, buf); | 41 | cur_part_info.start + block, nr_blocks, buf); |
42 | } | 42 | } |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Set short name in directory entry | 45 | * Set short name in directory entry |
46 | */ | 46 | */ |
47 | static void set_name(dir_entry *dirent, const char *filename) | 47 | static void set_name(dir_entry *dirent, const char *filename) |
48 | { | 48 | { |
49 | char s_name[VFAT_MAXLEN_BYTES]; | 49 | char s_name[VFAT_MAXLEN_BYTES]; |
50 | char *period; | 50 | char *period; |
51 | int period_location, len, i, ext_num; | 51 | int period_location, len, i, ext_num; |
52 | 52 | ||
53 | if (filename == NULL) | 53 | if (filename == NULL) |
54 | return; | 54 | return; |
55 | 55 | ||
56 | len = strlen(filename); | 56 | len = strlen(filename); |
57 | if (len == 0) | 57 | if (len == 0) |
58 | return; | 58 | return; |
59 | 59 | ||
60 | strcpy(s_name, filename); | 60 | strcpy(s_name, filename); |
61 | uppercase(s_name, len); | 61 | uppercase(s_name, len); |
62 | 62 | ||
63 | period = strchr(s_name, '.'); | 63 | period = strchr(s_name, '.'); |
64 | if (period == NULL) { | 64 | if (period == NULL) { |
65 | period_location = len; | 65 | period_location = len; |
66 | ext_num = 0; | 66 | ext_num = 0; |
67 | } else { | 67 | } else { |
68 | period_location = period - s_name; | 68 | period_location = period - s_name; |
69 | ext_num = len - period_location - 1; | 69 | ext_num = len - period_location - 1; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* Pad spaces when the length of file name is shorter than eight */ | 72 | /* Pad spaces when the length of file name is shorter than eight */ |
73 | if (period_location < 8) { | 73 | if (period_location < 8) { |
74 | memcpy(dirent->name, s_name, period_location); | 74 | memcpy(dirent->name, s_name, period_location); |
75 | for (i = period_location; i < 8; i++) | 75 | for (i = period_location; i < 8; i++) |
76 | dirent->name[i] = ' '; | 76 | dirent->name[i] = ' '; |
77 | } else if (period_location == 8) { | 77 | } else if (period_location == 8) { |
78 | memcpy(dirent->name, s_name, period_location); | 78 | memcpy(dirent->name, s_name, period_location); |
79 | } else { | 79 | } else { |
80 | memcpy(dirent->name, s_name, 6); | 80 | memcpy(dirent->name, s_name, 6); |
81 | dirent->name[6] = '~'; | 81 | dirent->name[6] = '~'; |
82 | dirent->name[7] = '1'; | 82 | dirent->name[7] = '1'; |
83 | } | 83 | } |
84 | 84 | ||
85 | if (ext_num < 3) { | 85 | if (ext_num < 3) { |
86 | memcpy(dirent->ext, s_name + period_location + 1, ext_num); | 86 | memcpy(dirent->ext, s_name + period_location + 1, ext_num); |
87 | for (i = ext_num; i < 3; i++) | 87 | for (i = ext_num; i < 3; i++) |
88 | dirent->ext[i] = ' '; | 88 | dirent->ext[i] = ' '; |
89 | } else | 89 | } else |
90 | memcpy(dirent->ext, s_name + period_location + 1, 3); | 90 | memcpy(dirent->ext, s_name + period_location + 1, 3); |
91 | 91 | ||
92 | debug("name : %s\n", dirent->name); | 92 | debug("name : %s\n", dirent->name); |
93 | debug("ext : %s\n", dirent->ext); | 93 | debug("ext : %s\n", dirent->ext); |
94 | } | 94 | } |
95 | 95 | ||
96 | static __u8 num_of_fats; | 96 | static __u8 num_of_fats; |
97 | /* | 97 | /* |
98 | * Write fat buffer into block device | 98 | * Write fat buffer into block device |
99 | */ | 99 | */ |
100 | static int flush_fat_buffer(fsdata *mydata) | 100 | static int flush_fat_buffer(fsdata *mydata) |
101 | { | 101 | { |
102 | int getsize = FATBUFBLOCKS; | 102 | int getsize = FATBUFBLOCKS; |
103 | __u32 fatlength = mydata->fatlength; | 103 | __u32 fatlength = mydata->fatlength; |
104 | __u8 *bufptr = mydata->fatbuf; | 104 | __u8 *bufptr = mydata->fatbuf; |
105 | __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS; | 105 | __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS; |
106 | 106 | ||
107 | startblock += mydata->fat_sect; | 107 | startblock += mydata->fat_sect; |
108 | 108 | ||
109 | if (getsize > fatlength) | 109 | if (getsize > fatlength) |
110 | getsize = fatlength; | 110 | getsize = fatlength; |
111 | 111 | ||
112 | /* Write FAT buf */ | 112 | /* Write FAT buf */ |
113 | if (disk_write(startblock, getsize, bufptr) < 0) { | 113 | if (disk_write(startblock, getsize, bufptr) < 0) { |
114 | debug("error: writing FAT blocks\n"); | 114 | debug("error: writing FAT blocks\n"); |
115 | return -1; | 115 | return -1; |
116 | } | 116 | } |
117 | 117 | ||
118 | if (num_of_fats == 2) { | 118 | if (num_of_fats == 2) { |
119 | /* Update corresponding second FAT blocks */ | 119 | /* Update corresponding second FAT blocks */ |
120 | startblock += mydata->fatlength; | 120 | startblock += mydata->fatlength; |
121 | if (disk_write(startblock, getsize, bufptr) < 0) { | 121 | if (disk_write(startblock, getsize, bufptr) < 0) { |
122 | debug("error: writing second FAT blocks\n"); | 122 | debug("error: writing second FAT blocks\n"); |
123 | return -1; | 123 | return -1; |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * Get the entry at index 'entry' in a FAT (12/16/32) table. | 131 | * Get the entry at index 'entry' in a FAT (12/16/32) table. |
132 | * On failure 0x00 is returned. | 132 | * On failure 0x00 is returned. |
133 | * When bufnum is changed, write back the previous fatbuf to the disk. | 133 | * When bufnum is changed, write back the previous fatbuf to the disk. |
134 | */ | 134 | */ |
135 | static __u32 get_fatent_value(fsdata *mydata, __u32 entry) | 135 | static __u32 get_fatent_value(fsdata *mydata, __u32 entry) |
136 | { | 136 | { |
137 | __u32 bufnum; | 137 | __u32 bufnum; |
138 | __u32 off16, offset; | 138 | __u32 off16, offset; |
139 | __u32 ret = 0x00; | 139 | __u32 ret = 0x00; |
140 | __u16 val1, val2; | 140 | __u16 val1, val2; |
141 | 141 | ||
142 | if (CHECK_CLUST(entry, mydata->fatsize)) { | 142 | if (CHECK_CLUST(entry, mydata->fatsize)) { |
143 | printf("Error: Invalid FAT entry: 0x%08x\n", entry); | 143 | printf("Error: Invalid FAT entry: 0x%08x\n", entry); |
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
146 | 146 | ||
147 | switch (mydata->fatsize) { | 147 | switch (mydata->fatsize) { |
148 | case 32: | 148 | case 32: |
149 | bufnum = entry / FAT32BUFSIZE; | 149 | bufnum = entry / FAT32BUFSIZE; |
150 | offset = entry - bufnum * FAT32BUFSIZE; | 150 | offset = entry - bufnum * FAT32BUFSIZE; |
151 | break; | 151 | break; |
152 | case 16: | 152 | case 16: |
153 | bufnum = entry / FAT16BUFSIZE; | 153 | bufnum = entry / FAT16BUFSIZE; |
154 | offset = entry - bufnum * FAT16BUFSIZE; | 154 | offset = entry - bufnum * FAT16BUFSIZE; |
155 | break; | 155 | break; |
156 | case 12: | 156 | case 12: |
157 | bufnum = entry / FAT12BUFSIZE; | 157 | bufnum = entry / FAT12BUFSIZE; |
158 | offset = entry - bufnum * FAT12BUFSIZE; | 158 | offset = entry - bufnum * FAT12BUFSIZE; |
159 | break; | 159 | break; |
160 | 160 | ||
161 | default: | 161 | default: |
162 | /* Unsupported FAT size */ | 162 | /* Unsupported FAT size */ |
163 | return ret; | 163 | return ret; |
164 | } | 164 | } |
165 | 165 | ||
166 | debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", | 166 | debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", |
167 | mydata->fatsize, entry, entry, offset, offset); | 167 | mydata->fatsize, entry, entry, offset, offset); |
168 | 168 | ||
169 | /* Read a new block of FAT entries into the cache. */ | 169 | /* Read a new block of FAT entries into the cache. */ |
170 | if (bufnum != mydata->fatbufnum) { | 170 | if (bufnum != mydata->fatbufnum) { |
171 | int getsize = FATBUFBLOCKS; | 171 | int getsize = FATBUFBLOCKS; |
172 | __u8 *bufptr = mydata->fatbuf; | 172 | __u8 *bufptr = mydata->fatbuf; |
173 | __u32 fatlength = mydata->fatlength; | 173 | __u32 fatlength = mydata->fatlength; |
174 | __u32 startblock = bufnum * FATBUFBLOCKS; | 174 | __u32 startblock = bufnum * FATBUFBLOCKS; |
175 | 175 | ||
176 | if (getsize > fatlength) | 176 | if (getsize > fatlength) |
177 | getsize = fatlength; | 177 | getsize = fatlength; |
178 | 178 | ||
179 | fatlength *= mydata->sect_size; /* We want it in bytes now */ | 179 | fatlength *= mydata->sect_size; /* We want it in bytes now */ |
180 | startblock += mydata->fat_sect; /* Offset from start of disk */ | 180 | startblock += mydata->fat_sect; /* Offset from start of disk */ |
181 | 181 | ||
182 | /* Write back the fatbuf to the disk */ | 182 | /* Write back the fatbuf to the disk */ |
183 | if (mydata->fatbufnum != -1) { | 183 | if (mydata->fatbufnum != -1) { |
184 | if (flush_fat_buffer(mydata) < 0) | 184 | if (flush_fat_buffer(mydata) < 0) |
185 | return -1; | 185 | return -1; |
186 | } | 186 | } |
187 | 187 | ||
188 | if (disk_read(startblock, getsize, bufptr) < 0) { | 188 | if (disk_read(startblock, getsize, bufptr) < 0) { |
189 | debug("Error reading FAT blocks\n"); | 189 | debug("Error reading FAT blocks\n"); |
190 | return ret; | 190 | return ret; |
191 | } | 191 | } |
192 | mydata->fatbufnum = bufnum; | 192 | mydata->fatbufnum = bufnum; |
193 | } | 193 | } |
194 | 194 | ||
195 | /* Get the actual entry from the table */ | 195 | /* Get the actual entry from the table */ |
196 | switch (mydata->fatsize) { | 196 | switch (mydata->fatsize) { |
197 | case 32: | 197 | case 32: |
198 | ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); | 198 | ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); |
199 | break; | 199 | break; |
200 | case 16: | 200 | case 16: |
201 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); | 201 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); |
202 | break; | 202 | break; |
203 | case 12: | 203 | case 12: |
204 | off16 = (offset * 3) / 4; | 204 | off16 = (offset * 3) / 4; |
205 | 205 | ||
206 | switch (offset & 0x3) { | 206 | switch (offset & 0x3) { |
207 | case 0: | 207 | case 0: |
208 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); | 208 | ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); |
209 | ret &= 0xfff; | 209 | ret &= 0xfff; |
210 | break; | 210 | break; |
211 | case 1: | 211 | case 1: |
212 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 212 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
213 | val1 &= 0xf000; | 213 | val1 &= 0xf000; |
214 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); | 214 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); |
215 | val2 &= 0x00ff; | 215 | val2 &= 0x00ff; |
216 | ret = (val2 << 4) | (val1 >> 12); | 216 | ret = (val2 << 4) | (val1 >> 12); |
217 | break; | 217 | break; |
218 | case 2: | 218 | case 2: |
219 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 219 | val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
220 | val1 &= 0xff00; | 220 | val1 &= 0xff00; |
221 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); | 221 | val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); |
222 | val2 &= 0x000f; | 222 | val2 &= 0x000f; |
223 | ret = (val2 << 8) | (val1 >> 8); | 223 | ret = (val2 << 8) | (val1 >> 8); |
224 | break; | 224 | break; |
225 | case 3: | 225 | case 3: |
226 | ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); | 226 | ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); |
227 | ret = (ret & 0xfff0) >> 4; | 227 | ret = (ret & 0xfff0) >> 4; |
228 | break; | 228 | break; |
229 | default: | 229 | default: |
230 | break; | 230 | break; |
231 | } | 231 | } |
232 | break; | 232 | break; |
233 | } | 233 | } |
234 | debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n", | 234 | debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n", |
235 | mydata->fatsize, ret, entry, offset); | 235 | mydata->fatsize, ret, entry, offset); |
236 | 236 | ||
237 | return ret; | 237 | return ret; |
238 | } | 238 | } |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Set the file name information from 'name' into 'slotptr', | 241 | * Set the file name information from 'name' into 'slotptr', |
242 | */ | 242 | */ |
243 | static int str2slot(dir_slot *slotptr, const char *name, int *idx) | 243 | static int str2slot(dir_slot *slotptr, const char *name, int *idx) |
244 | { | 244 | { |
245 | int j, end_idx = 0; | 245 | int j, end_idx = 0; |
246 | 246 | ||
247 | for (j = 0; j <= 8; j += 2) { | 247 | for (j = 0; j <= 8; j += 2) { |
248 | if (name[*idx] == 0x00) { | 248 | if (name[*idx] == 0x00) { |
249 | slotptr->name0_4[j] = 0; | 249 | slotptr->name0_4[j] = 0; |
250 | slotptr->name0_4[j + 1] = 0; | 250 | slotptr->name0_4[j + 1] = 0; |
251 | end_idx++; | 251 | end_idx++; |
252 | goto name0_4; | 252 | goto name0_4; |
253 | } | 253 | } |
254 | slotptr->name0_4[j] = name[*idx]; | 254 | slotptr->name0_4[j] = name[*idx]; |
255 | (*idx)++; | 255 | (*idx)++; |
256 | end_idx++; | 256 | end_idx++; |
257 | } | 257 | } |
258 | for (j = 0; j <= 10; j += 2) { | 258 | for (j = 0; j <= 10; j += 2) { |
259 | if (name[*idx] == 0x00) { | 259 | if (name[*idx] == 0x00) { |
260 | slotptr->name5_10[j] = 0; | 260 | slotptr->name5_10[j] = 0; |
261 | slotptr->name5_10[j + 1] = 0; | 261 | slotptr->name5_10[j + 1] = 0; |
262 | end_idx++; | 262 | end_idx++; |
263 | goto name5_10; | 263 | goto name5_10; |
264 | } | 264 | } |
265 | slotptr->name5_10[j] = name[*idx]; | 265 | slotptr->name5_10[j] = name[*idx]; |
266 | (*idx)++; | 266 | (*idx)++; |
267 | end_idx++; | 267 | end_idx++; |
268 | } | 268 | } |
269 | for (j = 0; j <= 2; j += 2) { | 269 | for (j = 0; j <= 2; j += 2) { |
270 | if (name[*idx] == 0x00) { | 270 | if (name[*idx] == 0x00) { |
271 | slotptr->name11_12[j] = 0; | 271 | slotptr->name11_12[j] = 0; |
272 | slotptr->name11_12[j + 1] = 0; | 272 | slotptr->name11_12[j + 1] = 0; |
273 | end_idx++; | 273 | end_idx++; |
274 | goto name11_12; | 274 | goto name11_12; |
275 | } | 275 | } |
276 | slotptr->name11_12[j] = name[*idx]; | 276 | slotptr->name11_12[j] = name[*idx]; |
277 | (*idx)++; | 277 | (*idx)++; |
278 | end_idx++; | 278 | end_idx++; |
279 | } | 279 | } |
280 | 280 | ||
281 | if (name[*idx] == 0x00) | 281 | if (name[*idx] == 0x00) |
282 | return 1; | 282 | return 1; |
283 | 283 | ||
284 | return 0; | 284 | return 0; |
285 | /* Not used characters are filled with 0xff 0xff */ | 285 | /* Not used characters are filled with 0xff 0xff */ |
286 | name0_4: | 286 | name0_4: |
287 | for (; end_idx < 5; end_idx++) { | 287 | for (; end_idx < 5; end_idx++) { |
288 | slotptr->name0_4[end_idx * 2] = 0xff; | 288 | slotptr->name0_4[end_idx * 2] = 0xff; |
289 | slotptr->name0_4[end_idx * 2 + 1] = 0xff; | 289 | slotptr->name0_4[end_idx * 2 + 1] = 0xff; |
290 | } | 290 | } |
291 | end_idx = 5; | 291 | end_idx = 5; |
292 | name5_10: | 292 | name5_10: |
293 | end_idx -= 5; | 293 | end_idx -= 5; |
294 | for (; end_idx < 6; end_idx++) { | 294 | for (; end_idx < 6; end_idx++) { |
295 | slotptr->name5_10[end_idx * 2] = 0xff; | 295 | slotptr->name5_10[end_idx * 2] = 0xff; |
296 | slotptr->name5_10[end_idx * 2 + 1] = 0xff; | 296 | slotptr->name5_10[end_idx * 2 + 1] = 0xff; |
297 | } | 297 | } |
298 | end_idx = 11; | 298 | end_idx = 11; |
299 | name11_12: | 299 | name11_12: |
300 | end_idx -= 11; | 300 | end_idx -= 11; |
301 | for (; end_idx < 2; end_idx++) { | 301 | for (; end_idx < 2; end_idx++) { |
302 | slotptr->name11_12[end_idx * 2] = 0xff; | 302 | slotptr->name11_12[end_idx * 2] = 0xff; |
303 | slotptr->name11_12[end_idx * 2 + 1] = 0xff; | 303 | slotptr->name11_12[end_idx * 2 + 1] = 0xff; |
304 | } | 304 | } |
305 | 305 | ||
306 | return 1; | 306 | return 1; |
307 | } | 307 | } |
308 | 308 | ||
309 | static int is_next_clust(fsdata *mydata, dir_entry *dentptr); | 309 | static int is_next_clust(fsdata *mydata, dir_entry *dentptr); |
310 | static void flush_dir_table(fsdata *mydata, dir_entry **dentptr); | 310 | static void flush_dir_table(fsdata *mydata, dir_entry **dentptr); |
311 | 311 | ||
312 | /* | 312 | /* |
313 | * Fill dir_slot entries with appropriate name, id, and attr | 313 | * Fill dir_slot entries with appropriate name, id, and attr |
314 | * The real directory entry is returned by 'dentptr' | 314 | * The real directory entry is returned by 'dentptr' |
315 | */ | 315 | */ |
316 | static void | 316 | static void |
317 | fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) | 317 | fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) |
318 | { | 318 | { |
319 | dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block; | 319 | dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block; |
320 | __u8 counter = 0, checksum; | 320 | __u8 counter = 0, checksum; |
321 | int idx = 0, ret; | 321 | int idx = 0, ret; |
322 | char s_name[16]; | 322 | char s_name[16]; |
323 | 323 | ||
324 | /* Get short file name and checksum value */ | 324 | /* Get short file name and checksum value */ |
325 | strncpy(s_name, (*dentptr)->name, 16); | 325 | strncpy(s_name, (*dentptr)->name, 16); |
326 | checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); | 326 | checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); |
327 | 327 | ||
328 | do { | 328 | do { |
329 | memset(slotptr, 0x00, sizeof(dir_slot)); | 329 | memset(slotptr, 0x00, sizeof(dir_slot)); |
330 | ret = str2slot(slotptr, l_name, &idx); | 330 | ret = str2slot(slotptr, l_name, &idx); |
331 | slotptr->id = ++counter; | 331 | slotptr->id = ++counter; |
332 | slotptr->attr = ATTR_VFAT; | 332 | slotptr->attr = ATTR_VFAT; |
333 | slotptr->alias_checksum = checksum; | 333 | slotptr->alias_checksum = checksum; |
334 | slotptr++; | 334 | slotptr++; |
335 | } while (ret == 0); | 335 | } while (ret == 0); |
336 | 336 | ||
337 | slotptr--; | 337 | slotptr--; |
338 | slotptr->id |= LAST_LONG_ENTRY_MASK; | 338 | slotptr->id |= LAST_LONG_ENTRY_MASK; |
339 | 339 | ||
340 | while (counter >= 1) { | 340 | while (counter >= 1) { |
341 | if (is_next_clust(mydata, *dentptr)) { | 341 | if (is_next_clust(mydata, *dentptr)) { |
342 | /* A new cluster is allocated for directory table */ | 342 | /* A new cluster is allocated for directory table */ |
343 | flush_dir_table(mydata, dentptr); | 343 | flush_dir_table(mydata, dentptr); |
344 | } | 344 | } |
345 | memcpy(*dentptr, slotptr, sizeof(dir_slot)); | 345 | memcpy(*dentptr, slotptr, sizeof(dir_slot)); |
346 | (*dentptr)++; | 346 | (*dentptr)++; |
347 | slotptr--; | 347 | slotptr--; |
348 | counter--; | 348 | counter--; |
349 | } | 349 | } |
350 | 350 | ||
351 | if (is_next_clust(mydata, *dentptr)) { | 351 | if (is_next_clust(mydata, *dentptr)) { |
352 | /* A new cluster is allocated for directory table */ | 352 | /* A new cluster is allocated for directory table */ |
353 | flush_dir_table(mydata, dentptr); | 353 | flush_dir_table(mydata, dentptr); |
354 | } | 354 | } |
355 | } | 355 | } |
356 | 356 | ||
357 | static __u32 dir_curclust; | 357 | static __u32 dir_curclust; |
358 | 358 | ||
359 | /* | 359 | /* |
360 | * Extract the full long filename starting at 'retdent' (which is really | 360 | * Extract the full long filename starting at 'retdent' (which is really |
361 | * a slot) into 'l_name'. If successful also copy the real directory entry | 361 | * a slot) into 'l_name'. If successful also copy the real directory entry |
362 | * into 'retdent' | 362 | * into 'retdent' |
363 | * If additional adjacent cluster for directory entries is read into memory, | 363 | * If additional adjacent cluster for directory entries is read into memory, |
364 | * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and | 364 | * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and |
365 | * the location of the real directory entry is returned by 'retdent' | 365 | * the location of the real directory entry is returned by 'retdent' |
366 | * Return 0 on success, -1 otherwise. | 366 | * Return 0 on success, -1 otherwise. |
367 | */ | 367 | */ |
368 | static int | 368 | static int |
369 | get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, | 369 | get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, |
370 | dir_entry **retdent, char *l_name) | 370 | dir_entry **retdent, char *l_name) |
371 | { | 371 | { |
372 | dir_entry *realdent; | 372 | dir_entry *realdent; |
373 | dir_slot *slotptr = (dir_slot *)(*retdent); | 373 | dir_slot *slotptr = (dir_slot *)(*retdent); |
374 | dir_slot *slotptr2 = NULL; | 374 | dir_slot *slotptr2 = NULL; |
375 | __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? | 375 | __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? |
376 | PREFETCH_BLOCKS : | 376 | PREFETCH_BLOCKS : |
377 | mydata->clust_size); | 377 | mydata->clust_size); |
378 | __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; | 378 | __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; |
379 | int idx = 0, cur_position = 0; | 379 | int idx = 0, cur_position = 0; |
380 | 380 | ||
381 | if (counter > VFAT_MAXSEQ) { | 381 | if (counter > VFAT_MAXSEQ) { |
382 | debug("Error: VFAT name is too long\n"); | 382 | debug("Error: VFAT name is too long\n"); |
383 | return -1; | 383 | return -1; |
384 | } | 384 | } |
385 | 385 | ||
386 | while ((__u8 *)slotptr < buflimit) { | 386 | while ((__u8 *)slotptr < buflimit) { |
387 | if (counter == 0) | 387 | if (counter == 0) |
388 | break; | 388 | break; |
389 | if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) | 389 | if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) |
390 | return -1; | 390 | return -1; |
391 | slotptr++; | 391 | slotptr++; |
392 | counter--; | 392 | counter--; |
393 | } | 393 | } |
394 | 394 | ||
395 | if ((__u8 *)slotptr >= buflimit) { | 395 | if ((__u8 *)slotptr >= buflimit) { |
396 | if (curclust == 0) | 396 | if (curclust == 0) |
397 | return -1; | 397 | return -1; |
398 | curclust = get_fatent_value(mydata, dir_curclust); | 398 | curclust = get_fatent_value(mydata, dir_curclust); |
399 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 399 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
400 | debug("curclust: 0x%x\n", curclust); | 400 | debug("curclust: 0x%x\n", curclust); |
401 | printf("Invalid FAT entry\n"); | 401 | printf("Invalid FAT entry\n"); |
402 | return -1; | 402 | return -1; |
403 | } | 403 | } |
404 | 404 | ||
405 | dir_curclust = curclust; | 405 | dir_curclust = curclust; |
406 | 406 | ||
407 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, | 407 | if (get_cluster(mydata, curclust, get_contents_vfatname_block, |
408 | mydata->clust_size * mydata->sect_size) != 0) { | 408 | mydata->clust_size * mydata->sect_size) != 0) { |
409 | debug("Error: reading directory block\n"); | 409 | debug("Error: reading directory block\n"); |
410 | return -1; | 410 | return -1; |
411 | } | 411 | } |
412 | 412 | ||
413 | slotptr2 = (dir_slot *)get_contents_vfatname_block; | 413 | slotptr2 = (dir_slot *)get_contents_vfatname_block; |
414 | while (counter > 0) { | 414 | while (counter > 0) { |
415 | if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) | 415 | if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) |
416 | & 0xff) != counter) | 416 | & 0xff) != counter) |
417 | return -1; | 417 | return -1; |
418 | slotptr2++; | 418 | slotptr2++; |
419 | counter--; | 419 | counter--; |
420 | } | 420 | } |
421 | 421 | ||
422 | /* Save the real directory entry */ | 422 | /* Save the real directory entry */ |
423 | realdent = (dir_entry *)slotptr2; | 423 | realdent = (dir_entry *)slotptr2; |
424 | while ((__u8 *)slotptr2 > get_contents_vfatname_block) { | 424 | while ((__u8 *)slotptr2 > get_contents_vfatname_block) { |
425 | slotptr2--; | 425 | slotptr2--; |
426 | slot2str(slotptr2, l_name, &idx); | 426 | slot2str(slotptr2, l_name, &idx); |
427 | } | 427 | } |
428 | } else { | 428 | } else { |
429 | /* Save the real directory entry */ | 429 | /* Save the real directory entry */ |
430 | realdent = (dir_entry *)slotptr; | 430 | realdent = (dir_entry *)slotptr; |
431 | } | 431 | } |
432 | 432 | ||
433 | do { | 433 | do { |
434 | slotptr--; | 434 | slotptr--; |
435 | if (slot2str(slotptr, l_name, &idx)) | 435 | if (slot2str(slotptr, l_name, &idx)) |
436 | break; | 436 | break; |
437 | } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); | 437 | } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); |
438 | 438 | ||
439 | l_name[idx] = '\0'; | 439 | l_name[idx] = '\0'; |
440 | if (*l_name == DELETED_FLAG) | 440 | if (*l_name == DELETED_FLAG) |
441 | *l_name = '\0'; | 441 | *l_name = '\0'; |
442 | else if (*l_name == aRING) | 442 | else if (*l_name == aRING) |
443 | *l_name = DELETED_FLAG; | 443 | *l_name = DELETED_FLAG; |
444 | downcase(l_name); | 444 | downcase(l_name); |
445 | 445 | ||
446 | /* Return the real directory entry */ | 446 | /* Return the real directory entry */ |
447 | *retdent = realdent; | 447 | *retdent = realdent; |
448 | 448 | ||
449 | if (slotptr2) { | 449 | if (slotptr2) { |
450 | memcpy(get_dentfromdir_block, get_contents_vfatname_block, | 450 | memcpy(get_dentfromdir_block, get_contents_vfatname_block, |
451 | mydata->clust_size * mydata->sect_size); | 451 | mydata->clust_size * mydata->sect_size); |
452 | cur_position = (__u8 *)realdent - get_contents_vfatname_block; | 452 | cur_position = (__u8 *)realdent - get_contents_vfatname_block; |
453 | *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; | 453 | *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; |
454 | } | 454 | } |
455 | 455 | ||
456 | return 0; | 456 | return 0; |
457 | } | 457 | } |
458 | 458 | ||
459 | /* | 459 | /* |
460 | * Set the entry at index 'entry' in a FAT (16/32) table. | 460 | * Set the entry at index 'entry' in a FAT (16/32) table. |
461 | */ | 461 | */ |
462 | static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) | 462 | static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value) |
463 | { | 463 | { |
464 | __u32 bufnum, offset; | 464 | __u32 bufnum, offset; |
465 | 465 | ||
466 | switch (mydata->fatsize) { | 466 | switch (mydata->fatsize) { |
467 | case 32: | 467 | case 32: |
468 | bufnum = entry / FAT32BUFSIZE; | 468 | bufnum = entry / FAT32BUFSIZE; |
469 | offset = entry - bufnum * FAT32BUFSIZE; | 469 | offset = entry - bufnum * FAT32BUFSIZE; |
470 | break; | 470 | break; |
471 | case 16: | 471 | case 16: |
472 | bufnum = entry / FAT16BUFSIZE; | 472 | bufnum = entry / FAT16BUFSIZE; |
473 | offset = entry - bufnum * FAT16BUFSIZE; | 473 | offset = entry - bufnum * FAT16BUFSIZE; |
474 | break; | 474 | break; |
475 | default: | 475 | default: |
476 | /* Unsupported FAT size */ | 476 | /* Unsupported FAT size */ |
477 | return -1; | 477 | return -1; |
478 | } | 478 | } |
479 | 479 | ||
480 | /* Read a new block of FAT entries into the cache. */ | 480 | /* Read a new block of FAT entries into the cache. */ |
481 | if (bufnum != mydata->fatbufnum) { | 481 | if (bufnum != mydata->fatbufnum) { |
482 | int getsize = FATBUFBLOCKS; | 482 | int getsize = FATBUFBLOCKS; |
483 | __u8 *bufptr = mydata->fatbuf; | 483 | __u8 *bufptr = mydata->fatbuf; |
484 | __u32 fatlength = mydata->fatlength; | 484 | __u32 fatlength = mydata->fatlength; |
485 | __u32 startblock = bufnum * FATBUFBLOCKS; | 485 | __u32 startblock = bufnum * FATBUFBLOCKS; |
486 | 486 | ||
487 | fatlength *= mydata->sect_size; | 487 | fatlength *= mydata->sect_size; |
488 | startblock += mydata->fat_sect; | 488 | startblock += mydata->fat_sect; |
489 | 489 | ||
490 | if (getsize > fatlength) | 490 | if (getsize > fatlength) |
491 | getsize = fatlength; | 491 | getsize = fatlength; |
492 | 492 | ||
493 | if (mydata->fatbufnum != -1) { | 493 | if (mydata->fatbufnum != -1) { |
494 | if (flush_fat_buffer(mydata) < 0) | 494 | if (flush_fat_buffer(mydata) < 0) |
495 | return -1; | 495 | return -1; |
496 | } | 496 | } |
497 | 497 | ||
498 | if (disk_read(startblock, getsize, bufptr) < 0) { | 498 | if (disk_read(startblock, getsize, bufptr) < 0) { |
499 | debug("Error reading FAT blocks\n"); | 499 | debug("Error reading FAT blocks\n"); |
500 | return -1; | 500 | return -1; |
501 | } | 501 | } |
502 | mydata->fatbufnum = bufnum; | 502 | mydata->fatbufnum = bufnum; |
503 | } | 503 | } |
504 | 504 | ||
505 | /* Set the actual entry */ | 505 | /* Set the actual entry */ |
506 | switch (mydata->fatsize) { | 506 | switch (mydata->fatsize) { |
507 | case 32: | 507 | case 32: |
508 | ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value); | 508 | ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value); |
509 | break; | 509 | break; |
510 | case 16: | 510 | case 16: |
511 | ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value); | 511 | ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value); |
512 | break; | 512 | break; |
513 | default: | 513 | default: |
514 | return -1; | 514 | return -1; |
515 | } | 515 | } |
516 | 516 | ||
517 | return 0; | 517 | return 0; |
518 | } | 518 | } |
519 | 519 | ||
520 | /* | 520 | /* |
521 | * Determine the entry value at index 'entry' in a FAT (16/32) table | 521 | * Determine the entry value at index 'entry' in a FAT (16/32) table |
522 | */ | 522 | */ |
523 | static __u32 determine_fatent(fsdata *mydata, __u32 entry) | 523 | static __u32 determine_fatent(fsdata *mydata, __u32 entry) |
524 | { | 524 | { |
525 | __u32 next_fat, next_entry = entry + 1; | 525 | __u32 next_fat, next_entry = entry + 1; |
526 | 526 | ||
527 | while (1) { | 527 | while (1) { |
528 | next_fat = get_fatent_value(mydata, next_entry); | 528 | next_fat = get_fatent_value(mydata, next_entry); |
529 | if (next_fat == 0) { | 529 | if (next_fat == 0) { |
530 | set_fatent_value(mydata, entry, next_entry); | 530 | set_fatent_value(mydata, entry, next_entry); |
531 | break; | 531 | break; |
532 | } | 532 | } |
533 | next_entry++; | 533 | next_entry++; |
534 | } | 534 | } |
535 | debug("FAT%d: entry: %08x, entry_value: %04x\n", | 535 | debug("FAT%d: entry: %08x, entry_value: %04x\n", |
536 | mydata->fatsize, entry, next_entry); | 536 | mydata->fatsize, entry, next_entry); |
537 | 537 | ||
538 | return next_entry; | 538 | return next_entry; |
539 | } | 539 | } |
540 | 540 | ||
541 | /* | 541 | /* |
542 | * Write at most 'size' bytes from 'buffer' into the specified cluster. | 542 | * Write at most 'size' bytes from 'buffer' into the specified cluster. |
543 | * Return 0 on success, -1 otherwise. | 543 | * Return 0 on success, -1 otherwise. |
544 | */ | 544 | */ |
545 | static int | 545 | static int |
546 | set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, | 546 | set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, |
547 | unsigned long size) | 547 | unsigned long size) |
548 | { | 548 | { |
549 | int idx = 0; | 549 | int idx = 0; |
550 | __u32 startsect; | 550 | __u32 startsect; |
551 | 551 | ||
552 | if (clustnum > 0) | 552 | if (clustnum > 0) |
553 | startsect = mydata->data_begin + | 553 | startsect = mydata->data_begin + |
554 | clustnum * mydata->clust_size; | 554 | clustnum * mydata->clust_size; |
555 | else | 555 | else |
556 | startsect = mydata->rootdir_sect; | 556 | startsect = mydata->rootdir_sect; |
557 | 557 | ||
558 | debug("clustnum: %d, startsect: %d\n", clustnum, startsect); | 558 | debug("clustnum: %d, startsect: %d\n", clustnum, startsect); |
559 | 559 | ||
560 | if ((size / mydata->sect_size) > 0) { | 560 | if ((size / mydata->sect_size) > 0) { |
561 | if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { | 561 | if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { |
562 | debug("Error writing data\n"); | 562 | debug("Error writing data\n"); |
563 | return -1; | 563 | return -1; |
564 | } | 564 | } |
565 | } | 565 | } |
566 | 566 | ||
567 | if (size % mydata->sect_size) { | 567 | if (size % mydata->sect_size) { |
568 | __u8 tmpbuf[mydata->sect_size]; | 568 | __u8 tmpbuf[mydata->sect_size]; |
569 | 569 | ||
570 | idx = size / mydata->sect_size; | 570 | idx = size / mydata->sect_size; |
571 | buffer += idx * mydata->sect_size; | 571 | buffer += idx * mydata->sect_size; |
572 | memcpy(tmpbuf, buffer, size % mydata->sect_size); | 572 | memcpy(tmpbuf, buffer, size % mydata->sect_size); |
573 | 573 | ||
574 | if (disk_write(startsect + idx, 1, tmpbuf) < 0) { | 574 | if (disk_write(startsect + idx, 1, tmpbuf) < 0) { |
575 | debug("Error writing data\n"); | 575 | debug("Error writing data\n"); |
576 | return -1; | 576 | return -1; |
577 | } | 577 | } |
578 | 578 | ||
579 | return 0; | 579 | return 0; |
580 | } | 580 | } |
581 | 581 | ||
582 | return 0; | 582 | return 0; |
583 | } | 583 | } |
584 | 584 | ||
585 | /* | 585 | /* |
586 | * Find the first empty cluster | 586 | * Find the first empty cluster |
587 | */ | 587 | */ |
588 | static int find_empty_cluster(fsdata *mydata) | 588 | static int find_empty_cluster(fsdata *mydata) |
589 | { | 589 | { |
590 | __u32 fat_val, entry = 3; | 590 | __u32 fat_val, entry = 3; |
591 | 591 | ||
592 | while (1) { | 592 | while (1) { |
593 | fat_val = get_fatent_value(mydata, entry); | 593 | fat_val = get_fatent_value(mydata, entry); |
594 | if (fat_val == 0) | 594 | if (fat_val == 0) |
595 | break; | 595 | break; |
596 | entry++; | 596 | entry++; |
597 | } | 597 | } |
598 | 598 | ||
599 | return entry; | 599 | return entry; |
600 | } | 600 | } |
601 | 601 | ||
602 | /* | 602 | /* |
603 | * Write directory entries in 'get_dentfromdir_block' to block device | 603 | * Write directory entries in 'get_dentfromdir_block' to block device |
604 | */ | 604 | */ |
605 | static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) | 605 | static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) |
606 | { | 606 | { |
607 | int dir_newclust = 0; | 607 | int dir_newclust = 0; |
608 | 608 | ||
609 | if (set_cluster(mydata, dir_curclust, | 609 | if (set_cluster(mydata, dir_curclust, |
610 | get_dentfromdir_block, | 610 | get_dentfromdir_block, |
611 | mydata->clust_size * mydata->sect_size) != 0) { | 611 | mydata->clust_size * mydata->sect_size) != 0) { |
612 | printf("error: wrinting directory entry\n"); | 612 | printf("error: wrinting directory entry\n"); |
613 | return; | 613 | return; |
614 | } | 614 | } |
615 | dir_newclust = find_empty_cluster(mydata); | 615 | dir_newclust = find_empty_cluster(mydata); |
616 | set_fatent_value(mydata, dir_curclust, dir_newclust); | 616 | set_fatent_value(mydata, dir_curclust, dir_newclust); |
617 | if (mydata->fatsize == 32) | 617 | if (mydata->fatsize == 32) |
618 | set_fatent_value(mydata, dir_newclust, 0xffffff8); | 618 | set_fatent_value(mydata, dir_newclust, 0xffffff8); |
619 | else if (mydata->fatsize == 16) | 619 | else if (mydata->fatsize == 16) |
620 | set_fatent_value(mydata, dir_newclust, 0xfff8); | 620 | set_fatent_value(mydata, dir_newclust, 0xfff8); |
621 | 621 | ||
622 | dir_curclust = dir_newclust; | 622 | dir_curclust = dir_newclust; |
623 | 623 | ||
624 | if (flush_fat_buffer(mydata) < 0) | 624 | if (flush_fat_buffer(mydata) < 0) |
625 | return; | 625 | return; |
626 | 626 | ||
627 | memset(get_dentfromdir_block, 0x00, | 627 | memset(get_dentfromdir_block, 0x00, |
628 | mydata->clust_size * mydata->sect_size); | 628 | mydata->clust_size * mydata->sect_size); |
629 | 629 | ||
630 | *dentptr = (dir_entry *) get_dentfromdir_block; | 630 | *dentptr = (dir_entry *) get_dentfromdir_block; |
631 | } | 631 | } |
632 | 632 | ||
633 | /* | 633 | /* |
634 | * Set empty cluster from 'entry' to the end of a file | 634 | * Set empty cluster from 'entry' to the end of a file |
635 | */ | 635 | */ |
636 | static int clear_fatent(fsdata *mydata, __u32 entry) | 636 | static int clear_fatent(fsdata *mydata, __u32 entry) |
637 | { | 637 | { |
638 | __u32 fat_val; | 638 | __u32 fat_val; |
639 | 639 | ||
640 | while (1) { | 640 | while (1) { |
641 | fat_val = get_fatent_value(mydata, entry); | 641 | fat_val = get_fatent_value(mydata, entry); |
642 | if (fat_val != 0) | 642 | if (fat_val != 0) |
643 | set_fatent_value(mydata, entry, 0); | 643 | set_fatent_value(mydata, entry, 0); |
644 | else | 644 | else |
645 | break; | 645 | break; |
646 | 646 | ||
647 | if (fat_val == 0xfffffff || fat_val == 0xffff) | 647 | if (fat_val == 0xfffffff || fat_val == 0xffff) |
648 | break; | 648 | break; |
649 | 649 | ||
650 | entry = fat_val; | 650 | entry = fat_val; |
651 | } | 651 | } |
652 | 652 | ||
653 | /* Flush fat buffer */ | 653 | /* Flush fat buffer */ |
654 | if (flush_fat_buffer(mydata) < 0) | 654 | if (flush_fat_buffer(mydata) < 0) |
655 | return -1; | 655 | return -1; |
656 | 656 | ||
657 | return 0; | 657 | return 0; |
658 | } | 658 | } |
659 | 659 | ||
660 | /* | 660 | /* |
661 | * Write at most 'maxsize' bytes from 'buffer' into | 661 | * Write at most 'maxsize' bytes from 'buffer' into |
662 | * the file associated with 'dentptr' | 662 | * the file associated with 'dentptr' |
663 | * Return the number of bytes read or -1 on fatal errors. | 663 | * Update the number of bytes written in *gotsize and return 0 |
664 | * or return -1 on fatal errors. | ||
664 | */ | 665 | */ |
665 | static int | 666 | static int |
666 | set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, | 667 | set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, |
667 | unsigned long maxsize) | 668 | loff_t maxsize, loff_t *gotsize) |
668 | { | 669 | { |
669 | unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; | 670 | loff_t filesize = FAT2CPU32(dentptr->size); |
670 | unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | 671 | unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; |
671 | __u32 curclust = START(dentptr); | 672 | __u32 curclust = START(dentptr); |
672 | __u32 endclust = 0, newclust = 0; | 673 | __u32 endclust = 0, newclust = 0; |
673 | unsigned long actsize; | 674 | loff_t actsize; |
674 | 675 | ||
675 | debug("Filesize: %ld bytes\n", filesize); | 676 | *gotsize = 0; |
677 | debug("Filesize: %llu bytes\n", filesize); | ||
676 | 678 | ||
677 | if (maxsize > 0 && filesize > maxsize) | 679 | if (maxsize > 0 && filesize > maxsize) |
678 | filesize = maxsize; | 680 | filesize = maxsize; |
679 | 681 | ||
680 | debug("%ld bytes\n", filesize); | 682 | debug("%llu bytes\n", filesize); |
681 | 683 | ||
682 | actsize = bytesperclust; | 684 | actsize = bytesperclust; |
683 | endclust = curclust; | 685 | endclust = curclust; |
684 | do { | 686 | do { |
685 | /* search for consecutive clusters */ | 687 | /* search for consecutive clusters */ |
686 | while (actsize < filesize) { | 688 | while (actsize < filesize) { |
687 | newclust = determine_fatent(mydata, endclust); | 689 | newclust = determine_fatent(mydata, endclust); |
688 | 690 | ||
689 | if ((newclust - 1) != endclust) | 691 | if ((newclust - 1) != endclust) |
690 | goto getit; | 692 | goto getit; |
691 | 693 | ||
692 | if (CHECK_CLUST(newclust, mydata->fatsize)) { | 694 | if (CHECK_CLUST(newclust, mydata->fatsize)) { |
693 | debug("curclust: 0x%x\n", newclust); | 695 | debug("curclust: 0x%x\n", newclust); |
694 | debug("Invalid FAT entry\n"); | 696 | debug("Invalid FAT entry\n"); |
695 | return gotsize; | 697 | return 0; |
696 | } | 698 | } |
697 | endclust = newclust; | 699 | endclust = newclust; |
698 | actsize += bytesperclust; | 700 | actsize += bytesperclust; |
699 | } | 701 | } |
700 | /* actsize >= file size */ | 702 | /* actsize >= file size */ |
701 | actsize -= bytesperclust; | 703 | actsize -= bytesperclust; |
702 | /* set remaining clusters */ | 704 | /* set remaining clusters */ |
703 | if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { | 705 | if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
704 | debug("error: writing cluster\n"); | 706 | debug("error: writing cluster\n"); |
705 | return -1; | 707 | return -1; |
706 | } | 708 | } |
707 | 709 | ||
708 | /* set remaining bytes */ | 710 | /* set remaining bytes */ |
709 | gotsize += (int)actsize; | 711 | *gotsize += actsize; |
710 | filesize -= actsize; | 712 | filesize -= actsize; |
711 | buffer += actsize; | 713 | buffer += actsize; |
712 | actsize = filesize; | 714 | actsize = filesize; |
713 | 715 | ||
714 | if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { | 716 | if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { |
715 | debug("error: writing cluster\n"); | 717 | debug("error: writing cluster\n"); |
716 | return -1; | 718 | return -1; |
717 | } | 719 | } |
718 | gotsize += actsize; | 720 | *gotsize += actsize; |
719 | 721 | ||
720 | /* Mark end of file in FAT */ | 722 | /* Mark end of file in FAT */ |
721 | if (mydata->fatsize == 16) | 723 | if (mydata->fatsize == 16) |
722 | newclust = 0xffff; | 724 | newclust = 0xffff; |
723 | else if (mydata->fatsize == 32) | 725 | else if (mydata->fatsize == 32) |
724 | newclust = 0xfffffff; | 726 | newclust = 0xfffffff; |
725 | set_fatent_value(mydata, endclust, newclust); | 727 | set_fatent_value(mydata, endclust, newclust); |
726 | 728 | ||
727 | return gotsize; | 729 | return 0; |
728 | getit: | 730 | getit: |
729 | if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { | 731 | if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
730 | debug("error: writing cluster\n"); | 732 | debug("error: writing cluster\n"); |
731 | return -1; | 733 | return -1; |
732 | } | 734 | } |
733 | gotsize += (int)actsize; | 735 | *gotsize += actsize; |
734 | filesize -= actsize; | 736 | filesize -= actsize; |
735 | buffer += actsize; | 737 | buffer += actsize; |
736 | 738 | ||
737 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 739 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
738 | debug("curclust: 0x%x\n", curclust); | 740 | debug("curclust: 0x%x\n", curclust); |
739 | debug("Invalid FAT entry\n"); | 741 | debug("Invalid FAT entry\n"); |
740 | return gotsize; | 742 | return 0; |
741 | } | 743 | } |
742 | actsize = bytesperclust; | 744 | actsize = bytesperclust; |
743 | curclust = endclust = newclust; | 745 | curclust = endclust = newclust; |
744 | } while (1); | 746 | } while (1); |
745 | } | 747 | } |
746 | 748 | ||
747 | /* | 749 | /* |
748 | * Fill dir_entry | 750 | * Fill dir_entry |
749 | */ | 751 | */ |
750 | static void fill_dentry(fsdata *mydata, dir_entry *dentptr, | 752 | static void fill_dentry(fsdata *mydata, dir_entry *dentptr, |
751 | const char *filename, __u32 start_cluster, __u32 size, __u8 attr) | 753 | const char *filename, __u32 start_cluster, __u32 size, __u8 attr) |
752 | { | 754 | { |
753 | if (mydata->fatsize == 32) | 755 | if (mydata->fatsize == 32) |
754 | dentptr->starthi = | 756 | dentptr->starthi = |
755 | cpu_to_le16((start_cluster & 0xffff0000) >> 16); | 757 | cpu_to_le16((start_cluster & 0xffff0000) >> 16); |
756 | dentptr->start = cpu_to_le16(start_cluster & 0xffff); | 758 | dentptr->start = cpu_to_le16(start_cluster & 0xffff); |
757 | dentptr->size = cpu_to_le32(size); | 759 | dentptr->size = cpu_to_le32(size); |
758 | 760 | ||
759 | dentptr->attr = attr; | 761 | dentptr->attr = attr; |
760 | 762 | ||
761 | set_name(dentptr, filename); | 763 | set_name(dentptr, filename); |
762 | } | 764 | } |
763 | 765 | ||
764 | /* | 766 | /* |
765 | * Check whether adding a file makes the file system to | 767 | * Check whether adding a file makes the file system to |
766 | * exceed the size of the block device | 768 | * exceed the size of the block device |
767 | * Return -1 when overflow occurs, otherwise return 0 | 769 | * Return -1 when overflow occurs, otherwise return 0 |
768 | */ | 770 | */ |
769 | static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size) | 771 | static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) |
770 | { | 772 | { |
771 | __u32 startsect, sect_num; | 773 | __u32 startsect, sect_num; |
772 | 774 | ||
773 | if (clustnum > 0) { | 775 | if (clustnum > 0) { |
774 | startsect = mydata->data_begin + | 776 | startsect = mydata->data_begin + |
775 | clustnum * mydata->clust_size; | 777 | clustnum * mydata->clust_size; |
776 | } else { | 778 | } else { |
777 | startsect = mydata->rootdir_sect; | 779 | startsect = mydata->rootdir_sect; |
778 | } | 780 | } |
779 | 781 | ||
780 | sect_num = size / mydata->sect_size; | 782 | sect_num = size / mydata->sect_size; |
781 | if (size % mydata->sect_size) | 783 | if (size % mydata->sect_size) |
782 | sect_num++; | 784 | sect_num++; |
783 | 785 | ||
784 | if (startsect + sect_num > cur_part_info.start + total_sector) | 786 | if (startsect + sect_num > cur_part_info.start + total_sector) |
785 | return -1; | 787 | return -1; |
786 | 788 | ||
787 | return 0; | 789 | return 0; |
788 | } | 790 | } |
789 | 791 | ||
790 | /* | 792 | /* |
791 | * Check if adding several entries exceed one cluster boundary | 793 | * Check if adding several entries exceed one cluster boundary |
792 | */ | 794 | */ |
793 | static int is_next_clust(fsdata *mydata, dir_entry *dentptr) | 795 | static int is_next_clust(fsdata *mydata, dir_entry *dentptr) |
794 | { | 796 | { |
795 | int cur_position; | 797 | int cur_position; |
796 | 798 | ||
797 | cur_position = (__u8 *)dentptr - get_dentfromdir_block; | 799 | cur_position = (__u8 *)dentptr - get_dentfromdir_block; |
798 | 800 | ||
799 | if (cur_position >= mydata->clust_size * mydata->sect_size) | 801 | if (cur_position >= mydata->clust_size * mydata->sect_size) |
800 | return 1; | 802 | return 1; |
801 | else | 803 | else |
802 | return 0; | 804 | return 0; |
803 | } | 805 | } |
804 | 806 | ||
805 | static dir_entry *empty_dentptr; | 807 | static dir_entry *empty_dentptr; |
806 | /* | 808 | /* |
807 | * Find a directory entry based on filename or start cluster number | 809 | * Find a directory entry based on filename or start cluster number |
808 | * If the directory entry is not found, | 810 | * If the directory entry is not found, |
809 | * the new position for writing a directory entry will be returned | 811 | * the new position for writing a directory entry will be returned |
810 | */ | 812 | */ |
811 | static dir_entry *find_directory_entry(fsdata *mydata, int startsect, | 813 | static dir_entry *find_directory_entry(fsdata *mydata, int startsect, |
812 | char *filename, dir_entry *retdent, __u32 start) | 814 | char *filename, dir_entry *retdent, __u32 start) |
813 | { | 815 | { |
814 | __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; | 816 | __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; |
815 | 817 | ||
816 | debug("get_dentfromdir: %s\n", filename); | 818 | debug("get_dentfromdir: %s\n", filename); |
817 | 819 | ||
818 | while (1) { | 820 | while (1) { |
819 | dir_entry *dentptr; | 821 | dir_entry *dentptr; |
820 | 822 | ||
821 | int i; | 823 | int i; |
822 | 824 | ||
823 | if (get_cluster(mydata, curclust, get_dentfromdir_block, | 825 | if (get_cluster(mydata, curclust, get_dentfromdir_block, |
824 | mydata->clust_size * mydata->sect_size) != 0) { | 826 | mydata->clust_size * mydata->sect_size) != 0) { |
825 | printf("Error: reading directory block\n"); | 827 | printf("Error: reading directory block\n"); |
826 | return NULL; | 828 | return NULL; |
827 | } | 829 | } |
828 | 830 | ||
829 | dentptr = (dir_entry *)get_dentfromdir_block; | 831 | dentptr = (dir_entry *)get_dentfromdir_block; |
830 | 832 | ||
831 | dir_curclust = curclust; | 833 | dir_curclust = curclust; |
832 | 834 | ||
833 | for (i = 0; i < DIRENTSPERCLUST; i++) { | 835 | for (i = 0; i < DIRENTSPERCLUST; i++) { |
834 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; | 836 | char s_name[14], l_name[VFAT_MAXLEN_BYTES]; |
835 | 837 | ||
836 | l_name[0] = '\0'; | 838 | l_name[0] = '\0'; |
837 | if (dentptr->name[0] == DELETED_FLAG) { | 839 | if (dentptr->name[0] == DELETED_FLAG) { |
838 | dentptr++; | 840 | dentptr++; |
839 | if (is_next_clust(mydata, dentptr)) | 841 | if (is_next_clust(mydata, dentptr)) |
840 | break; | 842 | break; |
841 | continue; | 843 | continue; |
842 | } | 844 | } |
843 | if ((dentptr->attr & ATTR_VOLUME)) { | 845 | if ((dentptr->attr & ATTR_VOLUME)) { |
844 | if (vfat_enabled && | 846 | if (vfat_enabled && |
845 | (dentptr->attr & ATTR_VFAT) && | 847 | (dentptr->attr & ATTR_VFAT) && |
846 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { | 848 | (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { |
847 | get_long_file_name(mydata, curclust, | 849 | get_long_file_name(mydata, curclust, |
848 | get_dentfromdir_block, | 850 | get_dentfromdir_block, |
849 | &dentptr, l_name); | 851 | &dentptr, l_name); |
850 | debug("vfatname: |%s|\n", l_name); | 852 | debug("vfatname: |%s|\n", l_name); |
851 | } else { | 853 | } else { |
852 | /* Volume label or VFAT entry */ | 854 | /* Volume label or VFAT entry */ |
853 | dentptr++; | 855 | dentptr++; |
854 | if (is_next_clust(mydata, dentptr)) | 856 | if (is_next_clust(mydata, dentptr)) |
855 | break; | 857 | break; |
856 | continue; | 858 | continue; |
857 | } | 859 | } |
858 | } | 860 | } |
859 | if (dentptr->name[0] == 0) { | 861 | if (dentptr->name[0] == 0) { |
860 | debug("Dentname == NULL - %d\n", i); | 862 | debug("Dentname == NULL - %d\n", i); |
861 | empty_dentptr = dentptr; | 863 | empty_dentptr = dentptr; |
862 | return NULL; | 864 | return NULL; |
863 | } | 865 | } |
864 | 866 | ||
865 | get_name(dentptr, s_name); | 867 | get_name(dentptr, s_name); |
866 | 868 | ||
867 | if (strcmp(filename, s_name) | 869 | if (strcmp(filename, s_name) |
868 | && strcmp(filename, l_name)) { | 870 | && strcmp(filename, l_name)) { |
869 | debug("Mismatch: |%s|%s|\n", | 871 | debug("Mismatch: |%s|%s|\n", |
870 | s_name, l_name); | 872 | s_name, l_name); |
871 | dentptr++; | 873 | dentptr++; |
872 | if (is_next_clust(mydata, dentptr)) | 874 | if (is_next_clust(mydata, dentptr)) |
873 | break; | 875 | break; |
874 | continue; | 876 | continue; |
875 | } | 877 | } |
876 | 878 | ||
877 | memcpy(retdent, dentptr, sizeof(dir_entry)); | 879 | memcpy(retdent, dentptr, sizeof(dir_entry)); |
878 | 880 | ||
879 | debug("DentName: %s", s_name); | 881 | debug("DentName: %s", s_name); |
880 | debug(", start: 0x%x", START(dentptr)); | 882 | debug(", start: 0x%x", START(dentptr)); |
881 | debug(", size: 0x%x %s\n", | 883 | debug(", size: 0x%x %s\n", |
882 | FAT2CPU32(dentptr->size), | 884 | FAT2CPU32(dentptr->size), |
883 | (dentptr->attr & ATTR_DIR) ? | 885 | (dentptr->attr & ATTR_DIR) ? |
884 | "(DIR)" : ""); | 886 | "(DIR)" : ""); |
885 | 887 | ||
886 | return dentptr; | 888 | return dentptr; |
887 | } | 889 | } |
888 | 890 | ||
889 | /* | 891 | /* |
890 | * In FAT16/12, the root dir is locate before data area, shows | 892 | * In FAT16/12, the root dir is locate before data area, shows |
891 | * in following: | 893 | * in following: |
892 | * ------------------------------------------------------------- | 894 | * ------------------------------------------------------------- |
893 | * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | | 895 | * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | |
894 | * ------------------------------------------------------------- | 896 | * ------------------------------------------------------------- |
895 | * | 897 | * |
896 | * As a result if curclust is in Root dir, it is a negative | 898 | * As a result if curclust is in Root dir, it is a negative |
897 | * number or 0, 1. | 899 | * number or 0, 1. |
898 | * | 900 | * |
899 | */ | 901 | */ |
900 | if (mydata->fatsize != 32 && (int)curclust <= 1) { | 902 | if (mydata->fatsize != 32 && (int)curclust <= 1) { |
901 | /* Current clust is in root dir, set to next clust */ | 903 | /* Current clust is in root dir, set to next clust */ |
902 | curclust++; | 904 | curclust++; |
903 | if ((int)curclust <= 1) | 905 | if ((int)curclust <= 1) |
904 | continue; /* continue to find */ | 906 | continue; /* continue to find */ |
905 | 907 | ||
906 | /* Reach the end of root dir */ | 908 | /* Reach the end of root dir */ |
907 | empty_dentptr = dentptr; | 909 | empty_dentptr = dentptr; |
908 | return NULL; | 910 | return NULL; |
909 | } | 911 | } |
910 | 912 | ||
911 | curclust = get_fatent_value(mydata, dir_curclust); | 913 | curclust = get_fatent_value(mydata, dir_curclust); |
912 | if (IS_LAST_CLUST(curclust, mydata->fatsize)) { | 914 | if (IS_LAST_CLUST(curclust, mydata->fatsize)) { |
913 | empty_dentptr = dentptr; | 915 | empty_dentptr = dentptr; |
914 | return NULL; | 916 | return NULL; |
915 | } | 917 | } |
916 | if (CHECK_CLUST(curclust, mydata->fatsize)) { | 918 | if (CHECK_CLUST(curclust, mydata->fatsize)) { |
917 | debug("curclust: 0x%x\n", curclust); | 919 | debug("curclust: 0x%x\n", curclust); |
918 | debug("Invalid FAT entry\n"); | 920 | debug("Invalid FAT entry\n"); |
919 | return NULL; | 921 | return NULL; |
920 | } | 922 | } |
921 | } | 923 | } |
922 | 924 | ||
923 | return NULL; | 925 | return NULL; |
924 | } | 926 | } |
925 | 927 | ||
926 | static int do_fat_write(const char *filename, void *buffer, | 928 | static int do_fat_write(const char *filename, void *buffer, loff_t size, |
927 | unsigned long size) | 929 | loff_t *actwrite) |
928 | { | 930 | { |
929 | dir_entry *dentptr, *retdent; | 931 | dir_entry *dentptr, *retdent; |
930 | __u32 startsect; | 932 | __u32 startsect; |
931 | __u32 start_cluster; | 933 | __u32 start_cluster; |
932 | boot_sector bs; | 934 | boot_sector bs; |
933 | volume_info volinfo; | 935 | volume_info volinfo; |
934 | fsdata datablock; | 936 | fsdata datablock; |
935 | fsdata *mydata = &datablock; | 937 | fsdata *mydata = &datablock; |
936 | int cursect; | 938 | int cursect; |
937 | int ret = -1, name_len; | 939 | int ret = -1, name_len; |
938 | char l_filename[VFAT_MAXLEN_BYTES]; | 940 | char l_filename[VFAT_MAXLEN_BYTES]; |
939 | int write_size = size; | ||
940 | 941 | ||
942 | *actwrite = size; | ||
941 | dir_curclust = 0; | 943 | dir_curclust = 0; |
942 | 944 | ||
943 | if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { | 945 | if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { |
944 | debug("error: reading boot sector\n"); | 946 | debug("error: reading boot sector\n"); |
945 | return -1; | 947 | return -1; |
946 | } | 948 | } |
947 | 949 | ||
948 | total_sector = bs.total_sect; | 950 | total_sector = bs.total_sect; |
949 | if (total_sector == 0) | 951 | if (total_sector == 0) |
950 | total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ | 952 | total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ |
951 | 953 | ||
952 | if (mydata->fatsize == 32) | 954 | if (mydata->fatsize == 32) |
953 | mydata->fatlength = bs.fat32_length; | 955 | mydata->fatlength = bs.fat32_length; |
954 | else | 956 | else |
955 | mydata->fatlength = bs.fat_length; | 957 | mydata->fatlength = bs.fat_length; |
956 | 958 | ||
957 | mydata->fat_sect = bs.reserved; | 959 | mydata->fat_sect = bs.reserved; |
958 | 960 | ||
959 | cursect = mydata->rootdir_sect | 961 | cursect = mydata->rootdir_sect |
960 | = mydata->fat_sect + mydata->fatlength * bs.fats; | 962 | = mydata->fat_sect + mydata->fatlength * bs.fats; |
961 | num_of_fats = bs.fats; | 963 | num_of_fats = bs.fats; |
962 | 964 | ||
963 | mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; | 965 | mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; |
964 | mydata->clust_size = bs.cluster_size; | 966 | mydata->clust_size = bs.cluster_size; |
965 | 967 | ||
966 | if (mydata->fatsize == 32) { | 968 | if (mydata->fatsize == 32) { |
967 | mydata->data_begin = mydata->rootdir_sect - | 969 | mydata->data_begin = mydata->rootdir_sect - |
968 | (mydata->clust_size * 2); | 970 | (mydata->clust_size * 2); |
969 | } else { | 971 | } else { |
970 | int rootdir_size; | 972 | int rootdir_size; |
971 | 973 | ||
972 | rootdir_size = ((bs.dir_entries[1] * (int)256 + | 974 | rootdir_size = ((bs.dir_entries[1] * (int)256 + |
973 | bs.dir_entries[0]) * | 975 | bs.dir_entries[0]) * |
974 | sizeof(dir_entry)) / | 976 | sizeof(dir_entry)) / |
975 | mydata->sect_size; | 977 | mydata->sect_size; |
976 | mydata->data_begin = mydata->rootdir_sect + | 978 | mydata->data_begin = mydata->rootdir_sect + |
977 | rootdir_size - | 979 | rootdir_size - |
978 | (mydata->clust_size * 2); | 980 | (mydata->clust_size * 2); |
979 | } | 981 | } |
980 | 982 | ||
981 | mydata->fatbufnum = -1; | 983 | mydata->fatbufnum = -1; |
982 | mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); | 984 | mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); |
983 | if (mydata->fatbuf == NULL) { | 985 | if (mydata->fatbuf == NULL) { |
984 | debug("Error: allocating memory\n"); | 986 | debug("Error: allocating memory\n"); |
985 | return -1; | 987 | return -1; |
986 | } | 988 | } |
987 | 989 | ||
988 | if (disk_read(cursect, | 990 | if (disk_read(cursect, |
989 | (mydata->fatsize == 32) ? | 991 | (mydata->fatsize == 32) ? |
990 | (mydata->clust_size) : | 992 | (mydata->clust_size) : |
991 | PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { | 993 | PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { |
992 | debug("Error: reading rootdir block\n"); | 994 | debug("Error: reading rootdir block\n"); |
993 | goto exit; | 995 | goto exit; |
994 | } | 996 | } |
995 | dentptr = (dir_entry *) do_fat_read_at_block; | 997 | dentptr = (dir_entry *) do_fat_read_at_block; |
996 | 998 | ||
997 | name_len = strlen(filename); | 999 | name_len = strlen(filename); |
998 | if (name_len >= VFAT_MAXLEN_BYTES) | 1000 | if (name_len >= VFAT_MAXLEN_BYTES) |
999 | name_len = VFAT_MAXLEN_BYTES - 1; | 1001 | name_len = VFAT_MAXLEN_BYTES - 1; |
1000 | 1002 | ||
1001 | memcpy(l_filename, filename, name_len); | 1003 | memcpy(l_filename, filename, name_len); |
1002 | l_filename[name_len] = 0; /* terminate the string */ | 1004 | l_filename[name_len] = 0; /* terminate the string */ |
1003 | downcase(l_filename); | 1005 | downcase(l_filename); |
1004 | 1006 | ||
1005 | startsect = mydata->rootdir_sect; | 1007 | startsect = mydata->rootdir_sect; |
1006 | retdent = find_directory_entry(mydata, startsect, | 1008 | retdent = find_directory_entry(mydata, startsect, |
1007 | l_filename, dentptr, 0); | 1009 | l_filename, dentptr, 0); |
1008 | if (retdent) { | 1010 | if (retdent) { |
1009 | /* Update file size and start_cluster in a directory entry */ | 1011 | /* Update file size and start_cluster in a directory entry */ |
1010 | retdent->size = cpu_to_le32(size); | 1012 | retdent->size = cpu_to_le32(size); |
1011 | start_cluster = FAT2CPU16(retdent->start); | 1013 | start_cluster = FAT2CPU16(retdent->start); |
1012 | if (mydata->fatsize == 32) | 1014 | if (mydata->fatsize == 32) |
1013 | start_cluster |= | 1015 | start_cluster |= |
1014 | (FAT2CPU16(retdent->starthi) << 16); | 1016 | (FAT2CPU16(retdent->starthi) << 16); |
1015 | 1017 | ||
1016 | ret = check_overflow(mydata, start_cluster, size); | 1018 | ret = check_overflow(mydata, start_cluster, size); |
1017 | if (ret) { | 1019 | if (ret) { |
1018 | printf("Error: %ld overflow\n", size); | 1020 | printf("Error: %llu overflow\n", size); |
1019 | goto exit; | 1021 | goto exit; |
1020 | } | 1022 | } |
1021 | 1023 | ||
1022 | ret = clear_fatent(mydata, start_cluster); | 1024 | ret = clear_fatent(mydata, start_cluster); |
1023 | if (ret) { | 1025 | if (ret) { |
1024 | printf("Error: clearing FAT entries\n"); | 1026 | printf("Error: clearing FAT entries\n"); |
1025 | goto exit; | 1027 | goto exit; |
1026 | } | 1028 | } |
1027 | 1029 | ||
1028 | ret = set_contents(mydata, retdent, buffer, size); | 1030 | ret = set_contents(mydata, retdent, buffer, size, actwrite); |
1029 | if (ret < 0) { | 1031 | if (ret < 0) { |
1030 | printf("Error: writing contents\n"); | 1032 | printf("Error: writing contents\n"); |
1031 | goto exit; | 1033 | goto exit; |
1032 | } | 1034 | } |
1033 | write_size = ret; | 1035 | debug("attempt to write 0x%llx bytes\n", *actwrite); |
1034 | debug("attempt to write 0x%x bytes\n", write_size); | ||
1035 | 1036 | ||
1036 | /* Flush fat buffer */ | 1037 | /* Flush fat buffer */ |
1037 | ret = flush_fat_buffer(mydata); | 1038 | ret = flush_fat_buffer(mydata); |
1038 | if (ret) { | 1039 | if (ret) { |
1039 | printf("Error: flush fat buffer\n"); | 1040 | printf("Error: flush fat buffer\n"); |
1040 | goto exit; | 1041 | goto exit; |
1041 | } | 1042 | } |
1042 | 1043 | ||
1043 | /* Write directory table to device */ | 1044 | /* Write directory table to device */ |
1044 | ret = set_cluster(mydata, dir_curclust, | 1045 | ret = set_cluster(mydata, dir_curclust, |
1045 | get_dentfromdir_block, | 1046 | get_dentfromdir_block, |
1046 | mydata->clust_size * mydata->sect_size); | 1047 | mydata->clust_size * mydata->sect_size); |
1047 | if (ret) { | 1048 | if (ret) { |
1048 | printf("Error: writing directory entry\n"); | 1049 | printf("Error: writing directory entry\n"); |
1049 | goto exit; | 1050 | goto exit; |
1050 | } | 1051 | } |
1051 | } else { | 1052 | } else { |
1052 | /* Set short name to set alias checksum field in dir_slot */ | 1053 | /* Set short name to set alias checksum field in dir_slot */ |
1053 | set_name(empty_dentptr, filename); | 1054 | set_name(empty_dentptr, filename); |
1054 | fill_dir_slot(mydata, &empty_dentptr, filename); | 1055 | fill_dir_slot(mydata, &empty_dentptr, filename); |
1055 | 1056 | ||
1056 | ret = start_cluster = find_empty_cluster(mydata); | 1057 | ret = start_cluster = find_empty_cluster(mydata); |
1057 | if (ret < 0) { | 1058 | if (ret < 0) { |
1058 | printf("Error: finding empty cluster\n"); | 1059 | printf("Error: finding empty cluster\n"); |
1059 | goto exit; | 1060 | goto exit; |
1060 | } | 1061 | } |
1061 | 1062 | ||
1062 | ret = check_overflow(mydata, start_cluster, size); | 1063 | ret = check_overflow(mydata, start_cluster, size); |
1063 | if (ret) { | 1064 | if (ret) { |
1064 | printf("Error: %ld overflow\n", size); | 1065 | printf("Error: %llu overflow\n", size); |
1065 | goto exit; | 1066 | goto exit; |
1066 | } | 1067 | } |
1067 | 1068 | ||
1068 | /* Set attribute as archieve for regular file */ | 1069 | /* Set attribute as archieve for regular file */ |
1069 | fill_dentry(mydata, empty_dentptr, filename, | 1070 | fill_dentry(mydata, empty_dentptr, filename, |
1070 | start_cluster, size, 0x20); | 1071 | start_cluster, size, 0x20); |
1071 | 1072 | ||
1072 | ret = set_contents(mydata, empty_dentptr, buffer, size); | 1073 | ret = set_contents(mydata, empty_dentptr, buffer, size, |
1074 | actwrite); | ||
1073 | if (ret < 0) { | 1075 | if (ret < 0) { |
1074 | printf("Error: writing contents\n"); | 1076 | printf("Error: writing contents\n"); |
1075 | goto exit; | 1077 | goto exit; |
1076 | } | 1078 | } |
1077 | write_size = ret; | 1079 | debug("attempt to write 0x%llx bytes\n", *actwrite); |
1078 | debug("attempt to write 0x%x bytes\n", write_size); | ||
1079 | 1080 | ||
1080 | /* Flush fat buffer */ | 1081 | /* Flush fat buffer */ |
1081 | ret = flush_fat_buffer(mydata); | 1082 | ret = flush_fat_buffer(mydata); |
1082 | if (ret) { | 1083 | if (ret) { |
1083 | printf("Error: flush fat buffer\n"); | 1084 | printf("Error: flush fat buffer\n"); |
1084 | goto exit; | 1085 | goto exit; |
1085 | } | 1086 | } |
1086 | 1087 | ||
1087 | /* Write directory table to device */ | 1088 | /* Write directory table to device */ |
1088 | ret = set_cluster(mydata, dir_curclust, | 1089 | ret = set_cluster(mydata, dir_curclust, |
1089 | get_dentfromdir_block, | 1090 | get_dentfromdir_block, |
1090 | mydata->clust_size * mydata->sect_size); | 1091 | mydata->clust_size * mydata->sect_size); |
1091 | if (ret) { | 1092 | if (ret) { |
1092 | printf("Error: writing directory entry\n"); | 1093 | printf("Error: writing directory entry\n"); |
1093 | goto exit; | 1094 | goto exit; |
1094 | } | 1095 | } |
1095 | } | 1096 | } |
1096 | 1097 | ||
1097 | exit: | 1098 | exit: |
1098 | free(mydata->fatbuf); | 1099 | free(mydata->fatbuf); |
1099 | return ret < 0 ? ret : write_size; | 1100 | return ret; |
1100 | } | 1101 | } |
1101 | 1102 | ||
1102 | int file_fat_write(const char *filename, void *buffer, unsigned long maxsize) | 1103 | int file_fat_write(const char *filename, void *buffer, loff_t offset, |
1104 | loff_t maxsize, loff_t *actwrite) | ||
1103 | { | 1105 | { |
1106 | if (offset != 0) { | ||
1107 | printf("Error: non zero offset is currently not suported.\n"); | ||
1108 | return -1; | ||
1109 | } | ||
1110 | |||
1104 | printf("writing %s\n", filename); | 1111 | printf("writing %s\n", filename); |
fs/fat/file.c
1 | /* | 1 | /* |
2 | * file.c | 2 | * file.c |
3 | * | 3 | * |
4 | * Mini "VFS" by Marcus Sundberg | 4 | * Mini "VFS" by Marcus Sundberg |
5 | * | 5 | * |
6 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 | 6 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 |
7 | * 2003-03-10 - kharris@nexus-tech.net - ported to uboot | 7 | * 2003-03-10 - kharris@nexus-tech.net - ported to uboot |
8 | * | 8 | * |
9 | * SPDX-License-Identifier: GPL-2.0+ | 9 | * SPDX-License-Identifier: GPL-2.0+ |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <common.h> | 12 | #include <common.h> |
13 | #include <config.h> | 13 | #include <config.h> |
14 | #include <malloc.h> | 14 | #include <malloc.h> |
15 | #include <fat.h> | 15 | #include <fat.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/time.h> | 17 | #include <linux/time.h> |
18 | 18 | ||
19 | /* Supported filesystems */ | 19 | /* Supported filesystems */ |
20 | static const struct filesystem filesystems[] = { | 20 | static const struct filesystem filesystems[] = { |
21 | { file_fat_detectfs, file_fat_ls, file_fat_read, "FAT" }, | 21 | { file_fat_detectfs, file_fat_ls, file_fat_read, "FAT" }, |
22 | }; | 22 | }; |
23 | #define NUM_FILESYS (sizeof(filesystems)/sizeof(struct filesystem)) | 23 | #define NUM_FILESYS (sizeof(filesystems)/sizeof(struct filesystem)) |
24 | 24 | ||
25 | /* The filesystem which was last detected */ | 25 | /* The filesystem which was last detected */ |
26 | static int current_filesystem = FSTYPE_NONE; | 26 | static int current_filesystem = FSTYPE_NONE; |
27 | 27 | ||
28 | /* The current working directory */ | 28 | /* The current working directory */ |
29 | #define CWD_LEN 511 | 29 | #define CWD_LEN 511 |
30 | char file_cwd[CWD_LEN+1] = "/"; | 30 | char file_cwd[CWD_LEN+1] = "/"; |
31 | 31 | ||
32 | const char * | 32 | const char * |
33 | file_getfsname(int idx) | 33 | file_getfsname(int idx) |
34 | { | 34 | { |
35 | if (idx < 0 || idx >= NUM_FILESYS) | 35 | if (idx < 0 || idx >= NUM_FILESYS) |
36 | return NULL; | 36 | return NULL; |
37 | 37 | ||
38 | return filesystems[idx].name; | 38 | return filesystems[idx].name; |
39 | } | 39 | } |
40 | 40 | ||
41 | static void | 41 | static void |
42 | pathcpy(char *dest, const char *src) | 42 | pathcpy(char *dest, const char *src) |
43 | { | 43 | { |
44 | char *origdest = dest; | 44 | char *origdest = dest; |
45 | 45 | ||
46 | do { | 46 | do { |
47 | if (dest-file_cwd >= CWD_LEN) { | 47 | if (dest-file_cwd >= CWD_LEN) { |
48 | *dest = '\0'; | 48 | *dest = '\0'; |
49 | return; | 49 | return; |
50 | } | 50 | } |
51 | *(dest) = *(src); | 51 | *(dest) = *(src); |
52 | if (*src == '\0') { | 52 | if (*src == '\0') { |
53 | if (dest-- != origdest && ISDIRDELIM(*dest)) { | 53 | if (dest-- != origdest && ISDIRDELIM(*dest)) { |
54 | *dest = '\0'; | 54 | *dest = '\0'; |
55 | } | 55 | } |
56 | return; | 56 | return; |
57 | } | 57 | } |
58 | ++dest; | 58 | ++dest; |
59 | 59 | ||
60 | if (ISDIRDELIM(*src)) | 60 | if (ISDIRDELIM(*src)) |
61 | while (ISDIRDELIM(*src)) src++; | 61 | while (ISDIRDELIM(*src)) src++; |
62 | else | 62 | else |
63 | src++; | 63 | src++; |
64 | } while (1); | 64 | } while (1); |
65 | } | 65 | } |
66 | 66 | ||
67 | int | 67 | int |
68 | file_cd(const char *path) | 68 | file_cd(const char *path) |
69 | { | 69 | { |
70 | if (ISDIRDELIM(*path)) { | 70 | if (ISDIRDELIM(*path)) { |
71 | while (ISDIRDELIM(*path)) path++; | 71 | while (ISDIRDELIM(*path)) path++; |
72 | strncpy(file_cwd+1, path, CWD_LEN-1); | 72 | strncpy(file_cwd+1, path, CWD_LEN-1); |
73 | } else { | 73 | } else { |
74 | const char *origpath = path; | 74 | const char *origpath = path; |
75 | char *tmpstr = file_cwd; | 75 | char *tmpstr = file_cwd; |
76 | int back = 0; | 76 | int back = 0; |
77 | 77 | ||
78 | while (*tmpstr != '\0') tmpstr++; | 78 | while (*tmpstr != '\0') tmpstr++; |
79 | do { | 79 | do { |
80 | tmpstr--; | 80 | tmpstr--; |
81 | } while (ISDIRDELIM(*tmpstr)); | 81 | } while (ISDIRDELIM(*tmpstr)); |
82 | 82 | ||
83 | while (*path == '.') { | 83 | while (*path == '.') { |
84 | path++; | 84 | path++; |
85 | while (*path == '.') { | 85 | while (*path == '.') { |
86 | path++; | 86 | path++; |
87 | back++; | 87 | back++; |
88 | } | 88 | } |
89 | if (*path != '\0' && !ISDIRDELIM(*path)) { | 89 | if (*path != '\0' && !ISDIRDELIM(*path)) { |
90 | path = origpath; | 90 | path = origpath; |
91 | back = 0; | 91 | back = 0; |
92 | break; | 92 | break; |
93 | } | 93 | } |
94 | while (ISDIRDELIM(*path)) path++; | 94 | while (ISDIRDELIM(*path)) path++; |
95 | origpath = path; | 95 | origpath = path; |
96 | } | 96 | } |
97 | 97 | ||
98 | while (back--) { | 98 | while (back--) { |
99 | /* Strip off path component */ | 99 | /* Strip off path component */ |
100 | while (!ISDIRDELIM(*tmpstr)) { | 100 | while (!ISDIRDELIM(*tmpstr)) { |
101 | tmpstr--; | 101 | tmpstr--; |
102 | } | 102 | } |
103 | if (tmpstr == file_cwd) { | 103 | if (tmpstr == file_cwd) { |
104 | /* Incremented again right after the loop. */ | 104 | /* Incremented again right after the loop. */ |
105 | tmpstr--; | 105 | tmpstr--; |
106 | break; | 106 | break; |
107 | } | 107 | } |
108 | /* Skip delimiters */ | 108 | /* Skip delimiters */ |
109 | while (ISDIRDELIM(*tmpstr)) tmpstr--; | 109 | while (ISDIRDELIM(*tmpstr)) tmpstr--; |
110 | } | 110 | } |
111 | tmpstr++; | 111 | tmpstr++; |
112 | if (*path == '\0') { | 112 | if (*path == '\0') { |
113 | if (tmpstr == file_cwd) { | 113 | if (tmpstr == file_cwd) { |
114 | *tmpstr = '/'; | 114 | *tmpstr = '/'; |
115 | tmpstr++; | 115 | tmpstr++; |
116 | } | 116 | } |
117 | *tmpstr = '\0'; | 117 | *tmpstr = '\0'; |
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | *tmpstr = '/'; | 120 | *tmpstr = '/'; |
121 | pathcpy(tmpstr+1, path); | 121 | pathcpy(tmpstr+1, path); |
122 | } | 122 | } |
123 | 123 | ||
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | int | 127 | int |
128 | file_detectfs(void) | 128 | file_detectfs(void) |
129 | { | 129 | { |
130 | int i; | 130 | int i; |
131 | 131 | ||
132 | current_filesystem = FSTYPE_NONE; | 132 | current_filesystem = FSTYPE_NONE; |
133 | 133 | ||
134 | for (i = 0; i < NUM_FILESYS; i++) { | 134 | for (i = 0; i < NUM_FILESYS; i++) { |
135 | if (filesystems[i].detect() == 0) { | 135 | if (filesystems[i].detect() == 0) { |
136 | strcpy(file_cwd, "/"); | 136 | strcpy(file_cwd, "/"); |
137 | current_filesystem = i; | 137 | current_filesystem = i; |
138 | break; | 138 | break; |
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | return current_filesystem; | 142 | return current_filesystem; |
143 | } | 143 | } |
144 | 144 | ||
145 | int | 145 | int |
146 | file_ls(const char *dir) | 146 | file_ls(const char *dir) |
147 | { | 147 | { |
148 | char fullpath[1024]; | 148 | char fullpath[1024]; |
149 | const char *arg; | 149 | const char *arg; |
150 | 150 | ||
151 | if (current_filesystem == FSTYPE_NONE) { | 151 | if (current_filesystem == FSTYPE_NONE) { |
152 | printf("Can't list files without a filesystem!\n"); | 152 | printf("Can't list files without a filesystem!\n"); |
153 | return -1; | 153 | return -1; |
154 | } | 154 | } |
155 | 155 | ||
156 | if (ISDIRDELIM(*dir)) { | 156 | if (ISDIRDELIM(*dir)) { |
157 | arg = dir; | 157 | arg = dir; |
158 | } else { | 158 | } else { |
159 | sprintf(fullpath, "%s/%s", file_cwd, dir); | 159 | sprintf(fullpath, "%s/%s", file_cwd, dir); |
160 | arg = fullpath; | 160 | arg = fullpath; |
161 | } | 161 | } |
162 | return filesystems[current_filesystem].ls(arg); | 162 | return filesystems[current_filesystem].ls(arg); |
163 | } | 163 | } |
164 | 164 | ||
165 | long | 165 | int file_read(const char *filename, void *buffer, int maxsize) |
166 | file_read(const char *filename, void *buffer, unsigned long maxsize) | ||
167 | { | 166 | { |
168 | char fullpath[1024]; | 167 | char fullpath[1024]; |
169 | const char *arg; | 168 | const char *arg; |
170 | 169 | ||
171 | if (current_filesystem == FSTYPE_NONE) { | 170 | if (current_filesystem == FSTYPE_NONE) { |
172 | printf("Can't load file without a filesystem!\n"); | 171 | printf("Can't load file without a filesystem!\n"); |
173 | return -1; | 172 | return -1; |
174 | } | 173 | } |
175 | 174 | ||
176 | if (ISDIRDELIM(*filename)) { | 175 | if (ISDIRDELIM(*filename)) { |
177 | arg = filename; | 176 | arg = filename; |
178 | } else { | 177 | } else { |
179 | sprintf(fullpath, "%s/%s", file_cwd, filename); | 178 | sprintf(fullpath, "%s/%s", file_cwd, filename); |
180 | arg = fullpath; | 179 | arg = fullpath; |
181 | } | 180 | } |
182 | 181 | ||
183 | return filesystems[current_filesystem].read(arg, buffer, maxsize); | 182 | return filesystems[current_filesystem].read(arg, buffer, maxsize); |
184 | } | 183 | } |
185 | 184 |
include/fat.h
1 | /* | 1 | /* |
2 | * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg | 2 | * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg |
3 | * | 3 | * |
4 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 | 4 | * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 |
5 | * 2003-03-10 - kharris@nexus-tech.net - ported to u-boot | 5 | * 2003-03-10 - kharris@nexus-tech.net - ported to u-boot |
6 | * | 6 | * |
7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef _FAT_H_ | 10 | #ifndef _FAT_H_ |
11 | #define _FAT_H_ | 11 | #define _FAT_H_ |
12 | 12 | ||
13 | #include <asm/byteorder.h> | 13 | #include <asm/byteorder.h> |
14 | 14 | ||
15 | #define CONFIG_SUPPORT_VFAT | 15 | #define CONFIG_SUPPORT_VFAT |
16 | /* Maximum Long File Name length supported here is 128 UTF-16 code units */ | 16 | /* Maximum Long File Name length supported here is 128 UTF-16 code units */ |
17 | #define VFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */ | 17 | #define VFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */ |
18 | #define VFAT_MAXSEQ 9 /* Up to 9 of 13 2-byte UTF-16 entries */ | 18 | #define VFAT_MAXSEQ 9 /* Up to 9 of 13 2-byte UTF-16 entries */ |
19 | #define PREFETCH_BLOCKS 2 | 19 | #define PREFETCH_BLOCKS 2 |
20 | 20 | ||
21 | #ifndef CONFIG_FS_FAT_MAX_CLUSTSIZE | 21 | #ifndef CONFIG_FS_FAT_MAX_CLUSTSIZE |
22 | #define CONFIG_FS_FAT_MAX_CLUSTSIZE 65536 | 22 | #define CONFIG_FS_FAT_MAX_CLUSTSIZE 65536 |
23 | #endif | 23 | #endif |
24 | #define MAX_CLUSTSIZE CONFIG_FS_FAT_MAX_CLUSTSIZE | 24 | #define MAX_CLUSTSIZE CONFIG_FS_FAT_MAX_CLUSTSIZE |
25 | 25 | ||
26 | #define DIRENTSPERBLOCK (mydata->sect_size / sizeof(dir_entry)) | 26 | #define DIRENTSPERBLOCK (mydata->sect_size / sizeof(dir_entry)) |
27 | #define DIRENTSPERCLUST ((mydata->clust_size * mydata->sect_size) / \ | 27 | #define DIRENTSPERCLUST ((mydata->clust_size * mydata->sect_size) / \ |
28 | sizeof(dir_entry)) | 28 | sizeof(dir_entry)) |
29 | 29 | ||
30 | #define FATBUFBLOCKS 6 | 30 | #define FATBUFBLOCKS 6 |
31 | #define FATBUFSIZE (mydata->sect_size * FATBUFBLOCKS) | 31 | #define FATBUFSIZE (mydata->sect_size * FATBUFBLOCKS) |
32 | #define FAT12BUFSIZE ((FATBUFSIZE*2)/3) | 32 | #define FAT12BUFSIZE ((FATBUFSIZE*2)/3) |
33 | #define FAT16BUFSIZE (FATBUFSIZE/2) | 33 | #define FAT16BUFSIZE (FATBUFSIZE/2) |
34 | #define FAT32BUFSIZE (FATBUFSIZE/4) | 34 | #define FAT32BUFSIZE (FATBUFSIZE/4) |
35 | 35 | ||
36 | 36 | ||
37 | /* Filesystem identifiers */ | 37 | /* Filesystem identifiers */ |
38 | #define FAT12_SIGN "FAT12 " | 38 | #define FAT12_SIGN "FAT12 " |
39 | #define FAT16_SIGN "FAT16 " | 39 | #define FAT16_SIGN "FAT16 " |
40 | #define FAT32_SIGN "FAT32 " | 40 | #define FAT32_SIGN "FAT32 " |
41 | #define SIGNLEN 8 | 41 | #define SIGNLEN 8 |
42 | 42 | ||
43 | /* File attributes */ | 43 | /* File attributes */ |
44 | #define ATTR_RO 1 | 44 | #define ATTR_RO 1 |
45 | #define ATTR_HIDDEN 2 | 45 | #define ATTR_HIDDEN 2 |
46 | #define ATTR_SYS 4 | 46 | #define ATTR_SYS 4 |
47 | #define ATTR_VOLUME 8 | 47 | #define ATTR_VOLUME 8 |
48 | #define ATTR_DIR 16 | 48 | #define ATTR_DIR 16 |
49 | #define ATTR_ARCH 32 | 49 | #define ATTR_ARCH 32 |
50 | 50 | ||
51 | #define ATTR_VFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) | 51 | #define ATTR_VFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) |
52 | 52 | ||
53 | #define DELETED_FLAG ((char)0xe5) /* Marks deleted files when in name[0] */ | 53 | #define DELETED_FLAG ((char)0xe5) /* Marks deleted files when in name[0] */ |
54 | #define aRING 0x05 /* Used as special character in name[0] */ | 54 | #define aRING 0x05 /* Used as special character in name[0] */ |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Indicates that the entry is the last long entry in a set of long | 57 | * Indicates that the entry is the last long entry in a set of long |
58 | * dir entries | 58 | * dir entries |
59 | */ | 59 | */ |
60 | #define LAST_LONG_ENTRY_MASK 0x40 | 60 | #define LAST_LONG_ENTRY_MASK 0x40 |
61 | 61 | ||
62 | /* Flags telling whether we should read a file or list a directory */ | 62 | /* Flags telling whether we should read a file or list a directory */ |
63 | #define LS_NO 0 | 63 | #define LS_NO 0 |
64 | #define LS_YES 1 | 64 | #define LS_YES 1 |
65 | #define LS_DIR 1 | 65 | #define LS_DIR 1 |
66 | #define LS_ROOT 2 | 66 | #define LS_ROOT 2 |
67 | 67 | ||
68 | #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') | 68 | #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') |
69 | 69 | ||
70 | #define FSTYPE_NONE (-1) | 70 | #define FSTYPE_NONE (-1) |
71 | 71 | ||
72 | #if defined(__linux__) && defined(__KERNEL__) | 72 | #if defined(__linux__) && defined(__KERNEL__) |
73 | #define FAT2CPU16 le16_to_cpu | 73 | #define FAT2CPU16 le16_to_cpu |
74 | #define FAT2CPU32 le32_to_cpu | 74 | #define FAT2CPU32 le32_to_cpu |
75 | #else | 75 | #else |
76 | #if __LITTLE_ENDIAN | 76 | #if __LITTLE_ENDIAN |
77 | #define FAT2CPU16(x) (x) | 77 | #define FAT2CPU16(x) (x) |
78 | #define FAT2CPU32(x) (x) | 78 | #define FAT2CPU32(x) (x) |
79 | #else | 79 | #else |
80 | #define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) | 80 | #define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) |
81 | #define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ | 81 | #define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ |
82 | (((x) & 0x0000ff00) << 8) | \ | 82 | (((x) & 0x0000ff00) << 8) | \ |
83 | (((x) & 0x00ff0000) >> 8) | \ | 83 | (((x) & 0x00ff0000) >> 8) | \ |
84 | (((x) & 0xff000000) >> 24)) | 84 | (((x) & 0xff000000) >> 24)) |
85 | #endif | 85 | #endif |
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | #define START(dent) (FAT2CPU16((dent)->start) \ | 88 | #define START(dent) (FAT2CPU16((dent)->start) \ |
89 | + (mydata->fatsize != 32 ? 0 : \ | 89 | + (mydata->fatsize != 32 ? 0 : \ |
90 | (FAT2CPU16((dent)->starthi) << 16))) | 90 | (FAT2CPU16((dent)->starthi) << 16))) |
91 | #define IS_LAST_CLUST(x, fatsize) ((x) >= ((fatsize) != 32 ? \ | 91 | #define IS_LAST_CLUST(x, fatsize) ((x) >= ((fatsize) != 32 ? \ |
92 | ((fatsize) != 16 ? 0xff8 : 0xfff8) : \ | 92 | ((fatsize) != 16 ? 0xff8 : 0xfff8) : \ |
93 | 0xffffff8)) | 93 | 0xffffff8)) |
94 | #define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ | 94 | #define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ |
95 | (x) >= ((fatsize) != 32 ? \ | 95 | (x) >= ((fatsize) != 32 ? \ |
96 | ((fatsize) != 16 ? 0xff0 : 0xfff0) : \ | 96 | ((fatsize) != 16 ? 0xff0 : 0xfff0) : \ |
97 | 0xffffff0)) | 97 | 0xffffff0)) |
98 | 98 | ||
99 | typedef struct boot_sector { | 99 | typedef struct boot_sector { |
100 | __u8 ignored[3]; /* Bootstrap code */ | 100 | __u8 ignored[3]; /* Bootstrap code */ |
101 | char system_id[8]; /* Name of fs */ | 101 | char system_id[8]; /* Name of fs */ |
102 | __u8 sector_size[2]; /* Bytes/sector */ | 102 | __u8 sector_size[2]; /* Bytes/sector */ |
103 | __u8 cluster_size; /* Sectors/cluster */ | 103 | __u8 cluster_size; /* Sectors/cluster */ |
104 | __u16 reserved; /* Number of reserved sectors */ | 104 | __u16 reserved; /* Number of reserved sectors */ |
105 | __u8 fats; /* Number of FATs */ | 105 | __u8 fats; /* Number of FATs */ |
106 | __u8 dir_entries[2]; /* Number of root directory entries */ | 106 | __u8 dir_entries[2]; /* Number of root directory entries */ |
107 | __u8 sectors[2]; /* Number of sectors */ | 107 | __u8 sectors[2]; /* Number of sectors */ |
108 | __u8 media; /* Media code */ | 108 | __u8 media; /* Media code */ |
109 | __u16 fat_length; /* Sectors/FAT */ | 109 | __u16 fat_length; /* Sectors/FAT */ |
110 | __u16 secs_track; /* Sectors/track */ | 110 | __u16 secs_track; /* Sectors/track */ |
111 | __u16 heads; /* Number of heads */ | 111 | __u16 heads; /* Number of heads */ |
112 | __u32 hidden; /* Number of hidden sectors */ | 112 | __u32 hidden; /* Number of hidden sectors */ |
113 | __u32 total_sect; /* Number of sectors (if sectors == 0) */ | 113 | __u32 total_sect; /* Number of sectors (if sectors == 0) */ |
114 | 114 | ||
115 | /* FAT32 only */ | 115 | /* FAT32 only */ |
116 | __u32 fat32_length; /* Sectors/FAT */ | 116 | __u32 fat32_length; /* Sectors/FAT */ |
117 | __u16 flags; /* Bit 8: fat mirroring, low 4: active fat */ | 117 | __u16 flags; /* Bit 8: fat mirroring, low 4: active fat */ |
118 | __u8 version[2]; /* Filesystem version */ | 118 | __u8 version[2]; /* Filesystem version */ |
119 | __u32 root_cluster; /* First cluster in root directory */ | 119 | __u32 root_cluster; /* First cluster in root directory */ |
120 | __u16 info_sector; /* Filesystem info sector */ | 120 | __u16 info_sector; /* Filesystem info sector */ |
121 | __u16 backup_boot; /* Backup boot sector */ | 121 | __u16 backup_boot; /* Backup boot sector */ |
122 | __u16 reserved2[6]; /* Unused */ | 122 | __u16 reserved2[6]; /* Unused */ |
123 | } boot_sector; | 123 | } boot_sector; |
124 | 124 | ||
125 | typedef struct volume_info | 125 | typedef struct volume_info |
126 | { | 126 | { |
127 | __u8 drive_number; /* BIOS drive number */ | 127 | __u8 drive_number; /* BIOS drive number */ |
128 | __u8 reserved; /* Unused */ | 128 | __u8 reserved; /* Unused */ |
129 | __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ | 129 | __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ |
130 | __u8 volume_id[4]; /* Volume ID number */ | 130 | __u8 volume_id[4]; /* Volume ID number */ |
131 | char volume_label[11]; /* Volume label */ | 131 | char volume_label[11]; /* Volume label */ |
132 | char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */ | 132 | char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */ |
133 | /* Boot code comes next, all but 2 bytes to fill up sector */ | 133 | /* Boot code comes next, all but 2 bytes to fill up sector */ |
134 | /* Boot sign comes last, 2 bytes */ | 134 | /* Boot sign comes last, 2 bytes */ |
135 | } volume_info; | 135 | } volume_info; |
136 | 136 | ||
137 | typedef struct dir_entry { | 137 | typedef struct dir_entry { |
138 | char name[8],ext[3]; /* Name and extension */ | 138 | char name[8],ext[3]; /* Name and extension */ |
139 | __u8 attr; /* Attribute bits */ | 139 | __u8 attr; /* Attribute bits */ |
140 | __u8 lcase; /* Case for base and extension */ | 140 | __u8 lcase; /* Case for base and extension */ |
141 | __u8 ctime_ms; /* Creation time, milliseconds */ | 141 | __u8 ctime_ms; /* Creation time, milliseconds */ |
142 | __u16 ctime; /* Creation time */ | 142 | __u16 ctime; /* Creation time */ |
143 | __u16 cdate; /* Creation date */ | 143 | __u16 cdate; /* Creation date */ |
144 | __u16 adate; /* Last access date */ | 144 | __u16 adate; /* Last access date */ |
145 | __u16 starthi; /* High 16 bits of cluster in FAT32 */ | 145 | __u16 starthi; /* High 16 bits of cluster in FAT32 */ |
146 | __u16 time,date,start;/* Time, date and first cluster */ | 146 | __u16 time,date,start;/* Time, date and first cluster */ |
147 | __u32 size; /* File size in bytes */ | 147 | __u32 size; /* File size in bytes */ |
148 | } dir_entry; | 148 | } dir_entry; |
149 | 149 | ||
150 | typedef struct dir_slot { | 150 | typedef struct dir_slot { |
151 | __u8 id; /* Sequence number for slot */ | 151 | __u8 id; /* Sequence number for slot */ |
152 | __u8 name0_4[10]; /* First 5 characters in name */ | 152 | __u8 name0_4[10]; /* First 5 characters in name */ |
153 | __u8 attr; /* Attribute byte */ | 153 | __u8 attr; /* Attribute byte */ |
154 | __u8 reserved; /* Unused */ | 154 | __u8 reserved; /* Unused */ |
155 | __u8 alias_checksum;/* Checksum for 8.3 alias */ | 155 | __u8 alias_checksum;/* Checksum for 8.3 alias */ |
156 | __u8 name5_10[12]; /* 6 more characters in name */ | 156 | __u8 name5_10[12]; /* 6 more characters in name */ |
157 | __u16 start; /* Unused */ | 157 | __u16 start; /* Unused */ |
158 | __u8 name11_12[4]; /* Last 2 characters in name */ | 158 | __u8 name11_12[4]; /* Last 2 characters in name */ |
159 | } dir_slot; | 159 | } dir_slot; |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Private filesystem parameters | 162 | * Private filesystem parameters |
163 | * | 163 | * |
164 | * Note: FAT buffer has to be 32 bit aligned | 164 | * Note: FAT buffer has to be 32 bit aligned |
165 | * (see FAT32 accesses) | 165 | * (see FAT32 accesses) |
166 | */ | 166 | */ |
167 | typedef struct { | 167 | typedef struct { |
168 | __u8 *fatbuf; /* Current FAT buffer */ | 168 | __u8 *fatbuf; /* Current FAT buffer */ |
169 | int fatsize; /* Size of FAT in bits */ | 169 | int fatsize; /* Size of FAT in bits */ |
170 | __u32 fatlength; /* Length of FAT in sectors */ | 170 | __u32 fatlength; /* Length of FAT in sectors */ |
171 | __u16 fat_sect; /* Starting sector of the FAT */ | 171 | __u16 fat_sect; /* Starting sector of the FAT */ |
172 | __u32 rootdir_sect; /* Start sector of root directory */ | 172 | __u32 rootdir_sect; /* Start sector of root directory */ |
173 | __u16 sect_size; /* Size of sectors in bytes */ | 173 | __u16 sect_size; /* Size of sectors in bytes */ |
174 | __u16 clust_size; /* Size of clusters in sectors */ | 174 | __u16 clust_size; /* Size of clusters in sectors */ |
175 | int data_begin; /* The sector of the first cluster, can be negative */ | 175 | int data_begin; /* The sector of the first cluster, can be negative */ |
176 | int fatbufnum; /* Used by get_fatent, init to -1 */ | 176 | int fatbufnum; /* Used by get_fatent, init to -1 */ |
177 | } fsdata; | 177 | } fsdata; |
178 | 178 | ||
179 | typedef int (file_detectfs_func)(void); | 179 | typedef int (file_detectfs_func)(void); |
180 | typedef int (file_ls_func)(const char *dir); | 180 | typedef int (file_ls_func)(const char *dir); |
181 | typedef long (file_read_func)(const char *filename, void *buffer, | 181 | typedef int (file_read_func)(const char *filename, void *buffer, |
182 | unsigned long maxsize); | 182 | int maxsize); |
183 | 183 | ||
184 | struct filesystem { | 184 | struct filesystem { |
185 | file_detectfs_func *detect; | 185 | file_detectfs_func *detect; |
186 | file_ls_func *ls; | 186 | file_ls_func *ls; |
187 | file_read_func *read; | 187 | file_read_func *read; |
188 | const char name[12]; | 188 | const char name[12]; |
189 | }; | 189 | }; |
190 | 190 | ||
191 | /* FAT tables */ | 191 | /* FAT tables */ |
192 | file_detectfs_func file_fat_detectfs; | 192 | file_detectfs_func file_fat_detectfs; |
193 | file_ls_func file_fat_ls; | 193 | file_ls_func file_fat_ls; |
194 | file_read_func file_fat_read; | 194 | file_read_func file_fat_read; |
195 | 195 | ||
196 | /* Currently this doesn't check if the dir exists or is valid... */ | 196 | /* Currently this doesn't check if the dir exists or is valid... */ |
197 | int file_cd(const char *path); | 197 | int file_cd(const char *path); |
198 | int file_fat_detectfs(void); | 198 | int file_fat_detectfs(void); |
199 | int file_fat_ls(const char *dir); | 199 | int file_fat_ls(const char *dir); |
200 | int fat_exists(const char *filename); | 200 | int fat_exists(const char *filename); |
201 | int fat_size(const char *filename); | 201 | int fat_size(const char *filename); |
202 | long file_fat_read_at(const char *filename, unsigned long pos, void *buffer, | 202 | int file_fat_read_at(const char *filename, loff_t pos, void *buffer, |
203 | unsigned long maxsize); | 203 | loff_t maxsize, loff_t *actread); |
204 | long file_fat_read(const char *filename, void *buffer, unsigned long maxsize); | 204 | int file_fat_read(const char *filename, void *buffer, int maxsize); |
205 | const char *file_getfsname(int idx); | 205 | const char *file_getfsname(int idx); |
206 | int fat_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info); | 206 | int fat_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info); |
207 | int fat_register_device(block_dev_desc_t *dev_desc, int part_no); | 207 | int fat_register_device(block_dev_desc_t *dev_desc, int part_no); |
208 | 208 | ||
209 | int file_fat_write(const char *filename, void *buffer, unsigned long maxsize); | 209 | int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len, |
210 | loff_t *actwrite); | ||
210 | int fat_read_file(const char *filename, void *buf, int offset, int len); | 211 | int fat_read_file(const char *filename, void *buf, int offset, int len); |
211 | void fat_close(void); | 212 | void fat_close(void); |
212 | #endif /* _FAT_H_ */ | 213 | #endif /* _FAT_H_ */ |
213 | 214 |