• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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