]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add readdir batching to sdmc
authorMichael Theall <pigman46@gmail.com>
Tue, 5 Apr 2016 22:36:09 +0000 (17:36 -0500)
committerMichael Theall <pigman46@gmail.com>
Tue, 5 Apr 2016 22:36:09 +0000 (17:36 -0500)
libctru/include/3ds/sdmc.h
libctru/source/sdmc_dev.c

index f648708c43a332db05a5c0d20a0a139d53f343b0..23bc7994179bd482bed46b83fc71a2f0ed8d2de3 100644 (file)
@@ -4,14 +4,21 @@
  */
 #pragma once
 
+#include <sys/types.h>
+
 #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.
index 014c79164bdcb23a8f24179e173664d42b6aab26..a0f84fd8652989d16df2fc1dfcf2c8b46b96fbb9 100644 (file)
@@ -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);
-  if(R_SUCCEEDED(rc))
+  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)
   {
-    if(entries == 0)
+    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))
     {
-      /* there are no more entries; ENOENT signals end-of-directory */
-      r->_errno = ENOENT;
-      return -1;
+      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))
+  {
+    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;