* eina: add eina_file_stat_ls and guaranty that eina_file_direct_ls

will not call anything else than readdir_r.


SVN revision: 54105
This commit is contained in:
Cedric BAIL 2010-11-02 17:07:04 +00:00
parent eb4cd21f0c
commit 17973f336e
2 changed files with 119 additions and 27 deletions

View 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;
/**

View 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()
*/
@ -614,6 +628,83 @@ eina_file_direct_ls(const char *dir)
return &it->iterator;
}
/**
* 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;
}
/**
* @}
*/