fs_readdir.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /****************************************************************************
  2. * fs/dirent/fs_readdir.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. 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, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <string.h>
  25. #include <dirent.h>
  26. #include <errno.h>
  27. #include <nuttx/fs/fs.h>
  28. #include <nuttx/fs/dirent.h>
  29. #include "inode/inode.h"
  30. /****************************************************************************
  31. * Private Functions
  32. ****************************************************************************/
  33. /****************************************************************************
  34. * Name: readpseudodir
  35. ****************************************************************************/
  36. static inline int readpseudodir(struct fs_dirent_s *idir)
  37. {
  38. FAR struct inode *prev;
  39. int ret;
  40. /* Check if we are at the end of the list */
  41. if (!idir->u.pseudo.fd_next)
  42. {
  43. /* End of file and error conditions are not distinguishable with
  44. * readdir. Here we return -ENOENT to signal the end of the
  45. * directory.
  46. */
  47. return -ENOENT;
  48. }
  49. /* Copy the inode name into the dirent structure */
  50. strncpy(idir->fd_dir.d_name, idir->u.pseudo.fd_next->i_name,
  51. NAME_MAX);
  52. /* If the node has file operations, we will say that it is a file. */
  53. idir->fd_dir.d_type = DTYPE_UNKNOWN;
  54. if (idir->u.pseudo.fd_next->u.i_ops)
  55. {
  56. #ifndef CONFIG_DISABLE_MOUNTPOINT
  57. if (INODE_IS_BLOCK(idir->u.pseudo.fd_next))
  58. {
  59. idir->fd_dir.d_type = DTYPE_BLK;
  60. }
  61. else if (INODE_IS_MTD(idir->u.pseudo.fd_next))
  62. {
  63. idir->fd_dir.d_type = DTYPE_MTD;
  64. }
  65. else if (INODE_IS_MOUNTPT(idir->u.pseudo.fd_next))
  66. {
  67. idir->fd_dir.d_type = DTYPE_DIRECTORY;
  68. }
  69. else
  70. #endif
  71. #ifdef CONFIG_PSEUDOFS_SOFTLINKS
  72. if (INODE_IS_SOFTLINK(idir->u.pseudo.fd_next))
  73. {
  74. idir->fd_dir.d_type = DTYPE_LINK;
  75. }
  76. else
  77. #endif
  78. if (INODE_IS_DRIVER(idir->u.pseudo.fd_next))
  79. {
  80. idir->fd_dir.d_type = DTYPE_CHR;
  81. }
  82. else if (INODE_IS_NAMEDSEM(idir->u.pseudo.fd_next))
  83. {
  84. idir->fd_dir.d_type = DTYPE_SEM;
  85. }
  86. else if (INODE_IS_MQUEUE(idir->u.pseudo.fd_next))
  87. {
  88. idir->fd_dir.d_type = DTYPE_MQ;
  89. }
  90. else if (INODE_IS_SHM(idir->u.pseudo.fd_next))
  91. {
  92. idir->fd_dir.d_type = DTYPE_SHM;
  93. }
  94. }
  95. /* If the node has child node(s) or no operations, then we will say that
  96. * it is a directory rather than a special file. NOTE: that the node can
  97. * be both!
  98. */
  99. if (idir->u.pseudo.fd_next->i_child || !idir->u.pseudo.fd_next->u.i_ops)
  100. {
  101. idir->fd_dir.d_type = DTYPE_DIRECTORY;
  102. }
  103. /* Now get the inode to visit next time that readdir() is called */
  104. ret = inode_semtake();
  105. if (ret < 0)
  106. {
  107. return ret;
  108. }
  109. prev = idir->u.pseudo.fd_next;
  110. idir->u.pseudo.fd_next = prev->i_peer; /* The next node to visit */
  111. if (idir->u.pseudo.fd_next)
  112. {
  113. /* Increment the reference count on this next node */
  114. idir->u.pseudo.fd_next->i_crefs++;
  115. }
  116. inode_semgive();
  117. if (prev)
  118. {
  119. inode_release(prev);
  120. }
  121. return OK;
  122. }
  123. /****************************************************************************
  124. * Public Functions
  125. ****************************************************************************/
  126. /****************************************************************************
  127. * Name: readdir
  128. *
  129. * Description:
  130. * The readdir() function returns a pointer to a dirent structure
  131. * representing the next directory entry in the directory stream pointed
  132. * to by dir. It returns NULL on reaching the end-of-file or if an error
  133. * occurred.
  134. *
  135. * Input Parameters:
  136. * dirp -- An instance of type DIR created by a previous call to opendir();
  137. *
  138. * Returned Value:
  139. * The readdir() function returns a pointer to a dirent structure, or NULL
  140. * if an error occurs or end-of-file is reached. On error, errno is set
  141. * appropriately.
  142. *
  143. * EBADF - Invalid directory stream descriptor dir
  144. *
  145. ****************************************************************************/
  146. FAR struct dirent *readdir(DIR *dirp)
  147. {
  148. FAR struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
  149. struct inode *inode;
  150. int ret;
  151. /* Verify that we were provided with a valid directory structure */
  152. if (!idir)
  153. {
  154. ret = EBADF;
  155. goto errout;
  156. }
  157. /* A special case is when we enumerate an "empty", unused inode. That is
  158. * an inode in the pseudo-filesystem that has no operations and no
  159. * children. This is a "dangling" directory entry that has lost its
  160. * children.
  161. */
  162. inode = idir->fd_root;
  163. if (!inode)
  164. {
  165. /* End of file and error conditions are not distinguishable
  166. * with readdir. We return NULL to signal either case.
  167. */
  168. ret = OK;
  169. goto errout;
  170. }
  171. /* The way we handle the readdir depends on the type of inode
  172. * that we are dealing with.
  173. */
  174. #ifndef CONFIG_DISABLE_MOUNTPOINT
  175. if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags))
  176. {
  177. /* The node is a file system mointpoint. Verify that the mountpoint
  178. * supports the readdir() method
  179. */
  180. if (!inode->u.i_mops || !inode->u.i_mops->readdir)
  181. {
  182. ret = EACCES;
  183. goto errout;
  184. }
  185. /* Perform the readdir() operation */
  186. ret = inode->u.i_mops->readdir(inode, idir);
  187. }
  188. else
  189. #endif
  190. {
  191. /* The node is part of the root pseudo file system */
  192. ret = readpseudodir(idir);
  193. }
  194. /* ret < 0 is an error. Special case: ret = -ENOENT is end of file */
  195. if (ret < 0)
  196. {
  197. if (ret == -ENOENT)
  198. {
  199. ret = OK;
  200. }
  201. else
  202. {
  203. ret = -ret;
  204. }
  205. goto errout;
  206. }
  207. /* Success */
  208. idir->fd_position++;
  209. return &idir->fd_dir;
  210. errout:
  211. set_errno(ret);
  212. return NULL;
  213. }