xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/uffs/uffs_find.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file uffs_find.c
35  * \brief find objects under dir
36  * \author Ricky Zheng, created 13th July, 2009
37  */
38 
39 #include <string.h>
40 #include <stdio.h>
41 #include "uffs_config.h"
42 #include "uffs/uffs_find.h"
43 
44 #define TPOOL(dev) &((dev)->mem.tree_pool)
45 
ResetFindInfo(uffs_FindInfo * f)46 static void ResetFindInfo(uffs_FindInfo *f)
47 {
48 	f->hash = 0;
49 	f->work = NULL;
50 	f->step = 0;
51 	f->pos = 0;
52 }
53 
_LoadObjectInfo(uffs_Device * dev,TreeNode * node,uffs_ObjectInfo * info,int type,int * err)54 static URET _LoadObjectInfo(uffs_Device *dev,
55 							TreeNode *node,
56 							uffs_ObjectInfo *info,
57 							int type,
58 							int *err)
59 {
60 	uffs_Buf *buf;
61 
62 	buf = uffs_BufGetEx(dev, (u8)type, node, 0, 0);
63 
64 	if (buf == NULL) {
65 		if (err)
66 			*err = UENOMEM;
67 		return U_FAIL;
68 	}
69 
70 	memcpy(&(info->info), buf->data, sizeof(uffs_FileInfo));
71 
72 	if (type == UFFS_TYPE_DIR) {
73 		info->len = 0;
74 		info->serial = node->u.dir.serial;
75 	}
76 	else {
77 		info->len = node->u.file.len;
78 		info->serial = node->u.file.serial;
79 	}
80 
81 	uffs_BufPut(dev, buf);
82 
83 	return U_SUCC;
84 }
85 
86 /**
87  * get object information
88  *
89  * \param[in] obj the object to be revealed
90  * \param[out] info object information will be loaded to info
91  * \param[out] err return error code if failed
92  *
93  * \return U_SUCC or U_FAIL
94  *
95  * \node the obj should be openned before call this function.
96  */
uffs_GetObjectInfo(uffs_Object * obj,uffs_ObjectInfo * info,int * err)97 URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err)
98 {
99 	uffs_Device *dev = obj->dev;
100 	URET ret = U_FAIL;
101 
102 	uffs_DeviceLock(dev);
103 
104 	if (obj && dev && info) {
105 		if (obj->parent == PARENT_OF_ROOT) {
106 			// this is ROOT. UFFS does not physically has root, just fake it ...
107 			memset(info, 0, sizeof(uffs_ObjectInfo));
108 			info->serial = obj->serial;
109 			info->info.attr |= (FILE_ATTR_DIR | FILE_ATTR_WRITE);
110 			if (err)
111 				*err = UENOERR;
112 			ret = U_SUCC;
113 		}
114 		else
115 			ret = _LoadObjectInfo(dev, obj->node, info, obj->type, err);
116 	}
117 	else {
118 		if (err)
119 			*err = UEINVAL;
120 	}
121 
122 	uffs_DeviceUnLock(dev);
123 
124 	return ret;
125 }
126 
127 
128 /**
129  * Open a FindInfo for finding objects under dir
130  *
131  * \param[out] f uffs_FindInfo structure
132  * \param[in] dir an openned dir object (openned by uffs_OpenObject() ).
133  *
134  * \return U_SUCC if success, U_FAIL if invalid param or the dir
135  *			is not been openned.
136  */
uffs_FindObjectOpen(uffs_FindInfo * f,uffs_Object * dir)137 URET uffs_FindObjectOpen(uffs_FindInfo *f, uffs_Object *dir)
138 {
139 	if (f == NULL || dir == NULL ||
140 			dir->dev == NULL || dir->open_succ != U_TRUE)
141 		return U_FAIL;
142 
143 	f->dev = dir->dev;
144 	f->serial = dir->serial;
145 	ResetFindInfo(f);
146 
147 	return U_SUCC;
148 }
149 
150 /**
151  * Open a FindInfo for finding objects under dir
152  *
153  * \param[out] f uffs_FindInfo structure
154  * \param[in] dev uffs device
155  * \param[in] dir serial number of the dir to be searched
156  *
157  * \return U_SUCC if success, U_FAIL if invalid param or the dir
158  *			serial number is not valid.
159  */
uffs_FindObjectOpenEx(uffs_FindInfo * f,uffs_Device * dev,int dir)160 URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir)
161 {
162 	TreeNode *node;
163 
164 	if (f == NULL || dev == NULL)
165 		return U_FAIL;
166 
167 	node = uffs_TreeFindDirNode(dev, dir);
168 
169 	if (node == NULL)
170 		return U_FAIL;
171 
172 	f->serial = dir;
173 	f->dev = dev;
174 	ResetFindInfo(f);
175 
176 	return U_SUCC;
177 }
178 
179 
do_FindObject(uffs_FindInfo * f,uffs_ObjectInfo * info,u16 x)180 static URET do_FindObject(uffs_FindInfo *f, uffs_ObjectInfo *info, u16 x)
181 {
182 	URET ret = U_SUCC;
183 	TreeNode *node;
184 	uffs_Device *dev = f->dev;
185 
186 	if (f->step == 0) { //!< working on dirs
187 		while (x != EMPTY_NODE) {
188 			node = FROM_IDX(x, TPOOL(dev));
189 			if (node->u.dir.parent == f->serial) {
190 				f->work = node;
191 				f->pos++;
192 				if (info)
193 					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
194 				goto ext;
195 			}
196 			x = node->hash_next;
197 		}
198 
199 		f->hash++; //come to next hash entry
200 
201 		for (; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) {
202 			x = dev->tree.dir_entry[f->hash];
203 			while (x != EMPTY_NODE) {
204 				node = FROM_IDX(x, TPOOL(dev));
205 				if (node->u.dir.parent == f->serial) {
206 					f->work = node;
207 					f->pos++;
208 					if (info)
209 						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
210 					goto ext;
211 				}
212 				x = node->hash_next;
213 			}
214 		}
215 
216 		//no subdirs, then lookup files ..
217 		f->step++;
218 		f->hash = 0;
219 		x = dev->tree.file_entry[f->hash];
220 	}
221 
222 	if (f->step == 1) {
223 
224 		while (x != EMPTY_NODE) {
225 			node = FROM_IDX(x, TPOOL(dev));
226 			if (node->u.file.parent == f->serial) {
227 				f->work = node;
228 				f->pos++;
229 				if (info)
230 					ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
231 				goto ext;
232 			}
233 			x = node->hash_next;
234 		}
235 
236 		f->hash++; //come to next hash entry
237 
238 		for (; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) {
239 			x = dev->tree.file_entry[f->hash];
240 			while (x != EMPTY_NODE) {
241 				node = FROM_IDX(x, TPOOL(dev));
242 				if (node->u.file.parent == f->serial) {
243 					f->work = node;
244 					f->pos++;
245 					if (info)
246 						ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
247 					goto ext;
248 				}
249 				x = node->hash_next;
250 			}
251 		}
252 
253 		//no any files, stopped.
254 		f->step++;
255 	}
256 
257 	ret = U_FAIL;
258 ext:
259 
260 	return ret;
261 
262 }
263 
264 
265 /**
266  * Find the first object
267  *
268  * \param[out] info the object information will be filled to info.
269  *				if info is NULL, then skip this object.
270  * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
271  *
272  * \return U_SUCC if an object is found, U_FAIL if no object is found.
273  */
uffs_FindObjectFirst(uffs_ObjectInfo * info,uffs_FindInfo * f)274 URET uffs_FindObjectFirst(uffs_ObjectInfo * info, uffs_FindInfo * f)
275 {
276 	uffs_Device *dev = f->dev;
277 	URET ret = U_SUCC;
278 
279 	uffs_DeviceLock(dev);
280 	ResetFindInfo(f);
281 	ret = do_FindObject(f, info, dev->tree.dir_entry[0]);
282 	uffs_DeviceUnLock(dev);
283 
284 	return ret;
285 }
286 
287 /**
288  * Find the next object.
289  *
290  * \param[out] info the object information will be filled to info.
291  *				if info is NULL, then skip this object.
292  * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
293  *
294  * \return U_SUCC if an object is found, U_FAIL if no object is found.
295  *
296  * \note uffs_FindObjectFirst() should be called before uffs_FindObjectNext().
297  */
uffs_FindObjectNext(uffs_ObjectInfo * info,uffs_FindInfo * f)298 URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo * f)
299 {
300 	uffs_Device *dev = f->dev;
301 	URET ret = U_SUCC;
302 
303 	if (dev == NULL || f->step > 1)
304 		return U_FAIL;
305 
306 	if (f->work == NULL)
307 		return uffs_FindObjectFirst(info, f);
308 
309 	uffs_DeviceLock(dev);
310 	ret = do_FindObject(f, info, f->work->hash_next);
311 	uffs_DeviceUnLock(dev);
312 
313 	return ret;
314 }
315 
316 /**
317  * Rewind a find object process.
318  *
319  * \note After rewind, you can call uffs_FindObjectFirst() to
320  *			start find object process.
321  */
uffs_FindObjectRewind(uffs_FindInfo * f)322 URET uffs_FindObjectRewind(uffs_FindInfo *f)
323 {
324 	if (f == NULL)
325 		return U_FAIL;
326 
327 	ResetFindInfo(f);
328 
329 	return U_SUCC;
330 }
331 
332 /**
333  * Close Find Object.
334  *
335  * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
336  *
337  * \return U_SUCC if success, U_FAIL if invalid param.
338  */
uffs_FindObjectClose(uffs_FindInfo * f)339 URET uffs_FindObjectClose(uffs_FindInfo * f)
340 {
341 	if (f == NULL)
342 		return U_FAIL;
343 
344 	f->dev = NULL;
345 	ResetFindInfo(f);
346 
347 	return U_SUCC;
348 }
349 
350 /**
351  * Count objects
352  *
353  * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
354  *
355  * \return object counts
356  * \note after call this function, you need to call
357  *		 uffs_FindObjectRewind() to start finding process.
358  */
uffs_FindObjectCount(uffs_FindInfo * f)359 int uffs_FindObjectCount(uffs_FindInfo *f)
360 {
361 	if (uffs_FindObjectFirst(NULL, f) == U_SUCC) {
362 		while (uffs_FindObjectNext(NULL, f) == U_SUCC) { };
363 	}
364 	return f->pos;
365 }
366 
367 /**
368  * Return current finding position
369  *
370  * \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
371  *
372  * \return current finding position
373  */
uffs_FindObjectTell(uffs_FindInfo * f)374 int uffs_FindObjectTell(uffs_FindInfo *f)
375 {
376 	return f->pos;
377 }
378 
379