* eina: add eina_file_stat_ls and guaranty that eina_file_direct_ls
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 2 Nov 2010 17:07:04 +0000 (17:07 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 2 Nov 2010 17:07:04 +0000 (17:07 +0000)
will not call anything else than readdir_r.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@54105 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/include/eina_file.h
src/lib/eina_file.c

index 0452b79..ae51a9f 100644 (file)
@@ -95,6 +95,7 @@ EAPI Eina_Bool eina_file_dir_list(const char           *dir,
                                   void                 *data) EINA_ARG_NONNULL(1, 3);
 EAPI Eina_Array    *eina_file_split(char *path) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
 EAPI Eina_Iterator *eina_file_ls(const char *dir) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
+EAPI Eina_Iterator *eina_file_stat_ls(const char *dir) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
 EAPI Eina_Iterator *eina_file_direct_ls(const char *dir) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
 
 /**
index af6f65c..c3c5335 100644 (file)
@@ -149,10 +149,7 @@ _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
 {
    struct dirent *dp;
    size_t length;
-#ifndef _DIRENT_HAVE_D_TYPE
-   struct stat st;
-#endif
-  
+
    dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
 
    do
@@ -211,29 +208,9 @@ _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
        break;
      }
 #else
-   if (stat(it->info.path, &st))
-     it->info.type = EINA_FILE_UNKNOWN;
-   else
-     {
-       if (S_ISREG(st.st_mode))
-         it->info.type = EINA_FILE_REG;
-       else if (S_ISDIR(st.st_mode))
-         it->info.type = EINA_FILE_DIR;
-       else if (S_ISCHR(st.st_mode))
-         it->info.type = EINA_FILE_CHR;
-       else if (S_ISBLK(st.st_mode))
-         it->info.type = EINA_FILE_BLK;
-       else if (S_ISFIFO(st.st_mode))
-         it->info.type = EINA_FILE_FIFO;
-       else if (S_ISLNK(st.st_mode))
-         it->info.type = EINA_FILE_LNK;
-       else if (S_ISSOCK(st.st_mode))
-         it->info.type = EINA_FILE_SOCK;
-       else
-         it->info.type = EINA_FILE_UNKNOWN;
-     }
+   it->info.type = EINA_FILE_UNKNOWN;
 #endif
-  
+
    *data = &it->info;
    return EINA_TRUE;
 }
@@ -253,6 +230,42 @@ _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
    free(it);
 }
 
+static Eina_Bool
+_eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
+{
+   struct stat st;
+
+   if (!_eina_file_direct_ls_iterator_next(it, data))
+     return EINA_FALSE;
+
+   if (it->info.type == EINA_FILE_UNKNOWN)
+     {
+        if (stat(it->info.path, &st))
+          it->info.type = EINA_FILE_UNKNOWN;
+        else
+          {
+             if (S_ISREG(st.st_mode))
+               it->info.type = EINA_FILE_REG;
+             else if (S_ISDIR(st.st_mode))
+               it->info.type = EINA_FILE_DIR;
+             else if (S_ISCHR(st.st_mode))
+               it->info.type = EINA_FILE_CHR;
+             else if (S_ISBLK(st.st_mode))
+               it->info.type = EINA_FILE_BLK;
+             else if (S_ISFIFO(st.st_mode))
+               it->info.type = EINA_FILE_FIFO;
+             else if (S_ISLNK(st.st_mode))
+               it->info.type = EINA_FILE_LNK;
+             else if (S_ISSOCK(st.st_mode))
+               it->info.type = EINA_FILE_SOCK;
+             else
+               it->info.type = EINA_FILE_UNKNOWN;
+          }
+     }
+
+   return EINA_TRUE;
+}
+
 /*============================================================================*
 *                                 Global                                     *
 *============================================================================*/
@@ -560,7 +573,8 @@ eina_file_ls(const char *dir)
  *         pointers that could be used but not modified. The lifetime
  *         of the returned pointer is until the next iteration and
  *         while the iterator is live, deleting the iterator
- *         invalidates the pointer.
+ *         invalidates the pointer. It will not call stat() when filesystem
+ *         doesn't provide information to fill type from readdir_r().
  *
  * @see eina_file_ls()
  */
@@ -615,5 +629,82 @@ eina_file_direct_ls(const char *dir)
 }
 
 /**
+ * Get an iterator to list the content of a directory, with direct information.
+ *
+ * Iterators are cheap to be created and allow interruption at any
+ * iteration. At each iteration, only the next directory entry is read
+ * from the filesystem with readdir_r().
+ *
+ * The iterator returns the direct pointer to couple of useful information in
+ * #Eina_File_Direct_Info and that pointer should not be modified anyhow!
+ *
+ * The iterator will walk over '.' and '..' without returning them.
+ *
+ * The iterator container is the DIR* corresponding to the current walk.
+ *
+ * @param  dir The name of the directory to list
+
+ * @return Return an Eina_Iterator that will walk over the files and
+ *         directory in the pointed directory. On failure it will
+ *         return NULL. The iterator emits #Eina_File_Direct_Info
+ *         pointers that could be used but not modified. The lifetime
+ *         of the returned pointer is until the next iteration and
+ *         while the iterator is live, deleting the iterator
+ *         invalidates the pointer. It will call stat() when filesystem
+ *         doesn't provide information to fill type from readdir_r().
+ *
+ * @see eina_file_direct_ls()
+ */
+EAPI Eina_Iterator *
+eina_file_stat_ls(const char *dir)
+{
+   Eina_File_Direct_Iterator *it;
+   size_t length;
+
+   if (!dir)
+      return NULL;
+
+   length = strlen(dir);
+   if (length < 1)
+      return NULL;
+
+   if (length + NAME_MAX + 2 >= PATH_MAX)
+      return NULL;
+
+   it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
+   if (!it)
+      return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->dirp = opendir(dir);
+   if (!it->dirp)
+     {
+        free(it);
+        return NULL;
+     }
+
+   memcpy(it->dir,       dir, length + 1);
+   it->length = length;
+
+   memcpy(it->info.path, dir, length);
+   if (dir[length - 1] == '/')
+      it->info.name_start = length;
+   else
+     {
+        it->info.path[length] = '/';
+        it->info.name_start = length + 1;
+     }
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_stat_ls_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_file_direct_ls_iterator_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
  * @}
  */