1 /****************************************************************************
2 * fs/inode/fs_foreachinode.c
3 *
4 * Copyright (C) 2012-2014 Gregory Nutt. All rights reserved.
5 * Author: Gregory Nutt <gnutt@nuttx.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name NuttX nor the names of its contributors may be
18 * used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 ****************************************************************************/
35
36 /****************************************************************************
37 * Included Files
38 ****************************************************************************/
39
40 #include "vfs_config.h"
41 #include "stdio.h"
42 #include "stdlib.h"
43 #include "string.h"
44 #include "errno.h"
45 #include "fs/fs.h"
46 #include "inode/inode.h"
47
48 /****************************************************************************
49 * Pre-processor Definitions
50 ****************************************************************************/
51
52 /* Is it better to allocate the struct inode_path_s from the heap? or
53 * from the stack? This decision depends on how often this is down and
54 * how much stack space you can afford.
55 */
56
57 #define ENUM_INODE_ALLOC 1
58
59 /****************************************************************************
60 * Private Types
61 ****************************************************************************/
62
63 /* This structure manages the full path to the inode. */
64
65 struct inode_path_s
66 {
67 foreach_inode_t handler;
68 FAR void *arg;
69 char path[CONFIG_PATH_MAX];
70 };
71
72 /****************************************************************************
73 * Private Functions
74 ****************************************************************************/
75
76 /****************************************************************************
77 * Name: foreach_inodelevel
78 *
79 * Description:
80 * This is the recursive 'heart' of foreach_inode. It will visit each
81 * inode at this level in the hierarchy and recurse handle each inode
82 * at the next level down.
83 *
84 * Assumptions:
85 * The caller holds the inode semaphore.
86 *
87 ****************************************************************************/
88
foreach_inodelevel(FAR struct inode * node,struct inode_path_s * info)89 static int foreach_inodelevel(FAR struct inode *node, struct inode_path_s *info)
90 {
91 int ret = OK;
92
93 /* Visit each node at this level */
94
95 for (; node; node = node->i_peer)
96 {
97 /* Give the next inode to the callback */
98 ret = info->handler(node, info->path, info->arg);
99
100 /* Break out of the loop early if the handler returns a non-zero
101 * value.
102 */
103
104 if (ret != 0)
105 {
106 break;
107 }
108
109 /* If there is a level 'beneath' this one, then recurse to visit all
110 * of the inodes at that level.
111 */
112
113 if (node->i_child)
114 {
115 /* Construct the path to the next level */
116
117 int pathlen = strlen(info->path);
118 int namlen = strlen(node->i_name) + 1;
119
120 /* Make sure that this would not exceed the maximum path length */
121
122 if (pathlen + namlen >= PATH_MAX)
123 {
124 ret = -ENAMETOOLONG;
125 break;
126 }
127
128 /* Append the path segment to this inode and recurse */
129
130 ret = snprintf_s(&info->path[pathlen], CONFIG_PATH_MAX - pathlen,
131 CONFIG_PATH_MAX - pathlen - 1, "%s/", node->i_name);
132 if (ret < 0)
133 {
134 ret = -ENAMETOOLONG;
135 break;
136 }
137
138 ret = foreach_inodelevel(node->i_child, info);
139
140 /* Truncate the path name back to the correct length */
141
142 info->path[pathlen] = '\0';
143
144 /* Return early if the handler at the lower level returned a non-
145 * zero value
146 */
147
148 if (ret != 0)
149 {
150 break;
151 }
152 }
153 }
154
155 /* Return the result of the traversal. */
156
157 return ret;
158 }
159
160 /****************************************************************************
161 * Public Functions
162 ****************************************************************************/
163 /****************************************************************************
164 * Name: foreach_inode
165 *
166 * Description:
167 * Visit each inode in the pseudo-file system. The traversal is terminated
168 * when the callback 'handler' returns a non-zero value, or when all of
169 * the inodes have been visited.
170 *
171 * NOTE 1: Use with caution... The pseudo-file system is locked throughout
172 * the traversal.
173 * NOTE 2: The search algorithm is recursive and could, in principle, use
174 * an indeterminant amount of stack space. This will not usually be a
175 * real work issue.
176 *
177 ****************************************************************************/
178
foreach_inode(foreach_inode_t handler,FAR void * arg)179 int foreach_inode(foreach_inode_t handler, FAR void *arg)
180 {
181 #ifdef ENUM_INODE_ALLOC
182 FAR struct inode_path_s *info;
183 int ret;
184
185 /* Allocate the mountpoint info structure */
186
187 info = (FAR struct inode_path_s *)malloc(sizeof(struct inode_path_s));
188 if (!info)
189 {
190 return -ENOMEM;
191 }
192
193 /* Initialize the info structure */
194
195 info->handler = handler;
196 info->arg = arg;
197 info->path[0] = '\0';
198
199 /* Start the recursion at the root inode */
200
201 inode_semtake();
202 ret = foreach_inodelevel(g_root_inode, info);
203 inode_semgive();
204
205 /* Free the info structure and return the result */
206
207 free(info);
208 return ret;
209
210 #else
211 struct inode_path_s info;
212 int ret;
213
214 /* Initialize the info structure */
215
216 info.handler = handler;
217 info.arg = arg;
218 info.path[0] = '\0';
219
220 /* Start the recursion at the root inode */
221
222 inode_semtake();
223 ret = foreach_inodelevel(g_root_inode, &info);
224 inode_semgive();
225
226 return ret;
227
228 #endif
229 }
230
231