Blame view

fs/fat/fat.c 30.3 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
71f951180   wdenk   * 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   wdenk   * Fix CONFIG_NET_...
9
10
11
   */
  
  #include <common.h>
2a981dc2c   Simon Glass   dm: block: Adjust...
12
  #include <blk.h>
71f951180   wdenk   * Fix CONFIG_NET_...
13
  #include <config.h>
ac4977719   Sergei Shtylyov   fat: fix crash wi...
14
  #include <exports.h>
71f951180   wdenk   * Fix CONFIG_NET_...
15
  #include <fat.h>
1f40366b3   Rob Clark   fs/fat: implement...
16
  #include <fs.h>
71f951180   wdenk   * Fix CONFIG_NET_...
17
  #include <asm/byteorder.h>
7205e4075   wdenk   * Patches by Deni...
18
  #include <part.h>
9a800ac71   Eric Nelson   fs/fat: align dis...
19
  #include <malloc.h>
cf92e05c0   Simon Glass   Move ALLOC_CACHE_...
20
  #include <memalign.h>
9a800ac71   Eric Nelson   fs/fat: align dis...
21
  #include <linux/compiler.h>
fb7e16cc1   Richard Genoud   FAT: use toupper/...
22
  #include <linux/ctype.h>
71f951180   wdenk   * Fix CONFIG_NET_...
23

71f951180   wdenk   * Fix CONFIG_NET_...
24
  /*
21a24c3bf   Rob Clark   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   wdenk   * Fix CONFIG_NET_...
28
   */
21a24c3bf   Rob Clark   fs/fat: fix case ...
29
  static void downcase(char *str, size_t len)
71f951180   wdenk   * Fix CONFIG_NET_...
30
  {
21a24c3bf   Rob Clark   fs/fat: fix case ...
31
  	while (*str != '\0' && len--) {
fb7e16cc1   Richard Genoud   FAT: use toupper/...
32
  		*str = tolower(*str);
71f951180   wdenk   * Fix CONFIG_NET_...
33
34
35
  		str++;
  	}
  }
4101f6879   Simon Glass   dm: Drop the bloc...
36
  static struct blk_desc *cur_dev;
9813b750f   Kyle Moffett   fs/fat: Fix FAT d...
37
  static disk_partition_t cur_part_info;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
38

9813b750f   Kyle Moffett   fs/fat: Fix FAT d...
39
  #define DOS_BOOT_MAGIC_OFFSET	0x1fe
7205e4075   wdenk   * Patches by Deni...
40
  #define DOS_FS_TYPE_OFFSET	0x36
66c2d73cf   Wolfgang Denk   FAT32: fix suppor...
41
  #define DOS_FS32_TYPE_OFFSET	0x52
71f951180   wdenk   * Fix CONFIG_NET_...
42

9813b750f   Kyle Moffett   fs/fat: Fix FAT d...
43
  static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
71f951180   wdenk   * Fix CONFIG_NET_...
44
  {
0a04ed86c   Łukasz Majewski   FIX: fat: Provide...
45
  	ulong ret;
2a981dc2c   Simon Glass   dm: block: Adjust...
46
  	if (!cur_dev)
7205e4075   wdenk   * Patches by Deni...
47
  		return -1;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
48

2a981dc2c   Simon Glass   dm: block: Adjust...
49
  	ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf);
0a04ed86c   Łukasz Majewski   FIX: fat: Provide...
50

42a9f147d   Tom Rini   fs/fat: Correct b...
51
  	if (ret != nr_blocks)
0a04ed86c   Łukasz Majewski   FIX: fat: Provide...
52
53
54
  		return -1;
  
  	return ret;
71f951180   wdenk   * Fix CONFIG_NET_...
55
  }
4101f6879   Simon Glass   dm: Drop the bloc...
56
  int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
71f951180   wdenk   * Fix CONFIG_NET_...
57
  {
9a800ac71   Eric Nelson   fs/fat: align dis...
58
  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
7205e4075   wdenk   * Patches by Deni...
59

5e8f98319   Stephen Warren   FAT: implement fa...
60
61
  	cur_dev = dev_desc;
  	cur_part_info = *info;
9813b750f   Kyle Moffett   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   Wolfgang Denk   Fix missing brace...
67
  	}
9813b750f   Kyle Moffett   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   wdenk   * Fix CONFIG_NET_...
83
  }
4101f6879   Simon Glass   dm: Drop the bloc...
84
  int fat_register_device(struct blk_desc *dev_desc, int part_no)
5e8f98319   Stephen Warren   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   Simon Glass   dm: part: Rename ...
92
  	if (part_get_info(dev_desc, part_no, &info)) {
5e8f98319   Stephen Warren   FAT: implement fa...
93
94
95
  		if (part_no != 0) {
  			printf("** Partition %d not valid on device %d **
  ",
bcce53d04   Simon Glass   dm: block: Rename...
96
  					part_no, dev_desc->devnum);
5e8f98319   Stephen Warren   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   Patrick Delaunay   cmd, disk: conver...
106
  #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
5e8f98319   Stephen Warren   FAT: implement fa...
107
108
109
110
111
112
  		info.uuid[0] = 0;
  #endif
  	}
  
  	return fat_set_blk_dev(dev_desc, &info);
  }
9813b750f   Kyle Moffett   fs/fat: Fix FAT d...
113

71f951180   wdenk   * Fix CONFIG_NET_...
114
  /*
71f951180   wdenk   * Fix CONFIG_NET_...
115
116
   * Extract zero terminated short name from a directory entry.
   */
9795e07b0   Benoît Thébaudeau   FAT: cosmetic: Re...
117
  static void get_name(dir_entry *dirent, char *s_name)
71f951180   wdenk   * Fix CONFIG_NET_...
118
119
  {
  	char *ptr;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
120
  	memcpy(s_name, dirent->name, 8);
71f951180   wdenk   * Fix CONFIG_NET_...
121
122
123
124
  	s_name[8] = '\0';
  	ptr = s_name;
  	while (*ptr && *ptr != ' ')
  		ptr++;
21a24c3bf   Rob Clark   fs/fat: fix case ...
125
126
  	if (dirent->lcase & CASE_LOWER_BASE)
  		downcase(s_name, (unsigned)(ptr - s_name));
71f951180   wdenk   * Fix CONFIG_NET_...
127
  	if (dirent->ext[0] && dirent->ext[0] != ' ') {
21a24c3bf   Rob Clark   fs/fat: fix case ...
128
  		*ptr++ = '.';
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
129
  		memcpy(ptr, dirent->ext, 3);
21a24c3bf   Rob Clark   fs/fat: fix case ...
130
131
  		if (dirent->lcase & CASE_LOWER_EXT)
  			downcase(ptr, 3);
71f951180   wdenk   * 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   Remy Bohmer   Remove non-ascii ...
140
  		*s_name = DELETED_FLAG;
71f951180   wdenk   * Fix CONFIG_NET_...
141
  }
b8948d2ae   Stefan Brüns   fs/fat: merge rea...
142
  static int flush_dirty_fat_buffer(fsdata *mydata);
d8c3ea998   Tien Fong Chee   spl: fat/fs: Add ...
143
144
  
  #if !CONFIG_IS_ENABLED(FAT_WRITE)
b8948d2ae   Stefan Brüns   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   wdenk   * 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   Benoît Thébaudeau   FAT: cosmetic: Re...
156
  static __u32 get_fatent(fsdata *mydata, __u32 entry)
71f951180   wdenk   * Fix CONFIG_NET_...
157
158
  {
  	__u32 bufnum;
b352caea7   Stefan Brüns   fs/fat: Fix unali...
159
  	__u32 offset, off8;
71f951180   wdenk   * Fix CONFIG_NET_...
160
  	__u32 ret = 0x00;
b8948d2ae   Stefan Brüns   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   wdenk   * 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   Stefan Brüns   fs/fat: merge rea...
184
185
  	debug("FAT%d: entry: 0x%08x = %d, offset: 0x%04x = %d
  ",
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
186
  	       mydata->fatsize, entry, entry, offset, offset);
2aa98c661   Wolfgang Denk   FAT32: fix broken...
187

71f951180   wdenk   * Fix CONFIG_NET_...
188
189
  	/* Read a new block of FAT entries into the cache. */
  	if (bufnum != mydata->fatbufnum) {
60b36f0fc   Sergei Shtylyov   fat: cannot compa...
190
  		__u32 getsize = FATBUFBLOCKS;
71f951180   wdenk   * Fix CONFIG_NET_...
191
192
193
  		__u8 *bufptr = mydata->fatbuf;
  		__u32 fatlength = mydata->fatlength;
  		__u32 startblock = bufnum * FATBUFBLOCKS;
6c1a80805   Stefan Brüns   fs/fat: Avoid cor...
194
  		/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
8006dd2e5   Benoît Thébaudeau   FAT: get_fatent: ...
195
196
  		if (startblock + getsize > fatlength)
  			getsize = fatlength - startblock;
60b36f0fc   Sergei Shtylyov   fat: cannot compa...
197

71f951180   wdenk   * Fix CONFIG_NET_...
198
  		startblock += mydata->fat_sect;	/* Offset from start of disk */
b8948d2ae   Stefan Brüns   fs/fat: merge rea...
199
200
201
  		/* Write back the fatbuf to the disk */
  		if (flush_dirty_fat_buffer(mydata) < 0)
  			return -1;
71f951180   wdenk   * Fix CONFIG_NET_...
202
  		if (disk_read(startblock, getsize, bufptr) < 0) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
203
204
  			debug("Error reading FAT blocks
  ");
71f951180   wdenk   * 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   Wolfgang Denk   fs/fat: Big code ...
213
  		ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
71f951180   wdenk   * Fix CONFIG_NET_...
214
215
  		break;
  	case 16:
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
216
  		ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
71f951180   wdenk   * Fix CONFIG_NET_...
217
  		break;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
218
  	case 12:
b352caea7   Stefan Brüns   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   Stefan Brüns   fs/fat: simplify ...
222
223
224
225
  
  		if (offset & 0x1)
  			ret >>= 4;
  		ret &= 0xfff;
71f951180   wdenk   * Fix CONFIG_NET_...
226
  	}
b8948d2ae   Stefan Brüns   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   wdenk   * Fix CONFIG_NET_...
230
231
232
  
  	return ret;
  }
71f951180   wdenk   * 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   Benoît Thébaudeau   FAT: cosmetic: Re...
238
  get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
71f951180   wdenk   * Fix CONFIG_NET_...
239
  {
3f270f42d   Erik Hansen   fat32 root direct...
240
  	__u32 idx = 0;
71f951180   wdenk   * Fix CONFIG_NET_...
241
  	__u32 startsect;
46236b140   Kyle Moffett   fs/fat: Improve e...
242
  	int ret;
71f951180   wdenk   * Fix CONFIG_NET_...
243
244
  
  	if (clustnum > 0) {
265edc03d   Rob Clark   fs/fat: Clean up ...
245
  		startsect = clust_to_sect(mydata, clustnum);
71f951180   wdenk   * Fix CONFIG_NET_...
246
247
248
  	} else {
  		startsect = mydata->rootdir_sect;
  	}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
249
250
  	debug("gc - clustnum: %d, startsect: %d
  ", clustnum, startsect);
cc63b25ef   Benoît Thébaudeau   FAT: get_cluster:...
251
  	if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
9a800ac71   Eric Nelson   fs/fat: align dis...
252
  		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
253

1c381cebb   Heinrich Schuchardt   fs: fat: unaligne...
254
255
  		debug("FAT: Misaligned buffer address (%p)
  ", buffer);
cc63b25ef   Benoît Thébaudeau   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   Sergei Shtylyov   fat: fix crash wi...
270
  		idx = size / mydata->sect_size;
cc63b25ef   Benoît Thébaudeau   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   Kyle Moffett   fs/fat: Improve e...
286
287
288
  		if (ret != 1) {
  			debug("Error reading data (got %d)
  ", ret);
7205e4075   wdenk   * Patches by Deni...
289
  			return -1;
71f951180   wdenk   * Fix CONFIG_NET_...
290
  		}
7205e4075   wdenk   * Patches by Deni...
291

cc63b25ef   Benoît Thébaudeau   FAT: get_cluster:...
292
  		memcpy(buffer, tmpbuf, size);
71f951180   wdenk   * Fix CONFIG_NET_...
293
294
295
296
  	}
  
  	return 0;
  }
c7a86d164   Heinrich Schuchardt   fs: fat: treat in...
297
298
299
  /**
   * get_contents() - read from file
   *
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
300
   * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr'
c7a86d164   Heinrich Schuchardt   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   wdenk   * Fix CONFIG_NET_...
311
   */
1ad0b98a0   Suriyan Ramasami   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   wdenk   * Fix CONFIG_NET_...
314
  {
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
315
  	loff_t filesize = FAT2CPU32(dentptr->size);
ac4977719   Sergei Shtylyov   fat: fix crash wi...
316
  	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
71f951180   wdenk   * Fix CONFIG_NET_...
317
  	__u32 curclust = START(dentptr);
7205e4075   wdenk   * Patches by Deni...
318
  	__u32 endclust, newclust;
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
319
  	loff_t actsize;
71f951180   wdenk   * Fix CONFIG_NET_...
320

1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
321
322
323
  	*gotsize = 0;
  	debug("Filesize: %llu bytes
  ", filesize);
71f951180   wdenk   * Fix CONFIG_NET_...
324

1170e634d   Benoît Thébaudeau   FAT: Make it poss...
325
  	if (pos >= filesize) {
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
326
327
328
  		debug("Read position past EOF: %llu
  ", pos);
  		return 0;
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
329
330
331
332
  	}
  
  	if (maxsize > 0 && filesize > pos + maxsize)
  		filesize = pos + maxsize;
71f951180   wdenk   * Fix CONFIG_NET_...
333

1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
334
335
  	debug("%llu bytes
  ", filesize);
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
336
337
  
  	actsize = bytesperclust;
1170e634d   Benoît Thébaudeau   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   Heinrich Schuchardt   fs: fat: treat in...
345
346
347
  			printf("Invalid FAT entry
  ");
  			return -1;
1170e634d   Benoît Thébaudeau   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   Tien Fong Chee   fs: fat: dynamica...
359
  		__u8 *tmp_buffer;
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
360
  		actsize = min(filesize, (loff_t)bytesperclust);
8537874a6   Tien Fong Chee   fs: fat: dynamica...
361
362
363
364
  		tmp_buffer = malloc_cache_aligned(actsize);
  		if (!tmp_buffer) {
  			debug("Error: allocating buffer
  ");
f13683816   Heinrich Schuchardt   fs: fat: get_cont...
365
  			return -1;
8537874a6   Tien Fong Chee   fs: fat: dynamica...
366
367
368
  		}
  
  		if (get_cluster(mydata, curclust, tmp_buffer, actsize) != 0) {
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
369
370
  			printf("Error reading cluster
  ");
8537874a6   Tien Fong Chee   fs: fat: dynamica...
371
  			free(tmp_buffer);
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
372
373
374
375
  			return -1;
  		}
  		filesize -= actsize;
  		actsize -= pos;
8537874a6   Tien Fong Chee   fs: fat: dynamica...
376
377
  		memcpy(buffer, tmp_buffer + pos, actsize);
  		free(tmp_buffer);
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
378
  		*gotsize += actsize;
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
379
  		if (!filesize)
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
380
  			return 0;
1170e634d   Benoît Thébaudeau   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   Heinrich Schuchardt   fs: fat: treat in...
387
388
389
  			printf("Invalid FAT entry
  ");
  			return -1;
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
390
391
392
393
  		}
  	}
  
  	actsize = bytesperclust;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
394
  	endclust = curclust;
71f951180   wdenk   * Fix CONFIG_NET_...
395
396
  
  	do {
7205e4075   wdenk   * Patches by Deni...
397
  		/* search for consecutive clusters */
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
398
  		while (actsize < filesize) {
7205e4075   wdenk   * Patches by Deni...
399
  			newclust = get_fatent(mydata, endclust);
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
400
  			if ((newclust - 1) != endclust)
7205e4075   wdenk   * Patches by Deni...
401
  				goto getit;
8ce4e5c2c   michael   Fix checking fat3...
402
  			if (CHECK_CLUST(newclust, mydata->fatsize)) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
403
404
  				debug("curclust: 0x%x
  ", newclust);
c7a86d164   Heinrich Schuchardt   fs: fat: treat in...
405
406
407
  				printf("Invalid FAT entry
  ");
  				return -1;
7205e4075   wdenk   * Patches by Deni...
408
  			}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
409
410
  			endclust = newclust;
  			actsize += bytesperclust;
7205e4075   wdenk   * Patches by Deni...
411
  		}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
412

7205e4075   wdenk   * Patches by Deni...
413
  		/* get remaining bytes */
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
414
  		actsize = filesize;
0880e5bb0   Benoît Thébaudeau   FAT: Simplify get...
415
  		if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
416
417
  			printf("Error reading cluster
  ");
7205e4075   wdenk   * Patches by Deni...
418
419
  			return -1;
  		}
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
420
421
  		*gotsize += actsize;
  		return 0;
7205e4075   wdenk   * Patches by Deni...
422
423
  getit:
  		if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
424
425
  			printf("Error reading cluster
  ");
7205e4075   wdenk   * Patches by Deni...
426
427
  			return -1;
  		}
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
428
  		*gotsize += (int)actsize;
7205e4075   wdenk   * Patches by Deni...
429
430
  		filesize -= actsize;
  		buffer += actsize;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
431

7205e4075   wdenk   * Patches by Deni...
432
  		curclust = get_fatent(mydata, endclust);
8ce4e5c2c   michael   Fix checking fat3...
433
  		if (CHECK_CLUST(curclust, mydata->fatsize)) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
434
435
436
437
  			debug("curclust: 0x%x
  ", curclust);
  			printf("Invalid FAT entry
  ");
c7a86d164   Heinrich Schuchardt   fs: fat: treat in...
438
  			return -1;
71f951180   wdenk   * Fix CONFIG_NET_...
439
  		}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
440
441
  		actsize = bytesperclust;
  		endclust = curclust;
71f951180   wdenk   * Fix CONFIG_NET_...
442
443
  	} while (1);
  }
71f951180   wdenk   * 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   Benoît Thébaudeau   FAT: cosmetic: Re...
449
  static int slot2str(dir_slot *slotptr, char *l_name, int *idx)
71f951180   wdenk   * 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   Wolfgang Denk   fs/fat: Big code ...
455
456
  		if (l_name[*idx] == 0x00)
  			return 1;
71f951180   wdenk   * Fix CONFIG_NET_...
457
458
459
460
  		(*idx)++;
  	}
  	for (j = 0; j <= 10; j += 2) {
  		l_name[*idx] = slotptr->name5_10[j];
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
461
462
  		if (l_name[*idx] == 0x00)
  			return 1;
71f951180   wdenk   * Fix CONFIG_NET_...
463
464
465
466
  		(*idx)++;
  	}
  	for (j = 0; j <= 2; j += 2) {
  		l_name[*idx] = slotptr->name11_12[j];
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
467
468
  		if (l_name[*idx] == 0x00)
  			return 1;
71f951180   wdenk   * Fix CONFIG_NET_...
469
470
471
472
473
  		(*idx)++;
  	}
  
  	return 0;
  }
71f951180   wdenk   * Fix CONFIG_NET_...
474
  /* Calculate short name checksum */
ff04f6d12   Marek Vasut   fs: fat: Fix mkck...
475
  static __u8 mkcksum(const char name[8], const char ext[3])
71f951180   wdenk   * Fix CONFIG_NET_...
476
477
  {
  	int i;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
478

71f951180   wdenk   * Fix CONFIG_NET_...
479
  	__u8 ret = 0;
6ad77d88e   Marek Vasut   vfat: Fix mkcksum...
480
  	for (i = 0; i < 8; i++)
ff04f6d12   Marek Vasut   fs: fat: Fix mkck...
481
  		ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i];
6ad77d88e   Marek Vasut   vfat: Fix mkcksum...
482
  	for (i = 0; i < 3; i++)
ff04f6d12   Marek Vasut   fs: fat: Fix mkck...
483
  		ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i];
71f951180   wdenk   * Fix CONFIG_NET_...
484
485
486
  
  	return ret;
  }
71f951180   wdenk   * Fix CONFIG_NET_...
487
488
  
  /*
71f951180   wdenk   * Fix CONFIG_NET_...
489
490
491
   * Read boot sector and volume info from a FAT filesystem
   */
  static int
9795e07b0   Benoît Thébaudeau   FAT: cosmetic: Re...
492
  read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
71f951180   wdenk   * Fix CONFIG_NET_...
493
  {
ac4977719   Sergei Shtylyov   fat: fix crash wi...
494
  	__u8 *block;
71f951180   wdenk   * Fix CONFIG_NET_...
495
  	volume_info *vistart;
ac4977719   Sergei Shtylyov   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   Tuomas Tynkkynen   fs/fat: Fix 'CACH...
503
  	block = malloc_cache_aligned(cur_dev->blksz);
ac4977719   Sergei Shtylyov   fat: fix crash wi...
504
505
506
507
508
  	if (block == NULL) {
  		debug("Error: allocating block
  ");
  		return -1;
  	}
71f951180   wdenk   * Fix CONFIG_NET_...
509

9795e07b0   Benoît Thébaudeau   FAT: cosmetic: Re...
510
  	if (disk_read(0, 1, block) < 0) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
511
512
  		debug("Error: reading block
  ");
ac4977719   Sergei Shtylyov   fat: fix crash wi...
513
  		goto fail;
71f951180   wdenk   * Fix CONFIG_NET_...
514
515
516
  	}
  
  	memcpy(bs, block, sizeof(boot_sector));
7385c28e9   Wolfgang Denk   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   wdenk   * 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   Wolfgang Denk   fs/fat: Big code ...
527
  		bs->flags = FAT2CPU16(bs->flags);
71f951180   wdenk   * Fix CONFIG_NET_...
528
  		bs->root_cluster = FAT2CPU32(bs->root_cluster);
7385c28e9   Wolfgang Denk   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   wdenk   * Fix CONFIG_NET_...
532
533
  		*fatsize = 32;
  	} else {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
534
  		vistart = (volume_info *)&(bs->fat32_length);
71f951180   wdenk   * Fix CONFIG_NET_...
535
536
537
  		*fatsize = 0;
  	}
  	memcpy(volinfo, vistart, sizeof(volume_info));
71f951180   wdenk   * Fix CONFIG_NET_...
538
  	if (*fatsize == 32) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
539
  		if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0)
ac4977719   Sergei Shtylyov   fat: fix crash wi...
540
  			goto exit;
71f951180   wdenk   * Fix CONFIG_NET_...
541
  	} else {
651351fe9   Tom Rix   FAT replace compa...
542
  		if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) {
71f951180   wdenk   * Fix CONFIG_NET_...
543
  			*fatsize = 12;
ac4977719   Sergei Shtylyov   fat: fix crash wi...
544
  			goto exit;
71f951180   wdenk   * Fix CONFIG_NET_...
545
  		}
651351fe9   Tom Rix   FAT replace compa...
546
  		if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) {
71f951180   wdenk   * Fix CONFIG_NET_...
547
  			*fatsize = 16;
ac4977719   Sergei Shtylyov   fat: fix crash wi...
548
  			goto exit;
71f951180   wdenk   * Fix CONFIG_NET_...
549
550
  		}
  	}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
551
552
  	debug("Error: broken fs_type sign
  ");
ac4977719   Sergei Shtylyov   fat: fix crash wi...
553
554
555
556
557
  fail:
  	ret = -1;
  exit:
  	free(block);
  	return ret;
71f951180   wdenk   * Fix CONFIG_NET_...
558
  }
45449980f   Rob Clark   fs/fat: split out...
559
  static int get_fs_info(fsdata *mydata)
71f951180   wdenk   * Fix CONFIG_NET_...
560
  {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
561
562
  	boot_sector bs;
  	volume_info volinfo;
45449980f   Rob Clark   fs/fat: split out...
563
  	int ret;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
564

45449980f   Rob Clark   fs/fat: split out...
565
566
  	ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize);
  	if (ret) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
567
568
  		debug("Error: reading boot sector
  ");
45449980f   Rob Clark   fs/fat: split out...
569
  		return ret;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
570
  	}
40e219165   Sergei Shtylyov   fat: root directo...
571
  	if (mydata->fatsize == 32) {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
572
  		mydata->fatlength = bs.fat32_length;
f23101f95   AKASHI Takahiro   fs: fat: extend g...
573
  		mydata->total_sect = bs.total_sect;
40e219165   Sergei Shtylyov   fat: root directo...
574
  	} else {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
575
  		mydata->fatlength = bs.fat_length;
f23101f95   AKASHI Takahiro   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   Sergei Shtylyov   fat: root directo...
579
  	}
f23101f95   AKASHI Takahiro   fs: fat: extend g...
580
581
  	if (!mydata->total_sect) /* unlikely */
  		mydata->total_sect = (u32)cur_part_info.size;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
582

f23101f95   AKASHI Takahiro   fs: fat: extend g...
583
  	mydata->fats = bs.fats;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
584
  	mydata->fat_sect = bs.reserved;
45449980f   Rob Clark   fs/fat: split out...
585
  	mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
586

ac4977719   Sergei Shtylyov   fat: fix crash wi...
587
  	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
588
  	mydata->clust_size = bs.cluster_size;
46236b140   Kyle Moffett   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   Patrick Wildt   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   Wolfgang Denk   fs/fat: Big code ...
608
609
610
611
  
  	if (mydata->fatsize == 32) {
  		mydata->data_begin = mydata->rootdir_sect -
  					(mydata->clust_size * 2);
c6e3baa56   Rob Clark   fs/fat: introduce...
612
  		mydata->root_cluster = bs.root_cluster;
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
613
  	} else {
45449980f   Rob Clark   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   Wolfgang Denk   fs/fat: Big code ...
618
  		mydata->data_begin = mydata->rootdir_sect +
45449980f   Rob Clark   fs/fat: split out...
619
  					mydata->rootdir_size -
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
620
  					(mydata->clust_size * 2);
9b18358dc   Anssi Hannula   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   Wolfgang Denk   fs/fat: Big code ...
628
629
630
  	}
  
  	mydata->fatbufnum = -1;
3c0ed9c3a   Stefan Brüns   fs/fat: Do not wr...
631
  	mydata->fat_dirty = 0;
09fa964bb   Tuomas Tynkkynen   fs/fat: Fix 'CACH...
632
  	mydata->fatbuf = malloc_cache_aligned(FATBUFSIZE);
ac4977719   Sergei Shtylyov   fat: fix crash wi...
633
634
635
636
637
  	if (mydata->fatbuf == NULL) {
  		debug("Error: allocating memory
  ");
  		return -1;
  	}
71f951180   wdenk   * Fix CONFIG_NET_...
638

7385c28e9   Wolfgang Denk   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   Rob Clark   fs/fat: introduce...
646
  	       mydata->root_cluster,
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
647
  	       mydata->rootdir_sect,
ac4977719   Sergei Shtylyov   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   Wolfgang Denk   fs/fat: Big code ...
652

45449980f   Rob Clark   fs/fat: split out...
653
654
  	return 0;
  }
c6e3baa56   Rob Clark   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   AKASHI Takahiro   fs: fat: remember...
677
  	unsigned   start_clust;   /* first cluster */
c6e3baa56   Rob Clark   fs/fat: introduce...
678
  	unsigned   clust;         /* current cluster */
f528c140c   AKASHI Takahiro   fs: fat: assure i...
679
  	unsigned   next_clust;    /* next cluster if remaining == 0 */
c6e3baa56   Rob Clark   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   AKASHI Takahiro   fs: fat: remember...
710
  	itr->start_clust = 0;
c6e3baa56   Rob Clark   fs/fat: introduce...
711
  	itr->clust = fsdata->root_cluster;
f528c140c   AKASHI Takahiro   fs: fat: assure i...
712
  	itr->next_clust = fsdata->root_cluster;
c6e3baa56   Rob Clark   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   AKASHI Takahiro   fs: fat: remember...
746
  	itr->start_clust = clustnum;
c6e3baa56   Rob Clark   fs/fat: introduce...
747
748
  	if (clustnum > 0) {
  		itr->clust = clustnum;
f528c140c   AKASHI Takahiro   fs: fat: assure i...
749
  		itr->next_clust = clustnum;
8df873147   Tuomas Tynkkynen   fs/fat: Fix pathn...
750
  		itr->is_root = 0;
c6e3baa56   Rob Clark   fs/fat: introduce...
751
752
  	} else {
  		itr->clust = parent->fsdata->root_cluster;
f528c140c   AKASHI Takahiro   fs: fat: assure i...
753
  		itr->next_clust = parent->fsdata->root_cluster;
8df873147   Tuomas Tynkkynen   fs/fat: Fix pathn...
754
  		itr->is_root = 1;
c6e3baa56   Rob Clark   fs/fat: introduce...
755
756
757
758
  	}
  	itr->dent = NULL;
  	itr->remaining = 0;
  	itr->last_cluster = 0;
c6e3baa56   Rob Clark   fs/fat: introduce...
759
  }
9b18358dc   Anssi Hannula   fs: fat: fix read...
760
  static void *next_cluster(fat_itr *itr, unsigned *nbytes)
c6e3baa56   Rob Clark   fs/fat: introduce...
761
762
763
764
  {
  	fsdata *mydata = itr->fsdata;  /* for silly macros */
  	int ret;
  	u32 sect;
9b18358dc   Anssi Hannula   fs: fat: fix read...
765
  	u32 read_size;
c6e3baa56   Rob Clark   fs/fat: introduce...
766
767
768
769
  
  	/* have we reached the end? */
  	if (itr->last_cluster)
  		return NULL;
9b18358dc   Anssi Hannula   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   Rob Clark   fs/fat: introduce...
788

9b18358dc   Anssi Hannula   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   Rob Clark   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   Anssi Hannula   fs: fat: fix read...
802
  	ret = disk_read(sect, read_size, itr->block);
c6e3baa56   Rob Clark   fs/fat: introduce...
803
804
805
806
807
  	if (ret < 0) {
  		debug("Error: reading block
  ");
  		return NULL;
  	}
9b18358dc   Anssi Hannula   fs: fat: fix read...
808
  	*nbytes = read_size * itr->fsdata->sect_size;
f528c140c   AKASHI Takahiro   fs: fat: assure i...
809
  	itr->clust = itr->next_clust;
c6e3baa56   Rob Clark   fs/fat: introduce...
810
  	if (itr->is_root && itr->fsdata->fatsize != 32) {
f528c140c   AKASHI Takahiro   fs: fat: assure i...
811
  		itr->next_clust++;
9b18358dc   Anssi Hannula   fs: fat: fix read...
812
  		if (itr->next_clust * itr->fsdata->clust_size >=
c6e3baa56   Rob Clark   fs/fat: introduce...
813
  		    itr->fsdata->rootdir_size) {
f528c140c   AKASHI Takahiro   fs: fat: assure i...
814
815
  			debug("nextclust: 0x%x
  ", itr->next_clust);
c6e3baa56   Rob Clark   fs/fat: introduce...
816
817
818
  			itr->last_cluster = 1;
  		}
  	} else {
f528c140c   AKASHI Takahiro   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   Rob Clark   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   Anssi Hannula   fs: fat: fix read...
833
834
  		unsigned nbytes;
  		struct dir_entry *dent = next_cluster(itr, &nbytes);
c6e3baa56   Rob Clark   fs/fat: introduce...
835
836
  
  		/* have we reached the last cluster? */
f528c140c   AKASHI Takahiro   fs: fat: assure i...
837
838
839
  		if (!dent) {
  			/* a sign for no more entries left */
  			itr->dent = NULL;
c6e3baa56   Rob Clark   fs/fat: introduce...
840
  			return NULL;
f528c140c   AKASHI Takahiro   fs: fat: assure i...
841
  		}
c6e3baa56   Rob Clark   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   Patrick Wildt   fs: fix FAT name ...
869
870
  		if (n + idx >= sizeof(itr->l_name))
  			return NULL;
c6e3baa56   Rob Clark   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   AKASHI Takahiro   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   Rob Clark   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   AKASHI Takahiro   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   Rob Clark   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   Tuomas Tynkkynen   fs: fat: Drop CON...
935
  			if ((dent->attr & ATTR_VFAT) == ATTR_VFAT &&
c6e3baa56   Rob Clark   fs/fat: introduce...
936
  			    (dent->name[0] & LAST_LONG_ENTRY_MASK)) {
39606d462   AKASHI Takahiro   fs: fat: handle d...
937
  				/* long file name */
c6e3baa56   Rob Clark   fs/fat: introduce...
938
  				dent = extract_vfat_name(itr);
39606d462   AKASHI Takahiro   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   Rob Clark   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   AKASHI Takahiro   fs: fat: handle d...
956
957
958
  		} else if (!(dent->attr & ATTR_ARCH) &&
  			   !(dent->attr & ATTR_DIR))
  			continue;
c6e3baa56   Rob Clark   fs/fat: introduce...
959

39606d462   AKASHI Takahiro   fs: fat: handle d...
960
  		/* short file name */
c6e3baa56   Rob Clark   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   AKASHI Takahiro   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   AKASHI Takahiro   fs: fat: assure i...
1030
  			itr->next_clust = itr->fsdata->root_cluster;
b94b6be54   AKASHI Takahiro   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   Rob Clark   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   Benoît Thébaudeau   FAT: cosmetic: Re...
1080
  int file_fat_detectfs(void)
71f951180   wdenk   * Fix CONFIG_NET_...
1081
  {
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1082
1083
1084
1085
  	boot_sector bs;
  	volume_info volinfo;
  	int fatsize;
  	char vol_label[12];
71f951180   wdenk   * Fix CONFIG_NET_...
1086

7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1087
  	if (cur_dev == NULL) {
7205e4075   wdenk   * Patches by Deni...
1088
1089
1090
1091
  		printf("No current device
  ");
  		return 1;
  	}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1092

fc843a02a   Simon Glass   Kconfig: Add a CO...
1093
  #if defined(CONFIG_IDE) || \
10e40d54b   Simon Glass   Kconfig: Add CONF...
1094
      defined(CONFIG_SATA) || \
c649e3c91   Simon Glass   dm: scsi: Rename ...
1095
      defined(CONFIG_SCSI) || \
dd60d1223   Jon Loeliger   fs/: Remove obsol...
1096
      defined(CONFIG_CMD_USB) || \
21f6f9636   Andy Fleming   Fix CONFIG_MMC us...
1097
      defined(CONFIG_MMC)
7205e4075   wdenk   * Patches by Deni...
1098
  	printf("Interface:  ");
7385c28e9   Wolfgang Denk   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   wdenk   * Patches by Deni...
1123
  	}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1124

bcce53d04   Simon Glass   dm: block: Rename...
1125
1126
  	printf("
    Device %d: ", cur_dev->devnum);
7205e4075   wdenk   * Patches by Deni...
1127
1128
  	dev_print(cur_dev);
  #endif
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1129
1130
  
  	if (read_bootsectandvi(&bs, &volinfo, &fatsize)) {
7205e4075   wdenk   * Patches by Deni...
1131
1132
1133
1134
1135
  		printf("
  No valid FAT fs found
  ");
  		return 1;
  	}
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1136
1137
  
  	memcpy(vol_label, volinfo.volume_label, 11);
7205e4075   wdenk   * Patches by Deni...
1138
  	vol_label[11] = '\0';
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1139
  	volinfo.fs_type[5] = '\0';
461f86e69   Stephen Warren   FAT: remove cur_p...
1140
1141
  	printf("Filesystem: %s \"%s\"
  ", volinfo.fs_type, vol_label);
7385c28e9   Wolfgang Denk   fs/fat: Big code ...
1142

7205e4075   wdenk   * Patches by Deni...
1143
  	return 0;
71f951180   wdenk   * Fix CONFIG_NET_...
1144
  }
b7b5f3195   Stephen Warren   fat: implement ex...
1145
1146
  int fat_exists(const char *filename)
  {
8eafae209   Rob Clark   fat/fs: convert t...
1147
  	fsdata fsdata;
2460098cf   Tom Rini   fs/fat: Reduce st...
1148
  	fat_itr *itr;
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
1149
  	int ret;
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
1150

09fa964bb   Tuomas Tynkkynen   fs/fat: Fix 'CACH...
1151
  	itr = malloc_cache_aligned(sizeof(fat_itr));
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1152
1153
  	if (!itr)
  		return 0;
8eafae209   Rob Clark   fat/fs: convert t...
1154
1155
  	ret = fat_itr_root(itr, &fsdata);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1156
  		goto out;
8eafae209   Rob Clark   fat/fs: convert t...
1157
1158
  
  	ret = fat_itr_resolve(itr, filename, TYPE_ANY);
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1159
  	free(fsdata.fatbuf);
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1160
  out:
2460098cf   Tom Rini   fs/fat: Reduce st...
1161
  	free(itr);
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
1162
  	return ret == 0;
b7b5f3195   Stephen Warren   fat: implement ex...
1163
  }
d455d8789   Suriyan Ramasami   fs: API changes e...
1164
  int fat_size(const char *filename, loff_t *size)
cf6598193   Stephen Warren   fs: implement siz...
1165
  {
8eafae209   Rob Clark   fat/fs: convert t...
1166
  	fsdata fsdata;
2460098cf   Tom Rini   fs/fat: Reduce st...
1167
  	fat_itr *itr;
8eafae209   Rob Clark   fat/fs: convert t...
1168
  	int ret;
09fa964bb   Tuomas Tynkkynen   fs/fat: Fix 'CACH...
1169
  	itr = malloc_cache_aligned(sizeof(fat_itr));
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1170
1171
  	if (!itr)
  		return -ENOMEM;
8eafae209   Rob Clark   fat/fs: convert t...
1172
1173
  	ret = fat_itr_root(itr, &fsdata);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1174
  		goto out_free_itr;
8eafae209   Rob Clark   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   Rob Clark   fs/fat: fix fatbu...
1182
  		free(fsdata.fatbuf);
d0cd30eb8   Andrew F. Davis   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   Rob Clark   fat/fs: convert t...
1188
  			*size = 0;
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1189
  		goto out_free_both;
8eafae209   Rob Clark   fat/fs: convert t...
1190
1191
1192
  	}
  
  	*size = FAT2CPU32(itr->dent->size);
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1193
  out_free_both:
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1194
  	free(fsdata.fatbuf);
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1195
  out_free_itr:
2460098cf   Tom Rini   fs/fat: Reduce st...
1196
  	free(itr);
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1197
  	return ret;
cf6598193   Stephen Warren   fs: implement siz...
1198
  }
1ad0b98a0   Suriyan Ramasami   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   wdenk   * Fix CONFIG_NET_...
1201
  {
8eafae209   Rob Clark   fat/fs: convert t...
1202
  	fsdata fsdata;
2460098cf   Tom Rini   fs/fat: Reduce st...
1203
  	fat_itr *itr;
8eafae209   Rob Clark   fat/fs: convert t...
1204
  	int ret;
09fa964bb   Tuomas Tynkkynen   fs/fat: Fix 'CACH...
1205
  	itr = malloc_cache_aligned(sizeof(fat_itr));
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1206
1207
  	if (!itr)
  		return -ENOMEM;
8eafae209   Rob Clark   fat/fs: convert t...
1208
1209
  	ret = fat_itr_root(itr, &fsdata);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1210
  		goto out_free_itr;
8eafae209   Rob Clark   fat/fs: convert t...
1211
1212
1213
  
  	ret = fat_itr_resolve(itr, filename, TYPE_FILE);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1214
  		goto out_free_both;
8eafae209   Rob Clark   fat/fs: convert t...
1215

287c04e11   Andreas Dannenberg   fs/fat: debug-pri...
1216
1217
  	debug("reading %s at pos %llu
  ", filename, pos);
e48485f5e   Tien Fong Chee   fs: fat: Reduce d...
1218
1219
1220
  
  	/* For saving default max clustersize memory allocated to malloc pool */
  	dir_entry *dentptr = itr->dent;
e48485f5e   Tien Fong Chee   fs: fat: Reduce d...
1221
  	ret = get_contents(&fsdata, dentptr, pos, buffer, maxsize, actread);
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1222

af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1223
  out_free_both:
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1224
  	free(fsdata.fatbuf);
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1225
  out_free_itr:
2460098cf   Tom Rini   fs/fat: Reduce st...
1226
  	free(itr);
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1227
  	return ret;
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
1228
  }
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
1229
  int file_fat_read(const char *filename, void *buffer, int maxsize)
1170e634d   Benoît Thébaudeau   FAT: Make it poss...
1230
  {
1ad0b98a0   Suriyan Ramasami   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   wdenk   * Fix CONFIG_NET_...
1239
  }
e6d524153   Simon Glass   fs: Move ls and r...
1240

d455d8789   Suriyan Ramasami   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   Simon Glass   fs: Move ls and r...
1243
  {
1ad0b98a0   Suriyan Ramasami   fat: Prepare API ...
1244
  	int ret;
e6d524153   Simon Glass   fs: Move ls and r...
1245

d455d8789   Suriyan Ramasami   fs: API changes e...
1246
1247
  	ret = file_fat_read_at(filename, offset, buf, len, actread);
  	if (ret)
e6d524153   Simon Glass   fs: Move ls and r...
1248
1249
  		printf("** Unable to read file %s **
  ", filename);
e6d524153   Simon Glass   fs: Move ls and r...
1250

d455d8789   Suriyan Ramasami   fs: API changes e...
1251
  	return ret;
e6d524153   Simon Glass   fs: Move ls and r...
1252
  }
1f40366b3   Rob Clark   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   Neil Armstrong   fat: Use cache al...
1262
  	fat_dir *dir;
1f40366b3   Rob Clark   fs/fat: implement...
1263
  	int ret;
34dd853ce   Neil Armstrong   fat: Use cache al...
1264
  	dir = malloc_cache_aligned(sizeof(*dir));
1f40366b3   Rob Clark   fs/fat: implement...
1265
1266
  	if (!dir)
  		return -ENOMEM;
34dd853ce   Neil Armstrong   fat: Use cache al...
1267
  	memset(dir, 0, sizeof(*dir));
1f40366b3   Rob Clark   fs/fat: implement...
1268
1269
1270
  
  	ret = fat_itr_root(&dir->itr, &dir->fsdata);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1271
  		goto fail_free_dir;
1f40366b3   Rob Clark   fs/fat: implement...
1272
1273
1274
  
  	ret = fat_itr_resolve(&dir->itr, filename, TYPE_DIR);
  	if (ret)
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1275
  		goto fail_free_both;
1f40366b3   Rob Clark   fs/fat: implement...
1276
1277
1278
  
  	*dirsp = (struct fs_dir_stream *)dir;
  	return 0;
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1279
  fail_free_both:
725ffdb5c   Rob Clark   fs/fat: fix fatbu...
1280
  	free(dir->fsdata.fatbuf);
af609e376   Tuomas Tynkkynen   fs/fat: Check mal...
1281
  fail_free_dir:
1f40366b3   Rob Clark   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   Rob Clark   fs/fat: fix fatbu...
1312
  	free(dir->fsdata.fatbuf);
1f40366b3   Rob Clark   fs/fat: implement...
1313
1314
  	free(dir);
  }
e6d524153   Simon Glass   fs: Move ls and r...
1315
1316
1317
  void fat_close(void)
  {
  }