nt9856x/BSP/u-boot/fs/exfat/exfat.c
2023-03-28 15:07:53 +08:00

1047 lines
24 KiB
C
Executable File

// SPDX-License-Identifier: GPL-2.0+
/*
* exfat.c
*
* exFAT filesystem implementation
*/
#include <common.h>
#include <blk.h> //new
#include <config.h>
#include <exports.h>
#include <exfat.h>
#include <fs.h>
#include <asm/byteorder.h>
#include <part.h>
#include <malloc.h>
#include <memalign.h> //new
#include <linux/compiler.h>
#include <linux/ctype.h>
/*
* Convert a string to lowercase. Converts at most 'len' characters,
* 'len' may be larger than the length of 'str' if 'str' is NULL
* terminated.
*/
static void downcase(char *str, size_t len)
{
while (*str != '\0' && len--) {
*str = tolower(*str);
str++;
}
}
static struct blk_desc *cur_dev;
static disk_partition_t cur_part_info;
#define DOS_BOOT_MAGIC_OFFSET 0x1fe
#define DOS_FS_TYPE_OFFSET 0x36
#define DOS_FS32_TYPE_OFFSET 0x52
#define DOS_EXFAT_TYPE_OFFSET 0x3
static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
{
ulong ret;
if (!cur_dev)
return -1;
ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf);
if (ret != nr_blocks)
return -1;
return ret;
}
int exfat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
{
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
cur_dev = dev_desc;
cur_part_info = *info;
/* Make sure it has a valid FAT header */
if (disk_read(0, 1, buffer) != 1) {
cur_dev = NULL;
return -1;
}
/* 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 exFAT filesystem */
if (!memcmp(buffer + DOS_EXFAT_TYPE_OFFSET, EXFAT_SIGN, 8))
return 0;
cur_dev = NULL;
return -1;
}
int exfat_register_device(struct blk_desc *dev_desc, int part_no)
{
disk_partition_t info;
/* First close any currently found FAT filesystem */
cur_dev = NULL;
/* Read the partition table, if present */
if (part_get_info(dev_desc, part_no, &info)) {
if (part_no != 0) {
printf("** Partition %d not valid on device %d **\n",
part_no, dev_desc->devnum);
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;
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
info.uuid[0] = 0;
#endif
}
return exfat_set_blk_dev(dev_desc, &info);
}
/*
* Get the first occurence of a directory delimiter ('/' or '\') in a string.
* Return index into string if found, -1 otherwise.
*/
static int dirdelim(char *str)
{
char *start = str;
while (*str != '\0') {
if (ISDIRDELIM(*str))
return str - start;
str++;
}
return -1;
}
static int flush_dirty_exfat_buffer(exfat_fsdata *mydata);
#if !CONFIG_IS_ENABLED(EXFAT_WRITE)
/* Stub for read only operation */
int flush_dirty_exfat_buffer(exfat_fsdata *mydata)
{
(void)(mydata);
return 0;
}
#endif
/*
* Get the entry at index 'entry' in a exFAT table.
* On failure 0x00 is returned.
*/
static __u32 exfat_get_fatent(exfat_fsdata *mydata, __u32 entry, exfat_stream_dentry *strmptr)
{
__u32 bufnum;
__u32 offset;
__u32 ret = 0x00;
// new
if (CHECK_CLUST(entry, mydata->fatsize)) {
printf("Error: Invalid FAT entry: 0x%08x\n", entry);
return ret;
}
switch (mydata->fatsize) {
case 32:
bufnum = entry / EXFATBUFSIZE;
offset = entry - bufnum * EXFATBUFSIZE;
break;
default:
/* Unsupported FAT size */
return ret;
}
debug("FAT%d: entry: 0x%08x = %d, offset: 0x%04x = %d\n",
mydata->fatsize, entry, entry, offset, offset);
if (strmptr && EXFAT_IS_CONTIGUOUS(strmptr)) {
__u32 first_clus;
__u32 clus_count;
unsigned long filesize = (unsigned long)EXFAT_SIZE(strmptr); //can not use __u64 division, or compile will failed
//(limitation: file size should not exceed 4GB)
first_clus = EXFAT_SIZE(strmptr);
clus_count = (filesize + mydata->sect_size * mydata->clust_size - 1) / (mydata->sect_size * mydata->clust_size);
if (entry < (first_clus + clus_count - 1)) {
// startClus can get next cluster , but should in Cluscount
ret = entry + 1 ;
} else {
//DBG_IND(" Cluster out of range is FirstClus = 0X%X ,StartClus = 0x%X , ClusCount = 0x%X \r\n" ,FirstClus ,StartClus, ClusCount);
ret = 0xFFFFFFFF;
}
return ret;
}
/* Read a new block of FAT entries into the cache. */
if (bufnum != mydata->fatbufnum) {
__u32 getsize = FATBUFBLOCKS;
__u8 *bufptr = mydata->fatbuf;
__u32 fatlength = mydata->fatlength;
__u32 startblock = bufnum * FATBUFBLOCKS;
if (startblock + getsize > fatlength)
getsize = fatlength - startblock;
startblock += mydata->fat_sect; /* Offset from start of disk */
/* Write back the fatbuf to the disk */
if (flush_dirty_exfat_buffer(mydata) < 0)
return -1;
if (disk_read(startblock, getsize, bufptr) < 0) {
debug("Error reading FAT blocks\n");
return ret;
}
mydata->fatbufnum = bufnum;
}
/* Get the actual entry from the table */
switch (mydata->fatsize) {
case 32:
ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
break;
}
debug("FAT%d: ret: %08x, entry: 0x%08x, offset: %04x\n",
mydata->fatsize, ret, entry, offset);
return ret;
}
/*
* Read at most 'size' bytes from the specified cluster into 'buffer'.
* Return 0 on success, -1 otherwise.
*/
static int
exfat_get_cluster(exfat_fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
{
__u32 idx = 0;
__u32 startsect;
int ret;
if (clustnum > 0) {
/* startsect = mydata->data_begin +
clustnum * mydata->clust_size; */
startsect = exfat_clust_to_sect(mydata, clustnum);
} else {
startsect = mydata->rootdir_sect;
}
debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
debug("FAT: Misaligned buffer address (%p)\n", buffer);
while (size >= mydata->sect_size) {
ret = disk_read(startsect++, 1, tmpbuf);
if (ret != 1) {
debug("Error reading data (got %d)\n", ret);
return -1;
}
memcpy(buffer, tmpbuf, mydata->sect_size);
buffer += mydata->sect_size;
size -= mydata->sect_size;
}
} else {
idx = size / mydata->sect_size;
ret = disk_read(startsect, idx, buffer);
if (ret != idx) {
debug("Error reading data (got %d)\n", 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);
if (ret != 1) {
debug("Error reading data (got %d)\n", ret);
return -1;
}
memcpy(buffer, tmpbuf, size);
}
return 0;
}
/*
* Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr'
* into 'buffer'.
* Update the number of bytes read in *gotsize or return -1 on fatal errors.
*/
/*
__u8 get_contents_vexfatname_block[EXFAT_MAX_CLUSTSIZE]
__aligned(ARCH_DMA_MINALIGN);
*/
static long
exfat_get_contents(exfat_fsdata *mydata, exfat_stream_dentry *strmptr, loff_t pos,
__u8 *buffer, loff_t maxsize)
{
loff_t filesize = EXFAT_SIZE(strmptr), gotsize = 0;
unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
__u32 curclust = EXFAT_START(strmptr);
__u32 endclust, newclust;
loff_t actsize;
debug("Filesize: %llu bytes\n", filesize);
if (EXFAT_SIZE(strmptr) >= 0xFFFFFFFFULL) {
debug("size too large\r\n");
return -1;
}
if (pos >= filesize) {
debug("Read position past EOF: %llu\n", pos);
return gotsize;
}
if (maxsize > 0 && filesize > pos + maxsize)
filesize = pos + maxsize;
debug("%llu bytes\n", filesize);
actsize = bytesperclust;
/* go to cluster at pos */
while (actsize <= pos) {
curclust = exfat_get_fatent(mydata, curclust, strmptr);
if (CHECK_CLUST(curclust, mydata->fatsize)) {
debug("curclust: 0x%x\n", curclust);
debug("Invalid FAT entry\n");
return gotsize;
}
actsize += bytesperclust;
}
/* actsize > pos */
actsize -= bytesperclust;
filesize -= actsize;
pos -= actsize;
/* align to beginning of next cluster if any */
if (pos) {
__u8 *tmp_buffer;
actsize = min(filesize, (loff_t)bytesperclust);
tmp_buffer = malloc_cache_aligned(actsize);
if (!tmp_buffer) {
debug("Error: allocating buffer\n");
return -ENOMEM;
}
if (exfat_get_cluster(mydata, curclust, tmp_buffer, actsize) != 0) {
printf("Error reading cluster\n");
free(tmp_buffer);
return -1;
}
filesize -= actsize;
actsize -= pos;
memcpy(buffer, tmp_buffer + pos, actsize);
free(tmp_buffer);
gotsize += actsize;
if (!filesize)
return gotsize;
buffer += actsize;
curclust = exfat_get_fatent(mydata, curclust, strmptr);
if (CHECK_CLUST(curclust, mydata->fatsize)) {
debug("curclust: 0x%x\n", curclust);
debug("Invalid FAT entry\n");
return gotsize;
}
}
actsize = bytesperclust;
endclust = curclust;
do {
/* search for consecutive clusters */
while (actsize < filesize) {
newclust = exfat_get_fatent(mydata, endclust, strmptr);
if ((newclust - 1) != endclust)
goto getit;
if (CHECK_CLUST(newclust, mydata->fatsize)) {
debug("curclust: 0x%x\n", newclust);
debug("Invalid FAT entry\n");
return gotsize;
}
endclust = newclust;
actsize += bytesperclust;
}
/* get remaining bytes */
actsize = filesize;
if (exfat_get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
printf("Error reading cluster\n");
return -1;
}
gotsize += actsize;
return gotsize;
getit:
if (exfat_get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
printf("Error reading cluster\n");
return -1;
}
gotsize += (int)actsize;
filesize -= actsize;
buffer += actsize;
curclust = exfat_get_fatent(mydata, endclust, strmptr);
if (CHECK_CLUST(curclust, mydata->fatsize)) {
debug("curclust: 0x%x\n", curclust);
printf("Invalid FAT entry\n");
return gotsize;
}
actsize = bytesperclust;
endclust = curclust;
} while (1);
}
/*
* 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.
*/
static int exfat_slot2str(exfat_name_dentry *slotptr, char *l_name, int *idx)
{
int i;
for (i = 0; i < EXFAT_NAME_ENTRY_MAXCHAR; i++) {
if (slotptr->name[i] > 0x80)
printf("NON-ASCII code 0x%X\r\n", slotptr->name[i]);
if (slotptr->entry_type != EXFAT_ENTRY_TYPE_NAME)
return 0;
l_name[*idx] = (char)slotptr->name[i];
if (l_name[*idx] == 0x00)
return 1;
(*idx)++;
}
return 0;
}
//Note: Only supports ASCII filename
static int
get_exfatname(exfat_fsdata *mydata, int curclust, __u8 *buf_head,
exfat_entry_set *curdent, char *l_name, exfat_stream_dentry *ret_strmptr)
{
exfat_name_dentry *name_deptr = &curdent->name_dentry[0];
exfat_stream_dentry *strm_deptr = &curdent->stream_dentry;
__u8 *buflimit = buf_head + mydata->sect_size * ((curclust == 0) ?
EXFAT_PREFETCH_BLOCKS :
mydata->clust_size);
//__u8 counter = (curdent->stream_dentry.name_len + EXFAT_NAME_ENTRY_MAXCHAR - 1) / EXFAT_NAME_ENTRY_MAXCHAR;
__u8 counter = (curdent->file_dentry.second_count - 1); //second_count excludes the stream entry
int idx = 0;
if (counter > EXFAT_NAME_ENTRY_MAXNUM) {
debug("Error: EXFAT name is too long\n");
return -1;
}
while (counter) {
if ((__u8 *)name_deptr >= buflimit) {
exfat_name_dentry *name_deptr2;
__u8 *tmp_buffer;
if (curclust == 0)
return -1;
curclust = exfat_get_fatent(mydata, curclust, NULL);
if (CHECK_CLUST(curclust, mydata->fatsize)) {
debug("curclust: 0x%x\n", curclust);
printf("Invalid FAT entry\n");
return -1;
}
tmp_buffer = malloc_cache_aligned(mydata->clust_size * mydata->sect_size);
if (!tmp_buffer) {
debug("Error: allocating buffer\n");
return -ENOMEM;
}
if (exfat_get_cluster(mydata, curclust, tmp_buffer,
mydata->clust_size * mydata->sect_size) != 0) {
debug("Error: reading directory block\n");
return -1;
}
name_deptr2 = (exfat_name_dentry *)(tmp_buffer + ((__u8 *)name_deptr - buflimit));
while (counter) {
exfat_slot2str(name_deptr2, l_name, &idx);
name_deptr2++;
counter--;
}
free(tmp_buffer);
} else {
exfat_slot2str(name_deptr, l_name, &idx);
name_deptr++;
counter--;
}
}
l_name[idx] = '\0';
downcase(l_name, EXFAT_MAXLEN_BYTES);
if ((__u8 *)strm_deptr < buflimit) {
memcpy(ret_strmptr, strm_deptr, sizeof(exfat_stream_dentry));
} else {
__u8 *tmp_buffer;
tmp_buffer = malloc_cache_aligned(sizeof(exfat_stream_dentry));
if (!tmp_buffer) {
debug("Error: allocating buffer\n");
return -ENOMEM;
}
memcpy(ret_strmptr, tmp_buffer, sizeof(exfat_stream_dentry));
free(tmp_buffer);
}
return 0;
}
/*
* Read boot sector and volume info from a FAT filesystem
*/
static int
exfat_read_bootsectandvi(exfat_boot_sector *bs, exfat_volume_info *volinfo, int *fatsize)
{
__u8 *block;
int ret = 0;
if (cur_dev == NULL) {
debug("Error: no device selected\n");
return -1;
}
/* block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz); */
block = malloc_cache_aligned(cur_dev->blksz); //new
if (block == NULL) {
debug("Error: allocating block\n");
return -1;
}
if (disk_read(0, 1, block) < 0) {
debug("Error: reading block\n");
goto fail;
}
//dump_buf(block, 512);
memcpy(bs, block, sizeof(exfat_boot_sector));
bs->partition_offset[0] = FAT2CPU32(bs->partition_offset[0]);
bs->partition_offset[1] = FAT2CPU32(bs->partition_offset[1]);
bs->volume_length[0] = FAT2CPU32(bs->volume_length[0]);
bs->volume_length[1] = FAT2CPU32(bs->volume_length[1]);
bs->fat_offset = FAT2CPU32(bs->fat_offset);
bs->fat_length = FAT2CPU32(bs->fat_length);
bs->cluster_heap_offset = FAT2CPU32(bs->cluster_heap_offset);
bs->cluster_count = FAT2CPU32(bs->cluster_count);
bs->first_clus_of_root_dir = FAT2CPU32(bs->first_clus_of_root_dir);
bs->volume_serial_number = FAT2CPU32(bs->volume_serial_number);
bs->file_system_revision = FAT2CPU16(bs->file_system_revision);
bs->volume_flags = FAT2CPU16(bs->volume_flags);
*fatsize = 32;
memcpy(volinfo->fs_type, bs->file_system_name, sizeof(bs->file_system_name));
if (strncmp(EXFAT_SIGN, bs->file_system_name, EXFAT_SIGNLEN) == 0)
goto exit;
debug("Error: broken fs_type sign\n");
fail:
ret = -1;
exit:
free(block);
return ret;
}
__u8 do_exfat_read_at_block[EXFAT_MAX_CLUSTSIZE]
__aligned(ARCH_DMA_MINALIGN);
long
do_exfat_read_at(const char *filename, loff_t pos, void *buffer,
loff_t maxsize, int dols, int dogetsize)
{
char fnamecopy[2048];
exfat_boot_sector bs;
exfat_volume_info volinfo;
exfat_fsdata datablock;
exfat_fsdata *mydata = &datablock;
//exfat_dir_entry *dentptr = NULL;
exfat_entry_set *exdentptr = NULL;
exfat_stream_dentry strmdent;
//char *subname = "";
__u32 cursect;
int idx, isdir = 0;
int files = 0, dirs = 0;
long ret = -1;
//int firsttime;
__u32 root_cluster = 0;
int j;
int sect_per_clus;
if (exfat_read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
debug("Error: reading boot sector\n");
return -1;
}
sect_per_clus = 1 << bs.sector_per_clus_shift;
root_cluster = bs.first_clus_of_root_dir;
mydata->fatlength = bs.fat_length;
mydata->fat_sect = bs.fat_offset;
mydata->fats = bs.number_of_fats;
cursect = mydata->rootdir_sect
= bs.cluster_heap_offset + (bs.first_clus_of_root_dir - 2) * sect_per_clus;
mydata->sect_size = 1 << bs.byte_per_sector_shift;
mydata->clust_size = sect_per_clus;
if (mydata->sect_size != cur_part_info.blksz) {
printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n",
mydata->sect_size, cur_part_info.blksz);
return -1;
}
if (mydata->clust_size * mydata->sect_size > EXFAT_MAX_CLUSTSIZE) {
printf("Error: clust_size(%d) > MAX(%d) bytes\n",
mydata->clust_size * mydata->sect_size, EXFAT_MAX_CLUSTSIZE);
return -1;
}
mydata->data_begin = mydata->rootdir_sect - (mydata->clust_size * root_cluster); //relative to root cluster
mydata->fatbufnum = -1;
mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
if (mydata->fatbuf == NULL) {
debug("Error: allocating memory\n");
return -1;
}
//if (vfat_enabled)
// debug("VFAT Support enabled\n");
debug("FAT%d, fat_sect: %d, fatlength: %d\n",
mydata->fatsize, mydata->fat_sect, mydata->fatlength);
debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n"
"Data begins at: %d\n",
root_cluster,
mydata->rootdir_sect,
mydata->rootdir_sect * mydata->sect_size, mydata->data_begin);
debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
mydata->clust_size);
/* "cwd" is always the root... */
while (ISDIRDELIM(*filename))
filename++;
/* Make a copy of the filename and convert it to lowercase */
strcpy(fnamecopy, filename);
downcase(fnamecopy, 2048);
if (*fnamecopy == '\0') {
if (!dols)
goto exit;
dols = LS_ROOT;
} else if ((idx = dirdelim(fnamecopy)) >= 0) {
#if 1
printf("Error: Only supports root files\r\n");
goto exit;
#else
isdir = 1;
fnamecopy[idx] = '\0';
subname = fnamecopy + idx + 1;
/* Handle multiple delimiters */
while (ISDIRDELIM(*subname))
subname++;
#endif
} else if (dols) {
isdir = 1;
}
j = 0;
while (1) {
int i;
if (j == 0) {
debug("FAT read sect=%d, clust_size=%d, EXDIRENTSPERBLOCK=%zd\n",
cursect, mydata->clust_size, EXFAT_DIRENTSPERBLOCK);
if (disk_read(cursect,
mydata->clust_size,
do_exfat_read_at_block) < 0) {
debug("Error: reading rootdir block\n");
goto exit;
}
//dentptr = (exfat_dir_entry *) do_exfat_read_at_block;
exdentptr = (exfat_entry_set *) do_exfat_read_at_block;
}
for (i = 0; i < EXFAT_DIRENTSPERCLUST; i++) {
char l_name[EXFAT_MAXLEN_BYTES];
l_name[0] = '\0';
/*
if (dentptr->name[0] == DELETED_FLAG) {
dentptr++;
continue;
}
*/
if (exdentptr->file_dentry.entry_type == 0) { //search end
debug("RootDentname == NULL - %d\n", i);
if (dols == LS_ROOT) {
printf("\n%d file(s), %d dir(s)\n\n",
files, dirs);
ret = 0;
}
goto exit;
}
if (exdentptr->file_dentry.entry_type != EXFAT_ENTRY_TYPE_FILE) {
exdentptr = (exfat_entry_set *)((char *)exdentptr + EXFAT_SIZE_PER_ENTRY);
continue;
}
//dump_buf(exdentptr, 512);
get_exfatname(mydata,
root_cluster,
do_exfat_read_at_block,
exdentptr, l_name, &strmdent);
debug("Rootexfatname: |%s|\n", l_name);
if (dols == LS_ROOT) {
char dirc;
int doit = 0;
int isdir =
(exdentptr->file_dentry.attrib & ATTR_DIR);
if (isdir) {
dirs++;
dirc = '/';
doit = 1;
} else {
dirc = ' ';
if (l_name[0] != 0) {
files++;
doit = 1;
}
}
if (doit) {
if (dirc == ' ') {
printf(" %8lld %s%c\n",
EXFAT_SIZE(&strmdent),
l_name,
dirc);
} else {
printf(" %s%c\n",
l_name,
dirc);
}
}
exdentptr = (exfat_entry_set *)((char *)exdentptr + EXFAT_SIZE_PER_ENTRY);
continue;
} else { //not dols, should read a file
if (strcmp(fnamecopy, l_name)) {
debug("RootMismatch: %s|%s|\n", fnamecopy, l_name);
exdentptr = (exfat_entry_set *)((char *)exdentptr + EXFAT_SIZE_PER_ENTRY);
continue;
}
if (isdir && !(exdentptr->file_dentry.attrib & ATTR_DIR))
goto exit;
debug("RootName: %s", l_name);
debug(", start: 0x%x", EXFAT_START(&strmdent));
debug(", size: 0x%llx %s\n",
EXFAT_SIZE(&strmdent),
isdir ? "(DIR)" : "");
goto rootdir_done; /* We got a match */
}
}
debug("END LOOP: j=%d clust_size=%d\n", j,
mydata->clust_size);
/*
* we must fetch the entries for the next
* root directory clusters when a cluster has been
* completely processed.
*/
j += mydata->clust_size;
int rootdir_end = 0;
if (j == mydata->clust_size) {
int nxtsect = 0;
int nxt_clust = 0;
nxt_clust = exfat_get_fatent(mydata, root_cluster, NULL);
rootdir_end = EXFAT_CHECK_CLUST(nxt_clust, 32);
nxtsect = mydata->data_begin +
(nxt_clust * mydata->clust_size);
root_cluster = nxt_clust;
cursect = nxtsect;
j = 0;
}
/* If end of rootdir reached */
if (rootdir_end) {
if (dols == LS_ROOT) {
printf("\n%d file(s), %d dir(s)\n\n",
files, dirs);
ret = 0;
}
goto exit;
}
}
rootdir_done:
#if 1
if(dogetsize)
ret = EXFAT_SIZE(&strmdent);
else
ret = exfat_get_contents(mydata, &strmdent, pos, buffer, maxsize);
debug("Size: %lld, got: %ld\n", EXFAT_SIZE(&strmdent), ret);
//dump_buf(buffer, 512);
#else
firsttime = 1;
while (isdir) {
int startsect = mydata->data_begin
+ EXFAT_START(exdentptr) * mydata->clust_size;
exfat_dir_entry dent;
char *nextname = NULL;
dent = *dentptr;
dentptr = &dent;
idx = dirdelim(subname);
if (idx >= 0) {
subname[idx] = '\0';
nextname = subname + idx + 1;
/* Handle multiple delimiters */
while (ISDIRDELIM(*nextname))
nextname++;
if (dols && *nextname == '\0')
firsttime = 0;
} else {
if (dols && firsttime) {
firsttime = 0;
} else {
isdir = 0;
}
}
if (get_dentfromdir(mydata, startsect, subname, dentptr,
isdir ? 0 : dols) == NULL) {
if (dols && !isdir)
ret = 0;
goto exit;
}
if (isdir && !(dentptr->attr & ATTR_DIR))
goto exit;
if (idx >= 0)
subname = nextname;
}
if (dogetsize)
ret = FAT2CPU32(dentptr->size);
else
ret = get_contents(mydata, dentptr, pos, buffer, maxsize);
debug("Size: %d, got: %ld\n", FAT2CPU32(dentptr->size), ret);
#endif
exit:
free(mydata->fatbuf);
return ret;
}
long
do_exfat_read(const char *filename, void *buffer, loff_t maxsize, int dols)
{
return do_exfat_read_at(filename, 0, buffer, maxsize, dols, 0);
}
int file_exfat_detectfs(void)
{
exfat_boot_sector bs;
exfat_volume_info volinfo;
int fatsize;
char vol_label[12];
if (cur_dev == NULL) {
printf("No current device\n");
return 1;
}
#if defined(CONFIG_IDE) || \
defined(CONFIG_SATA) || \
defined(CONFIG_SCSI) || \
defined(CONFIG_CMD_USB) || \
defined(CONFIG_MMC)
printf("Interface: ");
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");
}
printf("\n Device %d: ", cur_dev->devnum);
dev_print(cur_dev);
#endif
if (exfat_read_bootsectandvi(&bs, &volinfo, &fatsize)) {
printf("\nNo valid FAT fs found\n");
return 1;
}
memcpy(vol_label, volinfo.volume_label, 11);
vol_label[11] = '\0';
volinfo.fs_type[5] = '\0';
printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label);
return 0;
}
int exfat_ls(const char *dir)
{
return do_exfat_read(dir, NULL, 0, LS_YES);
}
int exfat_exists(const char *filename)
{
long ret;
ret = do_exfat_read_at(filename, 0, NULL, 0, LS_NO, 1);
return ret >= 0;
}
int exfat_size(const char *filename, loff_t *size)
{
long ret;
*size = 0;
ret = do_exfat_read_at(filename, 0, NULL, 0, LS_NO, 1);
if (ret == -1) {
return -1;
}
*size = (loff_t)ret;
return 0;
}
int file_exfat_read_at(const char *filename, loff_t pos, void *buffer,
loff_t maxsize, loff_t *actread)
{
long ret = -1;
*actread = 0;
ret = do_exfat_read_at(filename, pos, buffer, maxsize, LS_NO, 0);
if (ret == -1) {
return -1;
}
*actread = (loff_t)ret;
return 0;
}
int file_exfat_read(const char *filename, void *buffer, int maxsize)
{
loff_t actread;
int ret;
ret = file_exfat_read_at(filename, 0, buffer, maxsize, &actread);
if (ret)
return ret;
else
return actread;
}
int exfat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actread)
{
int ret;
ret = file_exfat_read_at(filename, offset, buf, len, actread);
if (ret)
printf("** Unable to read file %s **\n", filename);
return ret;
}
int exfat_opendir(const char *filename, struct fs_dir_stream **dirsp)
{
return 0;
}
int exfat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp)
{
return 0;
}
void exfat_closedir(struct fs_dir_stream *dirs)
{
}
void exfat_close(void)
{
}