From 4393593e48b4768ba8cbd5519ace205a851b8820 Mon Sep 17 00:00:00 2001 From: Michael Theall Date: Tue, 5 Apr 2016 17:36:09 -0500 Subject: [PATCH] Add readdir batching to sdmc --- libctru/include/3ds/sdmc.h | 11 ++++++-- libctru/source/sdmc_dev.c | 53 ++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/libctru/include/3ds/sdmc.h b/libctru/include/3ds/sdmc.h index f648708..23bc799 100644 --- a/libctru/include/3ds/sdmc.h +++ b/libctru/include/3ds/sdmc.h @@ -4,14 +4,21 @@ */ #pragma once +#include + #include <3ds/types.h> #include <3ds/services/fs.h> +#define SDMC_DIRITER_MAGIC 0x73646D63 /* "sdmc" */ + /*! Open directory struct */ typedef struct { - Handle fd; /*! CTRU handle */ - FS_DirectoryEntry entry_data; /*! Temporary storage for reading entries */ + u32 magic; /*! "sdmc" */ + Handle fd; /*! CTRU handle */ + ssize_t index; /*! Current entry index */ + size_t size; /*! Current batch size */ + FS_DirectoryEntry entry_data[32]; /*! Temporary storage for reading entries */ } sdmc_dir_t; /// Initializes the SDMC driver. diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index 014c791..a0f84fd 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -939,8 +939,10 @@ sdmc_diropen(struct _reent *r, rc = FSUSER_OpenDirectory(&fd, sdmcArchive, fs_path); if(R_SUCCEEDED(rc)) { + dir->magic = SDMC_DIRITER_MAGIC; dir->fd = fd; memset(&dir->entry_data, 0, sizeof(dir->entry_data)); + dir->index = -1; return dirState; } @@ -980,35 +982,58 @@ sdmc_dirnext(struct _reent *r, char *filename, struct stat *filestat) { - Result rc; - u32 entries; - ssize_t units; + Result rc; + u32 entries; + ssize_t units; + FS_DirectoryEntry *entry; /* get pointer to our data */ sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); - /* fetch the next entry */ - memset(&dir->entry_data, 0, sizeof(dir->entry_data)); - rc = FSDIR_Read(dir->fd, &entries, 1, &dir->entry_data); + static const size_t max_entries = sizeof(dir->entry_data) / sizeof(dir->entry_data[0]); + + /* check if it's in the batch already */ + if(++dir->index < dir->size) + { + rc = 0; + } + else + { + /* reset batch info */ + dir->index = -1; + dir->size = 0; + + /* fetch the next batch */ + memset(dir->entry_data, 0, sizeof(dir->entry_data)); + rc = FSDIR_Read(dir->fd, &entries, max_entries, dir->entry_data); + if(R_SUCCEEDED(rc)) + { + if(entries == 0) + { + /* there are no more entries; ENOENT signals end-of-directory */ + r->_errno = ENOENT; + return -1; + } + + dir->index = 0; + dir->size = entries; + } + } + if(R_SUCCEEDED(rc)) { - if(entries == 0) - { - /* there are no more entries; ENOENT signals end-of-directory */ - r->_errno = ENOENT; - return -1; - } + entry = &dir->entry_data[dir->index]; /* fill in the stat info */ filestat->st_ino = 0; - if(dir->entry_data.attributes & FS_ATTRIBUTE_DIRECTORY) + if(entry->attributes & FS_ATTRIBUTE_DIRECTORY) filestat->st_mode = S_IFDIR; else filestat->st_mode = S_IFREG; /* convert name from UTF-16 to UTF-8 */ memset(filename, 0, NAME_MAX); - units = utf16_to_utf8((uint8_t*)filename, dir->entry_data.name, NAME_MAX); + units = utf16_to_utf8((uint8_t*)filename, entry->name, NAME_MAX); if(units < 0) { r->_errno = EILSEQ;