openharmony_kernel_liteos_a/fs/fat/os_adapt/dirop_fat.c

275 lines
6.4 KiB
C
Executable File

/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dirop_fat.h"
#include "fatfs.h"
#include "errno.h"
#include "fs/fs.h"
#include "inode/inode.h"
#include "integer.h"
#include "string.h"
#ifdef LOSCFG_FS_FAT
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */
extern const struct mountpt_operations fat_operations;
#define SECTOR_SIZE 512
#define FIRST_MALLOC_SIZE 10
static INT vfat_check_path(const char *path)
{
struct inode *inode_ptr = NULL;
char *fullpath = NULL;
INT ret = vfs_normalize_path((const char *)NULL, path, &fullpath);
struct inode_search_s desc;
if (ret < ENOERR) {
ret = -ret;
set_errno(ret);
return FAT_ERROR;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
PRINT_ERR("ERROR: Failed to find %s\n", fullpath);
ret = -ret;
set_errno(ret);
return FAT_ERROR;
}
inode_ptr = desc.node;
free(fullpath);
if (inode_ptr && (inode_ptr->u.i_mops == &fat_operations)) {
inode_release(inode_ptr);
return ENOERR;
}
return FAT_ERROR;
}
static DIR_FAT *initdir_fat(DIR *dp)
{
DIR_FAT *dir_fat = NULL;
if (dp != NULL) {
dir_fat = (DIR_FAT *)malloc(sizeof(DIR_FAT) + PATH_MAX);
if (dir_fat != NULL) {
(void)memset_s(dir_fat, sizeof(DIR_FAT) + PATH_MAX, 0, sizeof(DIR_FAT) + PATH_MAX);
dir_fat->stDirStream.dd_nextloc = 0;
dir_fat->stDirStream.dd_size = 0;
dir_fat->stBuf.d_count = SECTOR_SIZE;
dir_fat->stBuf.d_usecount = 0;
(void)pthread_mutex_init(&(dir_fat->stDirStream.dd_lock), (const pthread_mutexattr_t *)NULL);
dir_fat->stDirStream.dp = dp;
return dir_fat;
}
(void)closedir(dp);
}
return NULL;
}
DIR_FAT *opendir_fat(const char *name)
{
INT ret;
DIR *dp = NULL;
ret = vfat_check_path(name);
if (ret) {
return NULL;
}
dp = opendir(name);
return initdir_fat(dp);
}
int closedir_fat(DIR_FAT *dir_fat)
{
INT ret;
if (dir_fat == NULL) {
return FAT_ERROR;
}
ret = closedir(dir_fat->stDirStream.dp);
if (ret == ENOERR) {
(void)pthread_mutex_destroy(&(dir_fat->stDirStream.dd_lock));
free(dir_fat);
}
return ret;
}
extern int fatfs_readdir_all(DIR_FAT *dir_fat);
struct fat_direntall *readdir_fat(DIR_FAT *dir_fat)
{
INT ret;
struct fat_direntall *de = (struct fat_direntall *)NULL;
if (dir_fat == NULL) {
return NULL;
}
if (pthread_mutex_lock(&(dir_fat->stDirStream.dd_lock)) != ENOERR) {
return NULL;
}
ret = fatfs_readdir_all(dir_fat);
if (!ret) {
de = &(dir_fat->stBuf.direntall);
}
if (pthread_mutex_unlock(&(dir_fat->stDirStream.dd_lock)) != ENOERR)
PRINT_ERR("readdir_fat mutex unlock error \n");
return de;
}
static struct fat_direntall **scandir_fat_remalloc_names(struct fat_direntall **names,
UINT *names_size, UINT pos, bool *failed)
{
struct fat_direntall **new_direntall = NULL;
INT32 ret;
if (pos == *names_size) {
if (*names_size == 0) {
*names_size = FIRST_MALLOC_SIZE;
} else {
*names_size <<= 1;
}
new_direntall = (struct fat_direntall **)malloc(*names_size * sizeof(struct fat_direntall *));
if (new_direntall == NULL) {
*failed = 1;
return names;
}
if (names != NULL) {
ret = memcpy_s(new_direntall, (*names_size) * sizeof(struct fat_direntall *),
names, pos * sizeof(struct fat_direntall *));
if (ret != EOK){
*failed = 1;
free(new_direntall);
return names;
}
free(names);
}
return new_direntall;
}
return names;
}
int scandir_fat(const char *dir, struct fat_direntall ***namelist,
int (*selector) (const struct fat_direntall *),
int (*compar) (const struct fat_direntall **, const struct fat_direntall **))
{
DIR_FAT *dp = opendir_fat(dir);
struct fat_direntall *current = NULL;
struct fat_direntall **names = NULL;
struct fat_direntall *vnew = NULL;
UINT names_size = 0;
UINT pos = 0;
UINT dsize;
bool failed = 0;
INT use_it;
if (dp == NULL) {
return FAT_ERROR;
}
current = readdir_fat(dp);
while (current != NULL) {
use_it = (selector == NULL);
if (!use_it) {
use_it = (*selector) (current);
}
if (use_it) {
names = scandir_fat_remalloc_names(names, &names_size, pos, &failed);
if (failed == 1) {
break;
}
dsize = current->d_reclen;
vnew = (struct fat_direntall *)malloc(dsize);
if (vnew == NULL) {
failed = 1;
break;
}
(void)memcpy_s(vnew, dsize, current, dsize);
names[pos++] = vnew;
}
current = readdir_fat(dp);
}
if (failed == 1) {
(void)closedir_fat(dp);
while (pos > 0) {
free(names[--pos]);
}
if (names != NULL) {
free(names);
}
return FAT_ERROR;
}
(void)closedir_fat(dp);
/* Sort the list if we have a comparison function to sort with. */
if (compar != NULL && names != NULL) {
qsort((void *)names, pos, sizeof (struct fat_direntall *), (int (*)(const void *, const void *))*compar);
}
*namelist = names;
return pos;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* CONFIG_FS_FAT */