1/**************************************************************************** 2 * fs/dirent/fs_readdir.c 3 * 4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5 * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/) 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 ****************************************************************************/ 20 21/**************************************************************************** 22 * Included Files 23 ****************************************************************************/ 24 25#include "vfs_config.h" 26#include "string.h" 27#include "dirent.h" 28#include "errno.h" 29#include "unistd.h" 30#include "fs/dirent_fs.h" 31#include "user_copy.h" 32#include "fs/file.h" 33#include "vnode.h" 34 35/**************************************************************************** 36 * Name: do_readdir 37 * 38 * Description: 39 * The do_readdir() function returns a pointer to a dirent structure 40 * representing the next directory entry in the directory stream pointed 41 * to by dir. It returns NULL on reaching the end-of-file or if an error 42 * occurred. 43 * 44 * Input Parameters: 45 * dirp -- An instance of type DIR created by a previous call to opendir(); 46 * 47 * Returned Value: 48 * The do_readdir() function returns a pointer to a dirent structure, or NULL 49 * if an error occurs or end-of-file is reached. On error, errno is set 50 * appropriately. 51 * 52 * EBADF - Invalid directory stream descriptor dir 53 * 54 ****************************************************************************/ 55static struct dirent *__readdir(DIR *dirp, int *lencnt) 56{ 57 struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; 58 struct Vnode *vnode_ptr = NULL; 59 int ret = 0; 60 int file_cnt = 0; 61 62 /* Verify that we were provided with a valid directory structure */ 63 64 if (!idir) 65 { 66 ret = -EBADF; 67 goto errout; 68 } 69 70 vnode_ptr = idir->fd_root; 71 if (vnode_ptr == NULL) 72 { 73 /* End of file and error conditions are not distinguishable 74 * with readdir. We return NULL to signal either case. 75 */ 76 77 ret = -ENOENT; 78 goto errout; 79 } 80 81 /* Perform the readdir() operation */ 82#ifdef LOSCFG_ENABLE_READ_BUFFER 83 idir->read_cnt = MAX_DIRENT_NUM; 84#else 85 idir->read_cnt = 1; 86#endif 87 88 if (vnode_ptr->vop != NULL && vnode_ptr->vop->Readdir != NULL) 89 { 90 file_cnt = vnode_ptr->vop->Readdir(vnode_ptr, idir); 91 } 92 else 93 { 94 ret = -ENOSYS; 95 goto errout; 96 } 97 98 if (file_cnt > 0) 99 { 100 *lencnt = file_cnt * sizeof(struct dirent); 101 return &(idir->fd_dir[0]); 102 } 103 104errout: 105 if (ret < 0) 106 { 107 set_errno(ret); 108 } 109 else if (file_cnt <= 0) 110 { 111 set_errno(ENOENT); 112 } 113 114 return (struct dirent *)NULL; 115} 116 117/**************************************************************************** 118 * Public Functions 119 ****************************************************************************/ 120 121/**************************************************************************** 122 * Name: readdir 123 * 124 * Description: 125 * The readdir() function returns a pointer to a dirent structure 126 * representing the next directory entry in the directory stream pointed 127 * to by dir. It returns NULL on reaching the end-of-file or if an error 128 * occurred. 129 * 130 * Inputs: 131 * dirp -- An instance of type DIR created by a previous call to opendir(); 132 * 133 * Return: 134 * The readdir() function returns a pointer to a dirent structure, or NULL 135 * if an error occurs or end-of-file is reached. On error, errno is set 136 * appropriately. 137 * 138 * EBADF - Invalid directory stream descriptor dir 139 * 140 ****************************************************************************/ 141struct dirent *readdir(DIR *dirp) 142{ 143 int ret; 144 int old_err = get_errno(); 145 int dirent_len = 0; 146 struct dirent *de = NULL; 147 struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; 148 149 if (idir->cur_pos != 0 && idir->cur_pos < MAX_DIRENT_NUM && idir->cur_pos < idir->end_pos) 150 { 151 de = &(idir->fd_dir[idir->cur_pos]); 152 153 if (idir->cur_pos == MAX_DIRENT_NUM) 154 { 155 idir->cur_pos = 0; 156 } 157 idir->cur_pos++; 158 159 return de; 160 } 161 else 162 { 163 de = __readdir(dirp, &dirent_len); 164 idir->end_pos = dirent_len / sizeof(struct dirent); 165 idir->cur_pos = 1; 166 167 if (de == NULL) 168 { 169 idir->cur_pos = 0; 170 ret = get_errno(); 171 /* Special case: ret = -ENOENT is end of file */ 172 173 if (ret == ENOENT) 174 { 175 set_errno(old_err); 176 } 177 } 178 } 179 return de; 180} 181 182/* readdir syscall routine */ 183 184int do_readdir(int fd, struct dirent **de, unsigned int count) 185{ 186 struct dirent *de_src = NULL; 187 int de_len = 0; 188 /* Did we get a valid file descriptor? */ 189 190#if CONFIG_NFILE_DESCRIPTORS > 0 191 struct file *filep = NULL; 192 193 if (de == NULL) 194 { 195 return -EINVAL; 196 } 197 198 if ((fd < 3) || (unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) 199 { 200 return -EBADF; 201 } 202 else 203 { 204 /* The descriptor is in a valid range to file descriptor... do the 205 * read. First, get the file structure. 206 */ 207 208 int ret = fs_getfilep(fd, &filep); 209 if (ret < 0) 210 { 211 /* The errno value has already been set */ 212 return -get_errno(); 213 } 214 215 /* Then let do_readdir do all of the work */ 216 217 de_src = __readdir(filep->f_dir, &de_len); 218 if (de_src == NULL) 219 { 220 /* Special case: ret = -ENOENT is end of file */ 221 return -get_errno(); 222 } 223 *de = de_src; 224 225 return de_len; 226 } 227#endif 228 return OK; 229} 230