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