// SPDX-License-Identifier: GPL-2.0+ /* * exfat.c * * exFAT filesystem implementation */ #include #include //new #include #include #include #include #include #include #include #include //new #include #include /* * 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) { }