Blame view
fs/fat/fat.c
30.3 KB
83d290c56 SPDX: Convert all... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
71f951180 * Fix CONFIG_NET_... |
2 3 4 5 6 7 8 |
/* * fat.c * * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg * * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 * 2003-03-10 - kharris@nexus-tech.net - ported to uboot |
71f951180 * Fix CONFIG_NET_... |
9 10 11 |
*/ #include <common.h> |
2a981dc2c dm: block: Adjust... |
12 |
#include <blk.h> |
71f951180 * Fix CONFIG_NET_... |
13 |
#include <config.h> |
ac4977719 fat: fix crash wi... |
14 |
#include <exports.h> |
71f951180 * Fix CONFIG_NET_... |
15 |
#include <fat.h> |
1f40366b3 fs/fat: implement... |
16 |
#include <fs.h> |
71f951180 * Fix CONFIG_NET_... |
17 |
#include <asm/byteorder.h> |
7205e4075 * Patches by Deni... |
18 |
#include <part.h> |
9a800ac71 fs/fat: align dis... |
19 |
#include <malloc.h> |
cf92e05c0 Move ALLOC_CACHE_... |
20 |
#include <memalign.h> |
9a800ac71 fs/fat: align dis... |
21 |
#include <linux/compiler.h> |
fb7e16cc1 FAT: use toupper/... |
22 |
#include <linux/ctype.h> |
71f951180 * Fix CONFIG_NET_... |
23 |
|
71f951180 * Fix CONFIG_NET_... |
24 |
/* |
21a24c3bf fs/fat: fix case ... |
25 26 27 |
* Convert a string to lowercase. Converts at most 'len' characters, * 'len' may be larger than the length of 'str' if 'str' is NULL * terminated. |
71f951180 * Fix CONFIG_NET_... |
28 |
*/ |
21a24c3bf fs/fat: fix case ... |
29 |
static void downcase(char *str, size_t len) |
71f951180 * Fix CONFIG_NET_... |
30 |
{ |
21a24c3bf fs/fat: fix case ... |
31 |
while (*str != '\0' && len--) { |
fb7e16cc1 FAT: use toupper/... |
32 |
*str = tolower(*str); |
71f951180 * Fix CONFIG_NET_... |
33 34 35 |
str++; } } |
4101f6879 dm: Drop the bloc... |
36 |
static struct blk_desc *cur_dev; |
9813b750f fs/fat: Fix FAT d... |
37 |
static disk_partition_t cur_part_info; |
7385c28e9 fs/fat: Big code ... |
38 |
|
9813b750f fs/fat: Fix FAT d... |
39 |
#define DOS_BOOT_MAGIC_OFFSET 0x1fe |
7205e4075 * Patches by Deni... |
40 |
#define DOS_FS_TYPE_OFFSET 0x36 |
66c2d73cf FAT32: fix suppor... |
41 |
#define DOS_FS32_TYPE_OFFSET 0x52 |
71f951180 * Fix CONFIG_NET_... |
42 |
|
9813b750f fs/fat: Fix FAT d... |
43 |
static int disk_read(__u32 block, __u32 nr_blocks, void *buf) |
71f951180 * Fix CONFIG_NET_... |
44 |
{ |
0a04ed86c FIX: fat: Provide... |
45 |
ulong ret; |
2a981dc2c dm: block: Adjust... |
46 |
if (!cur_dev) |
7205e4075 * Patches by Deni... |
47 |
return -1; |
7385c28e9 fs/fat: Big code ... |
48 |
|
2a981dc2c dm: block: Adjust... |
49 |
ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf); |
0a04ed86c FIX: fat: Provide... |
50 |
|
42a9f147d fs/fat: Correct b... |
51 |
if (ret != nr_blocks) |
0a04ed86c FIX: fat: Provide... |
52 53 54 |
return -1; return ret; |
71f951180 * Fix CONFIG_NET_... |
55 |
} |
4101f6879 dm: Drop the bloc... |
56 |
int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info) |
71f951180 * Fix CONFIG_NET_... |
57 |
{ |
9a800ac71 fs/fat: align dis... |
58 |
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); |
7205e4075 * Patches by Deni... |
59 |
|
5e8f98319 FAT: implement fa... |
60 61 |
cur_dev = dev_desc; cur_part_info = *info; |
9813b750f fs/fat: Fix FAT d... |
62 63 64 65 66 |
/* Make sure it has a valid FAT header */ if (disk_read(0, 1, buffer) != 1) { cur_dev = NULL; return -1; |
bf1060ea4 Fix missing brace... |
67 |
} |
9813b750f fs/fat: Fix FAT d... |
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
/* Check if it's actually a DOS volume */ if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { cur_dev = NULL; return -1; } /* Check for FAT12/FAT16/FAT32 filesystem */ if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) return 0; if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) return 0; cur_dev = NULL; return -1; |
71f951180 * Fix CONFIG_NET_... |
83 |
} |
4101f6879 dm: Drop the bloc... |
84 |
int fat_register_device(struct blk_desc *dev_desc, int part_no) |
5e8f98319 FAT: implement fa... |
85 86 87 88 89 90 91 |
{ disk_partition_t info; /* First close any currently found FAT filesystem */ cur_dev = NULL; /* Read the partition table, if present */ |
3e8bd4695 dm: part: Rename ... |
92 |
if (part_get_info(dev_desc, part_no, &info)) { |
5e8f98319 FAT: implement fa... |
93 94 95 |
if (part_no != 0) { printf("** Partition %d not valid on device %d ** ", |
bcce53d04 dm: block: Rename... |
96 |
part_no, dev_desc->devnum); |
5e8f98319 FAT: implement fa... |
97 98 99 100 101 102 103 104 105 |
return -1; } info.start = 0; info.size = dev_desc->lba; info.blksz = dev_desc->blksz; info.name[0] = 0; info.type[0] = 0; info.bootable = 0; |
b331cd620 cmd, disk: conver... |
106 |
#if CONFIG_IS_ENABLED(PARTITION_UUIDS) |
5e8f98319 FAT: implement fa... |
107 108 109 110 111 112 |
info.uuid[0] = 0; #endif } return fat_set_blk_dev(dev_desc, &info); } |
9813b750f fs/fat: Fix FAT d... |
113 |
|
71f951180 * Fix CONFIG_NET_... |
114 |
/* |
71f951180 * Fix CONFIG_NET_... |
115 116 |
* Extract zero terminated short name from a directory entry. */ |
9795e07b0 FAT: cosmetic: Re... |
117 |
static void get_name(dir_entry *dirent, char *s_name) |
71f951180 * Fix CONFIG_NET_... |
118 119 |
{ char *ptr; |
7385c28e9 fs/fat: Big code ... |
120 |
memcpy(s_name, dirent->name, 8); |
71f951180 * Fix CONFIG_NET_... |
121 122 123 124 |
s_name[8] = '\0'; ptr = s_name; while (*ptr && *ptr != ' ') ptr++; |
21a24c3bf fs/fat: fix case ... |
125 126 |
if (dirent->lcase & CASE_LOWER_BASE) downcase(s_name, (unsigned)(ptr - s_name)); |
71f951180 * Fix CONFIG_NET_... |
127 |
if (dirent->ext[0] && dirent->ext[0] != ' ') { |
21a24c3bf fs/fat: fix case ... |
128 |
*ptr++ = '.'; |
7385c28e9 fs/fat: Big code ... |
129 |
memcpy(ptr, dirent->ext, 3); |
21a24c3bf fs/fat: fix case ... |
130 131 |
if (dirent->lcase & CASE_LOWER_EXT) downcase(ptr, 3); |
71f951180 * Fix CONFIG_NET_... |
132 133 134 135 136 137 138 139 |
ptr[3] = '\0'; while (*ptr && *ptr != ' ') ptr++; } *ptr = '\0'; if (*s_name == DELETED_FLAG) *s_name = '\0'; else if (*s_name == aRING) |
3c2c2f427 Remove non-ascii ... |
140 |
*s_name = DELETED_FLAG; |
71f951180 * Fix CONFIG_NET_... |
141 |
} |
b8948d2ae fs/fat: merge rea... |
142 |
static int flush_dirty_fat_buffer(fsdata *mydata); |
d8c3ea998 spl: fat/fs: Add ... |
143 144 |
#if !CONFIG_IS_ENABLED(FAT_WRITE) |
b8948d2ae fs/fat: merge rea... |
145 146 147 148 149 150 151 |
/* Stub for read only operation */ int flush_dirty_fat_buffer(fsdata *mydata) { (void)(mydata); return 0; } #endif |
71f951180 * Fix CONFIG_NET_... |
152 153 154 155 |
/* * Get the entry at index 'entry' in a FAT (12/16/32) table. * On failure 0x00 is returned. */ |
9795e07b0 FAT: cosmetic: Re... |
156 |
static __u32 get_fatent(fsdata *mydata, __u32 entry) |
71f951180 * Fix CONFIG_NET_... |
157 158 |
{ __u32 bufnum; |
b352caea7 fs/fat: Fix unali... |
159 |
__u32 offset, off8; |
71f951180 * Fix CONFIG_NET_... |
160 |
__u32 ret = 0x00; |
b8948d2ae fs/fat: merge rea... |
161 162 163 164 165 |
if (CHECK_CLUST(entry, mydata->fatsize)) { printf("Error: Invalid FAT entry: 0x%08x ", entry); return ret; } |
71f951180 * Fix CONFIG_NET_... |
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
switch (mydata->fatsize) { case 32: bufnum = entry / FAT32BUFSIZE; offset = entry - bufnum * FAT32BUFSIZE; break; case 16: bufnum = entry / FAT16BUFSIZE; offset = entry - bufnum * FAT16BUFSIZE; break; case 12: bufnum = entry / FAT12BUFSIZE; offset = entry - bufnum * FAT12BUFSIZE; break; default: /* Unsupported FAT size */ return ret; } |
b8948d2ae fs/fat: merge rea... |
184 185 |
debug("FAT%d: entry: 0x%08x = %d, offset: 0x%04x = %d ", |
7385c28e9 fs/fat: Big code ... |
186 |
mydata->fatsize, entry, entry, offset, offset); |
2aa98c661 FAT32: fix broken... |
187 |
|
71f951180 * Fix CONFIG_NET_... |
188 189 |
/* Read a new block of FAT entries into the cache. */ if (bufnum != mydata->fatbufnum) { |
60b36f0fc fat: cannot compa... |
190 |
__u32 getsize = FATBUFBLOCKS; |
71f951180 * Fix CONFIG_NET_... |
191 192 193 |
__u8 *bufptr = mydata->fatbuf; __u32 fatlength = mydata->fatlength; __u32 startblock = bufnum * FATBUFBLOCKS; |
6c1a80805 fs/fat: Avoid cor... |
194 |
/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ |
8006dd2e5 FAT: get_fatent: ... |
195 196 |
if (startblock + getsize > fatlength) getsize = fatlength - startblock; |
60b36f0fc fat: cannot compa... |
197 |
|
71f951180 * Fix CONFIG_NET_... |
198 |
startblock += mydata->fat_sect; /* Offset from start of disk */ |
b8948d2ae fs/fat: merge rea... |
199 200 201 |
/* Write back the fatbuf to the disk */ if (flush_dirty_fat_buffer(mydata) < 0) return -1; |
71f951180 * Fix CONFIG_NET_... |
202 |
if (disk_read(startblock, getsize, bufptr) < 0) { |
7385c28e9 fs/fat: Big code ... |
203 204 |
debug("Error reading FAT blocks "); |
71f951180 * Fix CONFIG_NET_... |
205 206 207 208 209 210 211 212 |
return ret; } mydata->fatbufnum = bufnum; } /* Get the actual entry from the table */ switch (mydata->fatsize) { case 32: |
7385c28e9 fs/fat: Big code ... |
213 |
ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); |
71f951180 * Fix CONFIG_NET_... |
214 215 |
break; case 16: |
7385c28e9 fs/fat: Big code ... |
216 |
ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); |
71f951180 * Fix CONFIG_NET_... |
217 |
break; |
7385c28e9 fs/fat: Big code ... |
218 |
case 12: |
b352caea7 fs/fat: Fix unali... |
219 220 221 |
off8 = (offset * 3) / 2; /* fatbut + off8 may be unaligned, read in byte granularity */ ret = mydata->fatbuf[off8] + (mydata->fatbuf[off8 + 1] << 8); |
8d48c92b4 fs/fat: simplify ... |
222 223 224 225 |
if (offset & 0x1) ret >>= 4; ret &= 0xfff; |
71f951180 * Fix CONFIG_NET_... |
226 |
} |
b8948d2ae fs/fat: merge rea... |
227 228 229 |
debug("FAT%d: ret: 0x%08x, entry: 0x%08x, offset: 0x%04x ", mydata->fatsize, ret, entry, offset); |
71f951180 * Fix CONFIG_NET_... |
230 231 232 |
return ret; } |
71f951180 * Fix CONFIG_NET_... |
233 234 235 236 237 |
/* * Read at most 'size' bytes from the specified cluster into 'buffer'. * Return 0 on success, -1 otherwise. */ static int |
9795e07b0 FAT: cosmetic: Re... |
238 |
get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) |
71f951180 * Fix CONFIG_NET_... |
239 |
{ |
3f270f42d fat32 root direct... |
240 |
__u32 idx = 0; |
71f951180 * Fix CONFIG_NET_... |
241 |
__u32 startsect; |
46236b140 fs/fat: Improve e... |
242 |
int ret; |
71f951180 * Fix CONFIG_NET_... |
243 244 |
if (clustnum > 0) { |
265edc03d fs/fat: Clean up ... |
245 |
startsect = clust_to_sect(mydata, clustnum); |
71f951180 * Fix CONFIG_NET_... |
246 247 248 |
} else { startsect = mydata->rootdir_sect; } |
7385c28e9 fs/fat: Big code ... |
249 250 |
debug("gc - clustnum: %d, startsect: %d ", clustnum, startsect); |
cc63b25ef FAT: get_cluster:... |
251 |
if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { |
9a800ac71 fs/fat: align dis... |
252 |
ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); |
7385c28e9 fs/fat: Big code ... |
253 |
|
1c381cebb fs: fat: unaligne... |
254 255 |
debug("FAT: Misaligned buffer address (%p) ", buffer); |
cc63b25ef FAT: get_cluster:... |
256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
while (size >= mydata->sect_size) { ret = disk_read(startsect++, 1, tmpbuf); if (ret != 1) { debug("Error reading data (got %d) ", ret); return -1; } memcpy(buffer, tmpbuf, mydata->sect_size); buffer += mydata->sect_size; size -= mydata->sect_size; } } else { |
ac4977719 fat: fix crash wi... |
270 |
idx = size / mydata->sect_size; |
cc63b25ef FAT: get_cluster:... |
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
ret = disk_read(startsect, idx, buffer); if (ret != idx) { debug("Error reading data (got %d) ", ret); return -1; } startsect += idx; idx *= mydata->sect_size; buffer += idx; size -= idx; } if (size) { ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); ret = disk_read(startsect, 1, tmpbuf); |
46236b140 fs/fat: Improve e... |
286 287 288 |
if (ret != 1) { debug("Error reading data (got %d) ", ret); |
7205e4075 * Patches by Deni... |
289 |
return -1; |
71f951180 * Fix CONFIG_NET_... |
290 |
} |
7205e4075 * Patches by Deni... |
291 |
|
cc63b25ef FAT: get_cluster:... |
292 |
memcpy(buffer, tmpbuf, size); |
71f951180 * Fix CONFIG_NET_... |
293 294 295 296 |
} return 0; } |
c7a86d164 fs: fat: treat in... |
297 298 299 |
/** * get_contents() - read from file * |
1170e634d FAT: Make it poss... |
300 |
* Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr' |
c7a86d164 fs: fat: treat in... |
301 302 303 304 305 306 307 308 309 310 |
* into 'buffer'. Update the number of bytes read in *gotsize or return -1 on * fatal errors. * * @mydata: file system description * @dentprt: directory entry pointer * @pos: position from where to read * @buffer: buffer into which to read * @maxsize: maximum number of bytes to read * @gotsize: number of bytes actually read * Return: -1 on error, otherwise 0 |
71f951180 * Fix CONFIG_NET_... |
311 |
*/ |
1ad0b98a0 fat: Prepare API ... |
312 313 |
static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, loff_t maxsize, loff_t *gotsize) |
71f951180 * Fix CONFIG_NET_... |
314 |
{ |
1ad0b98a0 fat: Prepare API ... |
315 |
loff_t filesize = FAT2CPU32(dentptr->size); |
ac4977719 fat: fix crash wi... |
316 |
unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; |
71f951180 * Fix CONFIG_NET_... |
317 |
__u32 curclust = START(dentptr); |
7205e4075 * Patches by Deni... |
318 |
__u32 endclust, newclust; |
1ad0b98a0 fat: Prepare API ... |
319 |
loff_t actsize; |
71f951180 * Fix CONFIG_NET_... |
320 |
|
1ad0b98a0 fat: Prepare API ... |
321 322 323 |
*gotsize = 0; debug("Filesize: %llu bytes ", filesize); |
71f951180 * Fix CONFIG_NET_... |
324 |
|
1170e634d FAT: Make it poss... |
325 |
if (pos >= filesize) { |
1ad0b98a0 fat: Prepare API ... |
326 327 328 |
debug("Read position past EOF: %llu ", pos); return 0; |
1170e634d FAT: Make it poss... |
329 330 331 332 |
} if (maxsize > 0 && filesize > pos + maxsize) filesize = pos + maxsize; |
71f951180 * Fix CONFIG_NET_... |
333 |
|
1ad0b98a0 fat: Prepare API ... |
334 335 |
debug("%llu bytes ", filesize); |
7385c28e9 fs/fat: Big code ... |
336 337 |
actsize = bytesperclust; |
1170e634d FAT: Make it poss... |
338 339 340 341 342 343 344 |
/* go to cluster at pos */ while (actsize <= pos) { curclust = get_fatent(mydata, curclust); if (CHECK_CLUST(curclust, mydata->fatsize)) { debug("curclust: 0x%x ", curclust); |
c7a86d164 fs: fat: treat in... |
345 346 347 |
printf("Invalid FAT entry "); return -1; |
1170e634d FAT: Make it poss... |
348 349 350 351 352 353 354 355 356 357 358 |
} actsize += bytesperclust; } /* actsize > pos */ actsize -= bytesperclust; filesize -= actsize; pos -= actsize; /* align to beginning of next cluster if any */ if (pos) { |
8537874a6 fs: fat: dynamica... |
359 |
__u8 *tmp_buffer; |
1ad0b98a0 fat: Prepare API ... |
360 |
actsize = min(filesize, (loff_t)bytesperclust); |
8537874a6 fs: fat: dynamica... |
361 362 363 364 |
tmp_buffer = malloc_cache_aligned(actsize); if (!tmp_buffer) { debug("Error: allocating buffer "); |
f13683816 fs: fat: get_cont... |
365 |
return -1; |
8537874a6 fs: fat: dynamica... |
366 367 368 |
} if (get_cluster(mydata, curclust, tmp_buffer, actsize) != 0) { |
1170e634d FAT: Make it poss... |
369 370 |
printf("Error reading cluster "); |
8537874a6 fs: fat: dynamica... |
371 |
free(tmp_buffer); |
1170e634d FAT: Make it poss... |
372 373 374 375 |
return -1; } filesize -= actsize; actsize -= pos; |
8537874a6 fs: fat: dynamica... |
376 377 |
memcpy(buffer, tmp_buffer + pos, actsize); free(tmp_buffer); |
1ad0b98a0 fat: Prepare API ... |
378 |
*gotsize += actsize; |
1170e634d FAT: Make it poss... |
379 |
if (!filesize) |
1ad0b98a0 fat: Prepare API ... |
380 |
return 0; |
1170e634d FAT: Make it poss... |
381 382 383 384 385 386 |
buffer += actsize; curclust = get_fatent(mydata, curclust); if (CHECK_CLUST(curclust, mydata->fatsize)) { debug("curclust: 0x%x ", curclust); |
c7a86d164 fs: fat: treat in... |
387 388 389 |
printf("Invalid FAT entry "); return -1; |
1170e634d FAT: Make it poss... |
390 391 392 393 |
} } actsize = bytesperclust; |
7385c28e9 fs/fat: Big code ... |
394 |
endclust = curclust; |
71f951180 * Fix CONFIG_NET_... |
395 396 |
do { |
7205e4075 * Patches by Deni... |
397 |
/* search for consecutive clusters */ |
7385c28e9 fs/fat: Big code ... |
398 |
while (actsize < filesize) { |
7205e4075 * Patches by Deni... |
399 |
newclust = get_fatent(mydata, endclust); |
7385c28e9 fs/fat: Big code ... |
400 |
if ((newclust - 1) != endclust) |
7205e4075 * Patches by Deni... |
401 |
goto getit; |
8ce4e5c2c Fix checking fat3... |
402 |
if (CHECK_CLUST(newclust, mydata->fatsize)) { |
7385c28e9 fs/fat: Big code ... |
403 404 |
debug("curclust: 0x%x ", newclust); |
c7a86d164 fs: fat: treat in... |
405 406 407 |
printf("Invalid FAT entry "); return -1; |
7205e4075 * Patches by Deni... |
408 |
} |
7385c28e9 fs/fat: Big code ... |
409 410 |
endclust = newclust; actsize += bytesperclust; |
7205e4075 * Patches by Deni... |
411 |
} |
7385c28e9 fs/fat: Big code ... |
412 |
|
7205e4075 * Patches by Deni... |
413 |
/* get remaining bytes */ |
7385c28e9 fs/fat: Big code ... |
414 |
actsize = filesize; |
0880e5bb0 FAT: Simplify get... |
415 |
if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
7385c28e9 fs/fat: Big code ... |
416 417 |
printf("Error reading cluster "); |
7205e4075 * Patches by Deni... |
418 419 |
return -1; } |
1ad0b98a0 fat: Prepare API ... |
420 421 |
*gotsize += actsize; return 0; |
7205e4075 * Patches by Deni... |
422 423 |
getit: if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { |
7385c28e9 fs/fat: Big code ... |
424 425 |
printf("Error reading cluster "); |
7205e4075 * Patches by Deni... |
426 427 |
return -1; } |
1ad0b98a0 fat: Prepare API ... |
428 |
*gotsize += (int)actsize; |
7205e4075 * Patches by Deni... |
429 430 |
filesize -= actsize; buffer += actsize; |
7385c28e9 fs/fat: Big code ... |
431 |
|
7205e4075 * Patches by Deni... |
432 |
curclust = get_fatent(mydata, endclust); |
8ce4e5c2c Fix checking fat3... |
433 |
if (CHECK_CLUST(curclust, mydata->fatsize)) { |
7385c28e9 fs/fat: Big code ... |
434 435 436 437 |
debug("curclust: 0x%x ", curclust); printf("Invalid FAT entry "); |
c7a86d164 fs: fat: treat in... |
438 |
return -1; |
71f951180 * Fix CONFIG_NET_... |
439 |
} |
7385c28e9 fs/fat: Big code ... |
440 441 |
actsize = bytesperclust; endclust = curclust; |
71f951180 * Fix CONFIG_NET_... |
442 443 |
} while (1); } |
71f951180 * Fix CONFIG_NET_... |
444 445 446 447 448 |
/* * Extract the file name information from 'slotptr' into 'l_name', * starting at l_name[*idx]. * Return 1 if terminator (zero byte) is found, 0 otherwise. */ |
9795e07b0 FAT: cosmetic: Re... |
449 |
static int slot2str(dir_slot *slotptr, char *l_name, int *idx) |
71f951180 * Fix CONFIG_NET_... |
450 451 452 453 454 |
{ int j; for (j = 0; j <= 8; j += 2) { l_name[*idx] = slotptr->name0_4[j]; |
7385c28e9 fs/fat: Big code ... |
455 456 |
if (l_name[*idx] == 0x00) return 1; |
71f951180 * Fix CONFIG_NET_... |
457 458 459 460 |
(*idx)++; } for (j = 0; j <= 10; j += 2) { l_name[*idx] = slotptr->name5_10[j]; |
7385c28e9 fs/fat: Big code ... |
461 462 |
if (l_name[*idx] == 0x00) return 1; |
71f951180 * Fix CONFIG_NET_... |
463 464 465 466 |
(*idx)++; } for (j = 0; j <= 2; j += 2) { l_name[*idx] = slotptr->name11_12[j]; |
7385c28e9 fs/fat: Big code ... |
467 468 |
if (l_name[*idx] == 0x00) return 1; |
71f951180 * Fix CONFIG_NET_... |
469 470 471 472 473 |
(*idx)++; } return 0; } |
71f951180 * Fix CONFIG_NET_... |
474 |
/* Calculate short name checksum */ |
ff04f6d12 fs: fat: Fix mkck... |
475 |
static __u8 mkcksum(const char name[8], const char ext[3]) |
71f951180 * Fix CONFIG_NET_... |
476 477 |
{ int i; |
7385c28e9 fs/fat: Big code ... |
478 |
|
71f951180 * Fix CONFIG_NET_... |
479 |
__u8 ret = 0; |
6ad77d88e vfat: Fix mkcksum... |
480 |
for (i = 0; i < 8; i++) |
ff04f6d12 fs: fat: Fix mkck... |
481 |
ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i]; |
6ad77d88e vfat: Fix mkcksum... |
482 |
for (i = 0; i < 3; i++) |
ff04f6d12 fs: fat: Fix mkck... |
483 |
ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i]; |
71f951180 * Fix CONFIG_NET_... |
484 485 486 |
return ret; } |
71f951180 * Fix CONFIG_NET_... |
487 488 |
/* |
71f951180 * Fix CONFIG_NET_... |
489 490 491 |
* Read boot sector and volume info from a FAT filesystem */ static int |
9795e07b0 FAT: cosmetic: Re... |
492 |
read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) |
71f951180 * Fix CONFIG_NET_... |
493 |
{ |
ac4977719 fat: fix crash wi... |
494 |
__u8 *block; |
71f951180 * Fix CONFIG_NET_... |
495 |
volume_info *vistart; |
ac4977719 fat: fix crash wi... |
496 497 498 499 500 501 502 |
int ret = 0; if (cur_dev == NULL) { debug("Error: no device selected "); return -1; } |
09fa964bb fs/fat: Fix 'CACH... |
503 |
block = malloc_cache_aligned(cur_dev->blksz); |
ac4977719 fat: fix crash wi... |
504 505 506 507 508 |
if (block == NULL) { debug("Error: allocating block "); return -1; } |
71f951180 * Fix CONFIG_NET_... |
509 |
|
9795e07b0 FAT: cosmetic: Re... |
510 |
if (disk_read(0, 1, block) < 0) { |
7385c28e9 fs/fat: Big code ... |
511 512 |
debug("Error: reading block "); |
ac4977719 fat: fix crash wi... |
513 |
goto fail; |
71f951180 * Fix CONFIG_NET_... |
514 515 516 |
} memcpy(bs, block, sizeof(boot_sector)); |
7385c28e9 fs/fat: Big code ... |
517 518 519 520 521 |
bs->reserved = FAT2CPU16(bs->reserved); bs->fat_length = FAT2CPU16(bs->fat_length); bs->secs_track = FAT2CPU16(bs->secs_track); bs->heads = FAT2CPU16(bs->heads); bs->total_sect = FAT2CPU32(bs->total_sect); |
71f951180 * Fix CONFIG_NET_... |
522 523 524 525 526 |
/* FAT32 entries */ if (bs->fat_length == 0) { /* Assume FAT32 */ bs->fat32_length = FAT2CPU32(bs->fat32_length); |
7385c28e9 fs/fat: Big code ... |
527 |
bs->flags = FAT2CPU16(bs->flags); |
71f951180 * Fix CONFIG_NET_... |
528 |
bs->root_cluster = FAT2CPU32(bs->root_cluster); |
7385c28e9 fs/fat: Big code ... |
529 530 531 |
bs->info_sector = FAT2CPU16(bs->info_sector); bs->backup_boot = FAT2CPU16(bs->backup_boot); vistart = (volume_info *)(block + sizeof(boot_sector)); |
71f951180 * Fix CONFIG_NET_... |
532 533 |
*fatsize = 32; } else { |
7385c28e9 fs/fat: Big code ... |
534 |
vistart = (volume_info *)&(bs->fat32_length); |
71f951180 * Fix CONFIG_NET_... |
535 536 537 |
*fatsize = 0; } memcpy(volinfo, vistart, sizeof(volume_info)); |
71f951180 * Fix CONFIG_NET_... |
538 |
if (*fatsize == 32) { |
7385c28e9 fs/fat: Big code ... |
539 |
if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) |
ac4977719 fat: fix crash wi... |
540 |
goto exit; |
71f951180 * Fix CONFIG_NET_... |
541 |
} else { |
651351fe9 FAT replace compa... |
542 |
if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { |
71f951180 * Fix CONFIG_NET_... |
543 |
*fatsize = 12; |
ac4977719 fat: fix crash wi... |
544 |
goto exit; |
71f951180 * Fix CONFIG_NET_... |
545 |
} |
651351fe9 FAT replace compa... |
546 |
if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { |
71f951180 * Fix CONFIG_NET_... |
547 |
*fatsize = 16; |
ac4977719 fat: fix crash wi... |
548 |
goto exit; |
71f951180 * Fix CONFIG_NET_... |
549 550 |
} } |
7385c28e9 fs/fat: Big code ... |
551 552 |
debug("Error: broken fs_type sign "); |
ac4977719 fat: fix crash wi... |
553 554 555 556 557 |
fail: ret = -1; exit: free(block); return ret; |
71f951180 * Fix CONFIG_NET_... |
558 |
} |
45449980f fs/fat: split out... |
559 |
static int get_fs_info(fsdata *mydata) |
71f951180 * Fix CONFIG_NET_... |
560 |
{ |
7385c28e9 fs/fat: Big code ... |
561 562 |
boot_sector bs; volume_info volinfo; |
45449980f fs/fat: split out... |
563 |
int ret; |
7385c28e9 fs/fat: Big code ... |
564 |
|
45449980f fs/fat: split out... |
565 566 |
ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize); if (ret) { |
7385c28e9 fs/fat: Big code ... |
567 568 |
debug("Error: reading boot sector "); |
45449980f fs/fat: split out... |
569 |
return ret; |
7385c28e9 fs/fat: Big code ... |
570 |
} |
40e219165 fat: root directo... |
571 |
if (mydata->fatsize == 32) { |
7385c28e9 fs/fat: Big code ... |
572 |
mydata->fatlength = bs.fat32_length; |
f23101f95 fs: fat: extend g... |
573 |
mydata->total_sect = bs.total_sect; |
40e219165 fat: root directo... |
574 |
} else { |
7385c28e9 fs/fat: Big code ... |
575 |
mydata->fatlength = bs.fat_length; |
f23101f95 fs: fat: extend g... |
576 577 578 |
mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0]; if (!mydata->total_sect) mydata->total_sect = bs.total_sect; |
40e219165 fat: root directo... |
579 |
} |
f23101f95 fs: fat: extend g... |
580 581 |
if (!mydata->total_sect) /* unlikely */ mydata->total_sect = (u32)cur_part_info.size; |
7385c28e9 fs/fat: Big code ... |
582 |
|
f23101f95 fs: fat: extend g... |
583 |
mydata->fats = bs.fats; |
7385c28e9 fs/fat: Big code ... |
584 |
mydata->fat_sect = bs.reserved; |
45449980f fs/fat: split out... |
585 |
mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; |
7385c28e9 fs/fat: Big code ... |
586 |
|
ac4977719 fat: fix crash wi... |
587 |
mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; |
7385c28e9 fs/fat: Big code ... |
588 |
mydata->clust_size = bs.cluster_size; |
46236b140 fs/fat: Improve e... |
589 590 591 592 593 594 |
if (mydata->sect_size != cur_part_info.blksz) { printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu) ", mydata->sect_size, cur_part_info.blksz); return -1; } |
cd80a4fe6 fs: check FAT clu... |
595 596 597 598 599 600 601 602 603 604 605 606 607 |
if (mydata->clust_size == 0) { printf("Error: FAT cluster size not set "); return -1; } if ((unsigned int)mydata->clust_size * mydata->sect_size > MAX_CLUSTSIZE) { printf("Error: FAT cluster size too big (cs=%u, max=%u) ", (unsigned int)mydata->clust_size * mydata->sect_size, MAX_CLUSTSIZE); return -1; } |
7385c28e9 fs/fat: Big code ... |
608 609 610 611 |
if (mydata->fatsize == 32) { mydata->data_begin = mydata->rootdir_sect - (mydata->clust_size * 2); |
c6e3baa56 fs/fat: introduce... |
612 |
mydata->root_cluster = bs.root_cluster; |
7385c28e9 fs/fat: Big code ... |
613 |
} else { |
45449980f fs/fat: split out... |
614 615 616 617 |
mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + bs.dir_entries[0]) * sizeof(dir_entry)) / mydata->sect_size; |
7385c28e9 fs/fat: Big code ... |
618 |
mydata->data_begin = mydata->rootdir_sect + |
45449980f fs/fat: split out... |
619 |
mydata->rootdir_size - |
7385c28e9 fs/fat: Big code ... |
620 |
(mydata->clust_size * 2); |
9b18358dc fs: fat: fix read... |
621 622 623 624 625 626 627 |
/* * The root directory is not cluster-aligned and may be on a * "negative" cluster, this will be handled specially in * next_cluster(). */ mydata->root_cluster = 0; |
7385c28e9 fs/fat: Big code ... |
628 629 630 |
} mydata->fatbufnum = -1; |
3c0ed9c3a fs/fat: Do not wr... |
631 |
mydata->fat_dirty = 0; |
09fa964bb fs/fat: Fix 'CACH... |
632 |
mydata->fatbuf = malloc_cache_aligned(FATBUFSIZE); |
ac4977719 fat: fix crash wi... |
633 634 635 636 637 |
if (mydata->fatbuf == NULL) { debug("Error: allocating memory "); return -1; } |
71f951180 * Fix CONFIG_NET_... |
638 |
|
7385c28e9 fs/fat: Big code ... |
639 640 641 642 643 644 645 |
debug("FAT%d, fat_sect: %d, fatlength: %d ", mydata->fatsize, mydata->fat_sect, mydata->fatlength); debug("Rootdir begins at cluster: %d, sector: %d, offset: %x " "Data begins at: %d ", |
c6e3baa56 fs/fat: introduce... |
646 |
mydata->root_cluster, |
7385c28e9 fs/fat: Big code ... |
647 |
mydata->rootdir_sect, |
ac4977719 fat: fix crash wi... |
648 649 650 651 |
mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); debug("Sector size: %d, cluster size: %d ", mydata->sect_size, mydata->clust_size); |
7385c28e9 fs/fat: Big code ... |
652 |
|
45449980f fs/fat: split out... |
653 654 |
return 0; } |
c6e3baa56 fs/fat: introduce... |
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
/* * Directory iterator, to simplify filesystem traversal * * Implements an iterator pattern to traverse directory tables, * transparently handling directory tables split across multiple * clusters, and the difference between FAT12/FAT16 root directory * (contiguous) and subdirectories + FAT32 root (chained). * * Rough usage: * * for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { * // to traverse down to a subdirectory pointed to by * // current iterator position: * fat_itr_child(&itr, &itr); * } * * For more complete example, see fat_itr_resolve() */ typedef struct { fsdata *fsdata; /* filesystem parameters */ |
3a10e0723 fs: fat: remember... |
677 |
unsigned start_clust; /* first cluster */ |
c6e3baa56 fs/fat: introduce... |
678 |
unsigned clust; /* current cluster */ |
f528c140c fs: fat: assure i... |
679 |
unsigned next_clust; /* next cluster if remaining == 0 */ |
c6e3baa56 fs/fat: introduce... |
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
int last_cluster; /* set once we've read last cluster */ int is_root; /* is iterator at root directory */ int remaining; /* remaining dent's in current cluster */ /* current iterator position values: */ dir_entry *dent; /* current directory entry */ char l_name[VFAT_MAXLEN_BYTES]; /* long (vfat) name */ char s_name[14]; /* short 8.3 name */ char *name; /* l_name if there is one, else s_name */ /* storage for current cluster in memory: */ u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); } fat_itr; static int fat_itr_isdir(fat_itr *itr); /** * fat_itr_root() - initialize an iterator to start at the root * directory * * @itr: iterator to initialize * @fsdata: filesystem data for the partition * @return 0 on success, else -errno */ static int fat_itr_root(fat_itr *itr, fsdata *fsdata) { if (get_fs_info(fsdata)) return -ENXIO; itr->fsdata = fsdata; |
3a10e0723 fs: fat: remember... |
710 |
itr->start_clust = 0; |
c6e3baa56 fs/fat: introduce... |
711 |
itr->clust = fsdata->root_cluster; |
f528c140c fs: fat: assure i... |
712 |
itr->next_clust = fsdata->root_cluster; |
c6e3baa56 fs/fat: introduce... |
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
itr->dent = NULL; itr->remaining = 0; itr->last_cluster = 0; itr->is_root = 1; return 0; } /** * fat_itr_child() - initialize an iterator to descend into a sub- * directory * * Initializes 'itr' to iterate the contents of the directory at * the current cursor position of 'parent'. It is an error to * call this if the current cursor of 'parent' is pointing at a * regular file. * * Note that 'itr' and 'parent' can be the same pointer if you do * not need to preserve 'parent' after this call, which is useful * for traversing directory structure to resolve a file/directory. * * @itr: iterator to initialize * @parent: the iterator pointing at a directory entry in the * parent directory of the directory to iterate */ static void fat_itr_child(fat_itr *itr, fat_itr *parent) { fsdata *mydata = parent->fsdata; /* for silly macros */ unsigned clustnum = START(parent->dent); assert(fat_itr_isdir(parent)); itr->fsdata = parent->fsdata; |
3a10e0723 fs: fat: remember... |
746 |
itr->start_clust = clustnum; |
c6e3baa56 fs/fat: introduce... |
747 748 |
if (clustnum > 0) { itr->clust = clustnum; |
f528c140c fs: fat: assure i... |
749 |
itr->next_clust = clustnum; |
8df873147 fs/fat: Fix pathn... |
750 |
itr->is_root = 0; |
c6e3baa56 fs/fat: introduce... |
751 752 |
} else { itr->clust = parent->fsdata->root_cluster; |
f528c140c fs: fat: assure i... |
753 |
itr->next_clust = parent->fsdata->root_cluster; |
8df873147 fs/fat: Fix pathn... |
754 |
itr->is_root = 1; |
c6e3baa56 fs/fat: introduce... |
755 756 757 758 |
} itr->dent = NULL; itr->remaining = 0; itr->last_cluster = 0; |
c6e3baa56 fs/fat: introduce... |
759 |
} |
9b18358dc fs: fat: fix read... |
760 |
static void *next_cluster(fat_itr *itr, unsigned *nbytes) |
c6e3baa56 fs/fat: introduce... |
761 762 763 764 |
{ fsdata *mydata = itr->fsdata; /* for silly macros */ int ret; u32 sect; |
9b18358dc fs: fat: fix read... |
765 |
u32 read_size; |
c6e3baa56 fs/fat: introduce... |
766 767 768 769 |
/* have we reached the end? */ if (itr->last_cluster) return NULL; |
9b18358dc fs: fat: fix read... |
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 |
if (itr->is_root && itr->fsdata->fatsize != 32) { /* * The root directory is located before the data area and * cannot be indexed using the regular unsigned cluster * numbers (it may start at a "negative" cluster or not at a * cluster boundary at all), so consider itr->next_clust to be * a offset in cluster-sized units from the start of rootdir. */ unsigned sect_offset = itr->next_clust * itr->fsdata->clust_size; unsigned remaining_sects = itr->fsdata->rootdir_size - sect_offset; sect = itr->fsdata->rootdir_sect + sect_offset; /* do not read past the end of rootdir */ read_size = min_t(u32, itr->fsdata->clust_size, remaining_sects); } else { sect = clust_to_sect(itr->fsdata, itr->next_clust); read_size = itr->fsdata->clust_size; } |
c6e3baa56 fs/fat: introduce... |
788 |
|
9b18358dc fs: fat: fix read... |
789 790 791 |
debug("FAT read(sect=%d), clust_size=%d, read_size=%u, DIRENTSPERBLOCK=%zd ", sect, itr->fsdata->clust_size, read_size, DIRENTSPERBLOCK); |
c6e3baa56 fs/fat: introduce... |
792 793 794 795 796 797 798 799 800 801 |
/* * NOTE: do_fat_read_at() had complicated logic to deal w/ * vfat names that span multiple clusters in the fat16 case, * which get_dentfromdir() probably also needed (and was * missing). And not entirely sure what fat32 didn't have * the same issue.. We solve that by only caring about one * dent at a time and iteratively constructing the vfat long * name. */ |
9b18358dc fs: fat: fix read... |
802 |
ret = disk_read(sect, read_size, itr->block); |
c6e3baa56 fs/fat: introduce... |
803 804 805 806 807 |
if (ret < 0) { debug("Error: reading block "); return NULL; } |
9b18358dc fs: fat: fix read... |
808 |
*nbytes = read_size * itr->fsdata->sect_size; |
f528c140c fs: fat: assure i... |
809 |
itr->clust = itr->next_clust; |
c6e3baa56 fs/fat: introduce... |
810 |
if (itr->is_root && itr->fsdata->fatsize != 32) { |
f528c140c fs: fat: assure i... |
811 |
itr->next_clust++; |
9b18358dc fs: fat: fix read... |
812 |
if (itr->next_clust * itr->fsdata->clust_size >= |
c6e3baa56 fs/fat: introduce... |
813 |
itr->fsdata->rootdir_size) { |
f528c140c fs: fat: assure i... |
814 815 |
debug("nextclust: 0x%x ", itr->next_clust); |
c6e3baa56 fs/fat: introduce... |
816 817 818 |
itr->last_cluster = 1; } } else { |
f528c140c fs: fat: assure i... |
819 820 821 822 |
itr->next_clust = get_fatent(itr->fsdata, itr->next_clust); if (CHECK_CLUST(itr->next_clust, itr->fsdata->fatsize)) { debug("nextclust: 0x%x ", itr->next_clust); |
c6e3baa56 fs/fat: introduce... |
823 824 825 826 827 828 829 830 831 832 |
itr->last_cluster = 1; } } return itr->block; } static dir_entry *next_dent(fat_itr *itr) { if (itr->remaining == 0) { |
9b18358dc fs: fat: fix read... |
833 834 |
unsigned nbytes; struct dir_entry *dent = next_cluster(itr, &nbytes); |
c6e3baa56 fs/fat: introduce... |
835 836 |
/* have we reached the last cluster? */ |
f528c140c fs: fat: assure i... |
837 838 839 |
if (!dent) { /* a sign for no more entries left */ itr->dent = NULL; |
c6e3baa56 fs/fat: introduce... |
840 |
return NULL; |
f528c140c fs: fat: assure i... |
841 |
} |
c6e3baa56 fs/fat: introduce... |
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 |
itr->remaining = nbytes / sizeof(dir_entry) - 1; itr->dent = dent; } else { itr->remaining--; itr->dent++; } /* have we reached the last valid entry? */ if (itr->dent->name[0] == 0) return NULL; return itr->dent; } static dir_entry *extract_vfat_name(fat_itr *itr) { struct dir_entry *dent = itr->dent; int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK; u8 chksum, alias_checksum = ((dir_slot *)dent)->alias_checksum; int n = 0; while (seqn--) { char buf[13]; int idx = 0; slot2str((dir_slot *)dent, buf, &idx); |
8b021bb95 fs: fix FAT name ... |
869 870 |
if (n + idx >= sizeof(itr->l_name)) return NULL; |
c6e3baa56 fs/fat: introduce... |
871 872 873 874 875 876 877 878 879 |
/* shift accumulated long-name up and copy new part in: */ memmove(itr->l_name + idx, itr->l_name, n); memcpy(itr->l_name, buf, idx); n += idx; dent = next_dent(itr); if (!dent) return NULL; } |
39606d462 fs: fat: handle d... |
880 881 882 883 884 885 886 |
/* * We are now at the short file name entry. * If it is marked as deleted, just skip it. */ if (dent->name[0] == DELETED_FLAG || dent->name[0] == aRING) return NULL; |
c6e3baa56 fs/fat: introduce... |
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 |
itr->l_name[n] = '\0'; chksum = mkcksum(dent->name, dent->ext); /* checksum mismatch could mean deleted file, etc.. skip it: */ if (chksum != alias_checksum) { debug("** chksum=%x, alias_checksum=%x, l_name=%s, s_name=%8s.%3s ", chksum, alias_checksum, itr->l_name, dent->name, dent->ext); return NULL; } return dent; } /** * fat_itr_next() - step to the next entry in a directory * * Must be called once on a new iterator before the cursor is valid. * * @itr: the iterator to iterate * @return boolean, 1 if success or 0 if no more entries in the * current directory */ static int fat_itr_next(fat_itr *itr) { dir_entry *dent; itr->name = NULL; |
39606d462 fs: fat: handle d... |
916 917 918 919 920 921 922 923 924 |
/* * One logical directory entry consist of following slots: * name[0] Attributes * dent[N - N]: LFN[N - 1] N|0x40 ATTR_VFAT * ... * dent[N - 2]: LFN[1] 2 ATTR_VFAT * dent[N - 1]: LFN[0] 1 ATTR_VFAT * dent[N]: SFN ATTR_ARCH */ |
c6e3baa56 fs/fat: introduce... |
925 926 927 928 929 930 931 932 933 934 |
while (1) { dent = next_dent(itr); if (!dent) return 0; if (dent->name[0] == DELETED_FLAG || dent->name[0] == aRING) continue; if (dent->attr & ATTR_VOLUME) { |
8bad6cb17 fs: fat: Drop CON... |
935 |
if ((dent->attr & ATTR_VFAT) == ATTR_VFAT && |
c6e3baa56 fs/fat: introduce... |
936 |
(dent->name[0] & LAST_LONG_ENTRY_MASK)) { |
39606d462 fs: fat: handle d... |
937 |
/* long file name */ |
c6e3baa56 fs/fat: introduce... |
938 |
dent = extract_vfat_name(itr); |
39606d462 fs: fat: handle d... |
939 940 941 942 943 944 945 946 947 |
/* * If succeeded, dent has a valid short file * name entry for the current entry. * If failed, itr points to a current bogus * entry. So after fetching a next one, * it may have a short file name entry * for this bogus entry so that we can still * check for a short name. */ |
c6e3baa56 fs/fat: introduce... |
948 949 950 951 952 953 954 955 |
if (!dent) continue; itr->name = itr->l_name; break; } else { /* Volume label or VFAT entry, skip */ continue; } |
39606d462 fs: fat: handle d... |
956 957 958 |
} else if (!(dent->attr & ATTR_ARCH) && !(dent->attr & ATTR_DIR)) continue; |
c6e3baa56 fs/fat: introduce... |
959 |
|
39606d462 fs: fat: handle d... |
960 |
/* short file name */ |
c6e3baa56 fs/fat: introduce... |
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
break; } get_name(dent, itr->s_name); if (!itr->name) itr->name = itr->s_name; return 1; } /** * fat_itr_isdir() - is current cursor position pointing to a directory * * @itr: the iterator * @return true if cursor is at a directory */ static int fat_itr_isdir(fat_itr *itr) { return !!(itr->dent->attr & ATTR_DIR); } /* * Helpers: */ #define TYPE_FILE 0x1 #define TYPE_DIR 0x2 #define TYPE_ANY (TYPE_FILE | TYPE_DIR) /** * fat_itr_resolve() - traverse directory structure to resolve the * requested path. * * Traverse directory structure to the requested path. If the specified * path is to a directory, this will descend into the directory and * leave it iterator at the start of the directory. If the path is to a * file, it will leave the iterator in the parent directory with current * cursor at file's entry in the directory. * * @itr: iterator initialized to root * @path: the requested path * @type: bitmask of allowable file types * @return 0 on success or -errno */ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) { const char *next; /* chomp any extra leading slashes: */ while (path[0] && ISDIRDELIM(path[0])) path++; /* are we at the end? */ if (strlen(path) == 0) { if (!(type & TYPE_DIR)) return -ENOENT; return 0; } /* find length of next path entry: */ next = path; while (next[0] && !ISDIRDELIM(next[0])) next++; |
b94b6be54 fs: fat: handle "... |
1024 1025 1026 1027 1028 1029 |
if (itr->is_root) { /* root dir doesn't have "." nor ".." */ if ((((next - path) == 1) && !strncmp(path, ".", 1)) || (((next - path) == 2) && !strncmp(path, "..", 2))) { /* point back to itself */ itr->clust = itr->fsdata->root_cluster; |
f528c140c fs: fat: assure i... |
1030 |
itr->next_clust = itr->fsdata->root_cluster; |
b94b6be54 fs: fat: handle "... |
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 |
itr->dent = NULL; itr->remaining = 0; itr->last_cluster = 0; if (next[0] == 0) { if (type & TYPE_DIR) return 0; else return -ENOENT; } return fat_itr_resolve(itr, next, type); } } |
c6e3baa56 fs/fat: introduce... |
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
while (fat_itr_next(itr)) { int match = 0; unsigned n = max(strlen(itr->name), (size_t)(next - path)); /* check both long and short name: */ if (!strncasecmp(path, itr->name, n)) match = 1; else if (itr->name != itr->s_name && !strncasecmp(path, itr->s_name, n)) match = 1; if (!match) continue; if (fat_itr_isdir(itr)) { /* recurse into directory: */ fat_itr_child(itr, itr); return fat_itr_resolve(itr, next, type); } else if (next[0]) { /* * If next is not empty then we have a case * like: /path/to/realfile/nonsense */ debug("bad trailing path: %s ", next); return -ENOENT; } else if (!(type & TYPE_FILE)) { return -ENOTDIR; } else { return 0; } } return -ENOENT; } |
9795e07b0 FAT: cosmetic: Re... |
1080 |
int file_fat_detectfs(void) |
71f951180 * Fix CONFIG_NET_... |
1081 |
{ |
7385c28e9 fs/fat: Big code ... |
1082 1083 1084 1085 |
boot_sector bs; volume_info volinfo; int fatsize; char vol_label[12]; |
71f951180 * Fix CONFIG_NET_... |
1086 |
|
7385c28e9 fs/fat: Big code ... |
1087 |
if (cur_dev == NULL) { |
7205e4075 * Patches by Deni... |
1088 1089 1090 1091 |
printf("No current device "); return 1; } |
7385c28e9 fs/fat: Big code ... |
1092 |
|
fc843a02a Kconfig: Add a CO... |
1093 |
#if defined(CONFIG_IDE) || \ |
10e40d54b Kconfig: Add CONF... |
1094 |
defined(CONFIG_SATA) || \ |
c649e3c91 dm: scsi: Rename ... |
1095 |
defined(CONFIG_SCSI) || \ |
dd60d1223 fs/: Remove obsol... |
1096 |
defined(CONFIG_CMD_USB) || \ |
21f6f9636 Fix CONFIG_MMC us... |
1097 |
defined(CONFIG_MMC) |
7205e4075 * Patches by Deni... |
1098 |
printf("Interface: "); |
7385c28e9 fs/fat: Big code ... |
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
switch (cur_dev->if_type) { case IF_TYPE_IDE: printf("IDE"); break; case IF_TYPE_SATA: printf("SATA"); break; case IF_TYPE_SCSI: printf("SCSI"); break; case IF_TYPE_ATAPI: printf("ATAPI"); break; case IF_TYPE_USB: printf("USB"); break; case IF_TYPE_DOC: printf("DOC"); break; case IF_TYPE_MMC: printf("MMC"); break; default: printf("Unknown"); |
7205e4075 * Patches by Deni... |
1123 |
} |
7385c28e9 fs/fat: Big code ... |
1124 |
|
bcce53d04 dm: block: Rename... |
1125 1126 |
printf(" Device %d: ", cur_dev->devnum); |
7205e4075 * Patches by Deni... |
1127 1128 |
dev_print(cur_dev); #endif |
7385c28e9 fs/fat: Big code ... |
1129 1130 |
if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { |
7205e4075 * Patches by Deni... |
1131 1132 1133 1134 1135 |
printf(" No valid FAT fs found "); return 1; } |
7385c28e9 fs/fat: Big code ... |
1136 1137 |
memcpy(vol_label, volinfo.volume_label, 11); |
7205e4075 * Patches by Deni... |
1138 |
vol_label[11] = '\0'; |
7385c28e9 fs/fat: Big code ... |
1139 |
volinfo.fs_type[5] = '\0'; |
461f86e69 FAT: remove cur_p... |
1140 1141 |
printf("Filesystem: %s \"%s\" ", volinfo.fs_type, vol_label); |
7385c28e9 fs/fat: Big code ... |
1142 |
|
7205e4075 * Patches by Deni... |
1143 |
return 0; |
71f951180 * Fix CONFIG_NET_... |
1144 |
} |
b7b5f3195 fat: implement ex... |
1145 1146 |
int fat_exists(const char *filename) { |
8eafae209 fat/fs: convert t... |
1147 |
fsdata fsdata; |
2460098cf fs/fat: Reduce st... |
1148 |
fat_itr *itr; |
1ad0b98a0 fat: Prepare API ... |
1149 |
int ret; |
1ad0b98a0 fat: Prepare API ... |
1150 |
|
09fa964bb fs/fat: Fix 'CACH... |
1151 |
itr = malloc_cache_aligned(sizeof(fat_itr)); |
af609e376 fs/fat: Check mal... |
1152 1153 |
if (!itr) return 0; |
8eafae209 fat/fs: convert t... |
1154 1155 |
ret = fat_itr_root(itr, &fsdata); if (ret) |
af609e376 fs/fat: Check mal... |
1156 |
goto out; |
8eafae209 fat/fs: convert t... |
1157 1158 |
ret = fat_itr_resolve(itr, filename, TYPE_ANY); |
725ffdb5c fs/fat: fix fatbu... |
1159 |
free(fsdata.fatbuf); |
af609e376 fs/fat: Check mal... |
1160 |
out: |
2460098cf fs/fat: Reduce st... |
1161 |
free(itr); |
1ad0b98a0 fat: Prepare API ... |
1162 |
return ret == 0; |
b7b5f3195 fat: implement ex... |
1163 |
} |
d455d8789 fs: API changes e... |
1164 |
int fat_size(const char *filename, loff_t *size) |
cf6598193 fs: implement siz... |
1165 |
{ |
8eafae209 fat/fs: convert t... |
1166 |
fsdata fsdata; |
2460098cf fs/fat: Reduce st... |
1167 |
fat_itr *itr; |
8eafae209 fat/fs: convert t... |
1168 |
int ret; |
09fa964bb fs/fat: Fix 'CACH... |
1169 |
itr = malloc_cache_aligned(sizeof(fat_itr)); |
af609e376 fs/fat: Check mal... |
1170 1171 |
if (!itr) return -ENOMEM; |
8eafae209 fat/fs: convert t... |
1172 1173 |
ret = fat_itr_root(itr, &fsdata); if (ret) |
af609e376 fs/fat: Check mal... |
1174 |
goto out_free_itr; |
8eafae209 fat/fs: convert t... |
1175 1176 1177 1178 1179 1180 1181 |
ret = fat_itr_resolve(itr, filename, TYPE_FILE); if (ret) { /* * Directories don't have size, but fs_size() is not * expected to fail if passed a directory path: */ |
725ffdb5c fs/fat: fix fatbu... |
1182 |
free(fsdata.fatbuf); |
d0cd30eb8 fs: fat: Fix poss... |
1183 1184 1185 1186 1187 |
ret = fat_itr_root(itr, &fsdata); if (ret) goto out_free_itr; ret = fat_itr_resolve(itr, filename, TYPE_DIR); if (!ret) |
8eafae209 fat/fs: convert t... |
1188 |
*size = 0; |
af609e376 fs/fat: Check mal... |
1189 |
goto out_free_both; |
8eafae209 fat/fs: convert t... |
1190 1191 1192 |
} *size = FAT2CPU32(itr->dent->size); |
af609e376 fs/fat: Check mal... |
1193 |
out_free_both: |
725ffdb5c fs/fat: fix fatbu... |
1194 |
free(fsdata.fatbuf); |
af609e376 fs/fat: Check mal... |
1195 |
out_free_itr: |
2460098cf fs/fat: Reduce st... |
1196 |
free(itr); |
725ffdb5c fs/fat: fix fatbu... |
1197 |
return ret; |
cf6598193 fs: implement siz... |
1198 |
} |
1ad0b98a0 fat: Prepare API ... |
1199 1200 |
int file_fat_read_at(const char *filename, loff_t pos, void *buffer, loff_t maxsize, loff_t *actread) |
71f951180 * Fix CONFIG_NET_... |
1201 |
{ |
8eafae209 fat/fs: convert t... |
1202 |
fsdata fsdata; |
2460098cf fs/fat: Reduce st... |
1203 |
fat_itr *itr; |
8eafae209 fat/fs: convert t... |
1204 |
int ret; |
09fa964bb fs/fat: Fix 'CACH... |
1205 |
itr = malloc_cache_aligned(sizeof(fat_itr)); |
af609e376 fs/fat: Check mal... |
1206 1207 |
if (!itr) return -ENOMEM; |
8eafae209 fat/fs: convert t... |
1208 1209 |
ret = fat_itr_root(itr, &fsdata); if (ret) |
af609e376 fs/fat: Check mal... |
1210 |
goto out_free_itr; |
8eafae209 fat/fs: convert t... |
1211 1212 1213 |
ret = fat_itr_resolve(itr, filename, TYPE_FILE); if (ret) |
af609e376 fs/fat: Check mal... |
1214 |
goto out_free_both; |
8eafae209 fat/fs: convert t... |
1215 |
|
287c04e11 fs/fat: debug-pri... |
1216 1217 |
debug("reading %s at pos %llu ", filename, pos); |
e48485f5e fs: fat: Reduce d... |
1218 1219 1220 |
/* For saving default max clustersize memory allocated to malloc pool */ dir_entry *dentptr = itr->dent; |
e48485f5e fs: fat: Reduce d... |
1221 |
ret = get_contents(&fsdata, dentptr, pos, buffer, maxsize, actread); |
725ffdb5c fs/fat: fix fatbu... |
1222 |
|
af609e376 fs/fat: Check mal... |
1223 |
out_free_both: |
725ffdb5c fs/fat: fix fatbu... |
1224 |
free(fsdata.fatbuf); |
af609e376 fs/fat: Check mal... |
1225 |
out_free_itr: |
2460098cf fs/fat: Reduce st... |
1226 |
free(itr); |
725ffdb5c fs/fat: fix fatbu... |
1227 |
return ret; |
1170e634d FAT: Make it poss... |
1228 |
} |
1ad0b98a0 fat: Prepare API ... |
1229 |
int file_fat_read(const char *filename, void *buffer, int maxsize) |
1170e634d FAT: Make it poss... |
1230 |
{ |
1ad0b98a0 fat: Prepare API ... |
1231 1232 1233 1234 1235 1236 1237 1238 |
loff_t actread; int ret; ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread); if (ret) return ret; else return actread; |
71f951180 * Fix CONFIG_NET_... |
1239 |
} |
e6d524153 fs: Move ls and r... |
1240 |
|
d455d8789 fs: API changes e... |
1241 1242 |
int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread) |
e6d524153 fs: Move ls and r... |
1243 |
{ |
1ad0b98a0 fat: Prepare API ... |
1244 |
int ret; |
e6d524153 fs: Move ls and r... |
1245 |
|
d455d8789 fs: API changes e... |
1246 1247 |
ret = file_fat_read_at(filename, offset, buf, len, actread); if (ret) |
e6d524153 fs: Move ls and r... |
1248 1249 |
printf("** Unable to read file %s ** ", filename); |
e6d524153 fs: Move ls and r... |
1250 |
|
d455d8789 fs: API changes e... |
1251 |
return ret; |
e6d524153 fs: Move ls and r... |
1252 |
} |
1f40366b3 fs/fat: implement... |
1253 1254 1255 1256 1257 1258 1259 1260 1261 |
typedef struct { struct fs_dir_stream parent; struct fs_dirent dirent; fsdata fsdata; fat_itr itr; } fat_dir; int fat_opendir(const char *filename, struct fs_dir_stream **dirsp) { |
34dd853ce fat: Use cache al... |
1262 |
fat_dir *dir; |
1f40366b3 fs/fat: implement... |
1263 |
int ret; |
34dd853ce fat: Use cache al... |
1264 |
dir = malloc_cache_aligned(sizeof(*dir)); |
1f40366b3 fs/fat: implement... |
1265 1266 |
if (!dir) return -ENOMEM; |
34dd853ce fat: Use cache al... |
1267 |
memset(dir, 0, sizeof(*dir)); |
1f40366b3 fs/fat: implement... |
1268 1269 1270 |
ret = fat_itr_root(&dir->itr, &dir->fsdata); if (ret) |
af609e376 fs/fat: Check mal... |
1271 |
goto fail_free_dir; |
1f40366b3 fs/fat: implement... |
1272 1273 1274 |
ret = fat_itr_resolve(&dir->itr, filename, TYPE_DIR); if (ret) |
af609e376 fs/fat: Check mal... |
1275 |
goto fail_free_both; |
1f40366b3 fs/fat: implement... |
1276 1277 1278 |
*dirsp = (struct fs_dir_stream *)dir; return 0; |
af609e376 fs/fat: Check mal... |
1279 |
fail_free_both: |
725ffdb5c fs/fat: fix fatbu... |
1280 |
free(dir->fsdata.fatbuf); |
af609e376 fs/fat: Check mal... |
1281 |
fail_free_dir: |
1f40366b3 fs/fat: implement... |
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 |
free(dir); return ret; } int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) { fat_dir *dir = (fat_dir *)dirs; struct fs_dirent *dent = &dir->dirent; if (!fat_itr_next(&dir->itr)) return -ENOENT; memset(dent, 0, sizeof(*dent)); strcpy(dent->name, dir->itr.name); if (fat_itr_isdir(&dir->itr)) { dent->type = FS_DT_DIR; } else { dent->type = FS_DT_REG; dent->size = FAT2CPU32(dir->itr.dent->size); } *dentp = dent; return 0; } void fat_closedir(struct fs_dir_stream *dirs) { fat_dir *dir = (fat_dir *)dirs; |
725ffdb5c fs/fat: fix fatbu... |
1312 |
free(dir->fsdata.fatbuf); |
1f40366b3 fs/fat: implement... |
1313 1314 |
free(dir); } |
e6d524153 fs: Move ls and r... |
1315 1316 1317 |
void fat_close(void) { } |