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