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