1/**************************************************************************** 2 * fs/dirent/fs_opendir.c 3 * 4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5 * Based on NuttX originally written by Gregory Nutt 6 * 7 * Copyright (C) 2007-2009, 2011, 2013-2014, 2017-2018 Gregory Nutt. All 8 * rights reserved. 9 * Author: Gregory Nutt <gnutt@nuttx.org> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 3. Neither the name NuttX nor the names of its contributors may be 22 * used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 * 38 ****************************************************************************/ 39 40/**************************************************************************** 41 * Included Files 42 ****************************************************************************/ 43 44#include "vfs_config.h" 45#include "dirent.h" 46#include "string.h" 47#include "assert.h" 48#include "errno.h" 49#include "stdlib.h" 50#include "fs/dirent_fs.h" 51#include "vnode.h" 52#include "path_cache.h" 53 54/**************************************************************************** 55 * Public Functions 56 ****************************************************************************/ 57 58/**************************************************************************** 59 * Name: opendir 60 * 61 * Description: 62 * The opendir() function opens a directory stream corresponding to the 63 * directory name, and returns a pointer to the directory stream. The 64 * stream is positioned at the first entry in the directory. 65 * 66 * Input Parameters: 67 * path -- the directory to open 68 * 69 * Returned Value: 70 * The opendir() function returns a pointer to the directory stream. On 71 * error, NULL is returned, and errno is set appropriately. 72 * 73 * EACCES - Permission denied. 74 * EMFILE - Too many file descriptors in use by process. 75 * ENFILE - Too many files are currently open in the 76 * system. 77 * ENOENT - Directory does not exist, or name is an empty 78 * string. 79 * ENOMEM - Insufficient memory to complete the operation. 80 * ENOTDIR - 'path' is not a directory. 81 * 82 ****************************************************************************/ 83 84DIR *opendir(const char *path) 85{ 86 struct Vnode *vp = NULL; 87 struct fs_dirent_s *dir = NULL; 88 int ret; 89 90 /* Find the node matching the path. */ 91 VnodeHold(); 92 ret = VnodeLookup(path, &vp, 0); 93 if (vp == NULL || ret != OK) 94 { 95 VnodeDrop(); 96 goto errout; 97 } 98 if (vp->type != VNODE_TYPE_DIR) 99 { 100 ret = -ENOTDIR; 101 PRINT_ERR("opendir (%s) failed, err=%d\n", path, ret); 102 VnodeDrop(); 103 goto errout; 104 } 105 106 vp->useCount++; 107 VnodeDrop(); 108 109 /* Allocate a type DIR -- which is little more than an vp container. */ 110 dir = (struct fs_dirent_s *)calloc(1, sizeof(struct fs_dirent_s)); 111 if (!dir) 112 { 113 /* Insufficient memory to complete the operation. */ 114 ret = -ENOMEM; 115 goto errout_with_count; 116 } 117 118 /* Populate the DIR structure and return it to the caller. The way that 119 * we do this depends on whenever this is a "normal" pseudo-file-system 120 * vp or a file system mountpoint. 121 */ 122 123 dir->fd_position = 0; /* This is the position in the read stream */ 124 125 if (vp->vop != NULL && vp->vop->Opendir != NULL) 126 { 127 ret = vp->vop->Opendir(vp, dir); 128 } 129 else 130 { 131 ret = -ENOSYS; 132 } 133 if (ret < 0) 134 { 135 free(dir); 136 goto errout_with_count; 137 } 138 dir->fd_status = DIRENT_MAGIC; 139 dir->fd_root = vp; 140 141 return ((DIR *)dir); 142 143 /* Nasty goto's make error handling simpler */ 144 145errout_with_count: 146 VnodeHold(); 147 vp->useCount--; 148 VnodeDrop(); 149errout: 150 set_errno(-ret); 151 return NULL; 152} 153 154int do_opendir(const char *path, int oflags) 155{ 156 int ret; 157 158 struct Vnode *vp = NULL; 159 struct file *filep = NULL; 160 struct fs_dirent_s *dir = NULL; 161 char *fullpath = NULL; 162 char *relativepath = NULL; 163 164 if (path == NULL || *path == 0) 165 { 166 ret = -EINVAL; 167 goto errout; 168 } 169 170 ret = get_path_from_fd(AT_FDCWD, &relativepath); 171 if (ret < 0) 172 { 173 goto errout; 174 } 175 176 ret = vfs_normalize_path((const char *)relativepath, path, &fullpath); 177 if (relativepath) 178 { 179 free(relativepath); 180 } 181 if (ret < 0) 182 { 183 goto errout; 184 } 185 186 VnodeHold(); 187 /* Get an vnode for this file */ 188 ret = VnodeLookup(path, &vp, 0); 189 if (ret < 0) 190 { 191 VnodeDrop(); 192 goto errout; 193 } 194 if (vp->type != VNODE_TYPE_DIR) 195 { 196 ret = -ENOTDIR; 197 VnodeDrop(); 198 goto errout; 199 } 200 vp->useCount++; 201 VnodeDrop(); 202 203 filep = files_allocate(vp, oflags, 0, NULL, FILE_START_FD); 204 if (filep == NULL) 205 { 206 ret = -EMFILE; 207 goto errout_with_vnode; 208 } 209 210 /* Allocate a type DIR -- which is little more than an vnode container. */ 211 dir = (struct fs_dirent_s *)zalloc(sizeof(struct fs_dirent_s)); 212 if (dir == NULL) 213 { 214 ret = -ENOMEM; 215 goto errout_with_file; 216 } 217 dir->fd_position = 0; /* This is the position in the read stream */ 218 219 /* Open the directory at the relative path */ 220 if (vp->vop != NULL && vp->vop->Opendir != NULL) 221 { 222 ret = vp->vop->Opendir(vp, dir); 223 } 224 else 225 { 226 ret = -ENOSYS; 227 } 228 229 if (ret < 0) 230 { 231 free(dir); 232 goto errout_with_file; 233 } 234 235 dir->fd_root = vp; 236 dir->fd_status = DIRENT_MAGIC; 237 filep->f_dir = dir; 238 if (fullpath) 239 { 240 free(fullpath); 241 } 242 243 return filep->fd; 244 245errout_with_file: 246 files_release(filep->fd); 247errout_with_vnode: 248 VnodeHold(); 249 vp->useCount--; 250 VnodeDrop(); 251errout: 252 if (fullpath) 253 { 254 free(fullpath); 255 } 256 set_errno(-ret); 257 return VFS_ERROR; 258} 259