blob: 686e846c5c18b092117c7ad617e924c4c71e12f5 [file] [log] [blame]
Daniel Lezcanoc193b602011-06-08 23:30:00 +02001/*******************************************************************************
2 * Copyright (C) 2010, Linaro Limited.
3 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Author:
12 * Daniel Lezcano <daniel.lezcano@linaro.org>
13 *
14 *******************************************************************************/
15
16#define _GNU_SOURCE
17#include <stdio.h>
18#undef _GNU_SOURCE
19#include <stdlib.h>
Daniel Lezcano25fc4a32011-08-25 15:46:13 +020020#include <stdbool.h>
Daniel Lezcanoc193b602011-06-08 23:30:00 +020021#include <string.h>
22#include <dirent.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27#include "tree.h"
28
29/*
30 * Allocate a tree structure and initialize the different fields.
31 *
32 * @path : the absolute path to the directory
33 * @depth : the depth in the tree
34 * Returns a tree structure on success, NULL otherwise
35 */
36static inline struct tree *tree_alloc(const char *path, int depth)
37{
38 struct tree *t;
39
40 t = malloc(sizeof(*t));
41 if (!t)
42 return NULL;
43
44 /* Full pathname */
45 t->path = strdup(path);
46 if (!t->path) {
47 free(t);
48 return NULL;
49 }
50
51 /* Basename pointer on the full path name */
52 t->name = strrchr(t->path, '/') + 1;
53
54 t->depth = depth;
55 t->tail = t;
56 t->child = NULL;
57 t->parent = NULL;
58 t->next = NULL;
59 t->prev = NULL;
60 t->private = NULL;
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +020061 t->nrchild = 0;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020062
63 return t;
64}
65
66/*
67 * Free a tree structure and the fields we allocated in the
68 * tree_alloc function.
69 *
70 * @t : the tree structure to be freed
71 */
72static inline void tree_free(struct tree *t)
73{
74 free(t->path);
75 free(t);
76}
77
78/*
79 * Add at the end of the list the new list element.
80 *
81 * @head : the list to be appened
82 * @new : the new element to be added at the end of the list
83 */
84static inline void tree_add_tail(struct tree *head, struct tree *new)
85{
86 new->prev = head->tail;
87 head->tail->next = new;
88 head->tail = new;
89}
90
91/*
92 * Add a child in to a parent list, at the end of this list.
93 *
94 * @parent : the parent list to add the child
95 * @child : the child to be added
96 */
97static inline void tree_add_child(struct tree *parent, struct tree *child)
98{
99 child->parent = parent;
100
101 if (parent->child)
102 return tree_add_tail(parent->child, child);
103
104 parent->child = child;
105}
106
107/*
108 * This function will browse the directory structure and build a
109 * tree reflecting the content of the directory tree.
110 *
111 * @tree : the root node of the tree
112 * @filter : a callback to filter out the directories
113 * Returns 0 on success, -1 otherwise
114 */
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200115static int tree_scan(struct tree *tree, tree_filter_t filter, bool follow)
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200116{
117 DIR *dir;
118 char *basedir, *newpath;
119 struct dirent dirent, *direntp;
120 struct stat s;
121 int ret = 0;
122
123 dir = opendir(tree->path);
Sanjay Singh Rawat5fef0052013-04-17 15:02:01 +0530124 if (!dir) {
125 printf("error: unable to open directory %s\n", tree->path);
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200126 return -1;
Sanjay Singh Rawat5fef0052013-04-17 15:02:01 +0530127 }
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200128
129 while (!readdir_r(dir, &dirent, &direntp)) {
130
131 struct tree *child;
132
133 if (!direntp)
134 break;
135
136 if (direntp->d_name[0] == '.')
137 continue;
138
139 if (filter && filter(direntp->d_name))
140 continue;
141
142 ret = asprintf(&basedir, "%s", tree->path);
143 if (ret < 0)
144 return -1;
145
146 ret = basename(basedir) ? 0 : -1;
147 if (ret < 0)
148 goto out_free_basedir;
149
150 ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
151 if (ret < 0)
152 goto out_free_basedir;
153
154 ret = stat(newpath, &s);
155 if (ret)
156 goto out_free_newpath;
157
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200158 if (S_ISDIR(s.st_mode) || (S_ISLNK(s.st_mode) && follow)) {
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200159
160 ret = -1;
161
162 child = tree_alloc(newpath, tree->depth + 1);
163 if (!child)
164 goto out_free_newpath;
165
166 tree_add_child(tree, child);
167
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +0200168 tree->nrchild++;
169
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200170 ret = tree_scan(child, filter, follow);
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200171 }
172
173 out_free_newpath:
174 free(newpath);
175
176 out_free_basedir:
177 free(basedir);
178
179 if (ret)
180 break;
181 }
182
183 closedir(dir);
184
185 return ret;
186}
187
188/*
189 * This function takes the topmost directory path and populate the
190 * directory tree structures.
191 *
192 * @tree : a path to the topmost directory path
193 * Returns a tree structure corresponding to the root node of the
194 * directory tree representation on success, NULL otherwise
195 */
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200196struct tree *tree_load(const char *path, tree_filter_t filter, bool follow)
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200197{
198 struct tree *tree;
199
200 tree = tree_alloc(path, 0);
201 if (!tree)
202 return NULL;
203
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200204 if (tree_scan(tree, filter, follow)) {
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200205 tree_free(tree);
206 return NULL;
207 }
208
209 return tree;
210}
211
212/*
213 * This function will go over the tree passed as parameter and
214 * will call the callback passed as parameter for each node.
215 *
216 * @tree : the topmost node where we begin to browse the tree
217 * Returns 0 on success, < 0 otherwise
218 */
219int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
220{
221 if (!tree)
222 return 0;
223
224 if (cb(tree, data))
225 return -1;
226
227 if (tree_for_each(tree->child, cb, data))
228 return -1;
229
230 return tree_for_each(tree->next, cb, data);
231}
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200232
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200233/*
234 * This function will go over the tree passed as parameter at the reverse
235 * order and will call the callback passed as parameter for each.
236 * @tree : the lower node where we begin to browse the tree at the reverse
237 * order
238 * cb : a callback for each node the function will go over
239 * data : some private data to be passed across the callbacks
240 * Returns 0 on success, < 0 otherwise
241 */
Daniel Lezcano6d42e812011-06-08 23:30:01 +0200242int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data)
243{
244 if (!tree)
245 return 0;
246
247 if (cb(tree, data))
248 return -1;
249
250 if (tree_for_each_reverse(tree->prev, cb, data))
251 return -1;
252
253 return tree_for_each_reverse(tree->parent, cb, data);
254}
255
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200256
257/*
258 * The function will go over all the parent of the specified node passed
259 * as parameter.
260 * @tree : the child node from where we back path to the parent
261 * cb : a callback for each node the function will go over
262 * data : some private data to be passed across the callbacks
263 * Returns 0 on success, < 0 otherwise
264 */
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200265int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data)
266{
267 if (!tree)
268 return 0;
269
270 if (tree_for_each_parent(tree->parent, cb, data))
271 return -1;
272
273 return cb(tree, data);
274}
275
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200276/*
277 * The function will return the first node which match with the name as
278 * parameter.
279 * @tree : the tree where we begin to find
280 * @name : the name of the node the function must look for.
281 * Returns a pointer to the tree structure if found, NULL otherwise.
282 */
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200283struct tree *tree_find(struct tree *tree, const char *name)
284{
285 struct tree *t;
286
287 if (!tree)
288 return NULL;
289
290 if (!strcmp(tree->name, name))
291 return tree;
292
293 t = tree_find(tree->child, name);
294 if (t)
295 return t;
296
297 return tree_find(tree->next, name);
298}
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200299
300struct struct_find {
301 int nr;
302 const char *name;
303 struct tree ***ptree;
304};
305
306static int tree_finds_cb(struct tree *tree, void *data)
307{
308 struct struct_find *sf = data;
309
Daniel Lezcano528bb3f2011-06-21 00:57:08 +0200310 if (!strlen(sf->name))
311 return 0;
312
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200313 if (strncmp(sf->name, tree->name, strlen(sf->name)))
314 return 0;
315
316 if (sf->ptree)
317 (*(sf->ptree))[sf->nr] = tree;
318
319 sf->nr++;
320
321 return 0;
322}
323
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200324/*
325 * This function will search for all the nodes where the name begin
326 * with the name passed as parameter. *Note* the function allocates
327 * the array, it is up to the caller to free this array.
328 * @tree : the topmost node of the tree where we being to search
329 * @name : the name to find in the tree
330 * @ptr : a pointer to a pointer of pointer of tree structure :)
331 * Returns the number of elements found in the tree, < 0 if something
332 * went wrong.
333 */
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200334int tree_finds(struct tree *tree, const char *name, struct tree ***ptr)
335{
336 struct struct_find sf = { .nr = 0, .ptree = NULL, .name = name };
337 int nmatch;
338
339 /* first pass : count # of matching nodes */
340 tree_for_each(tree, tree_finds_cb, &sf);
341
342 /* no match */
343 if (!sf.nr)
344 return 0;
345
346 *ptr = malloc(sizeof(struct tree *) * sf.nr);
347 if (!*ptr)
348 return -1;
349
350 /* store the result as it will be overwritten by the next call */
351 nmatch = sf.nr;
352 sf.nr = 0;
353 sf.ptree = ptr;
354
355 /* second pass : fill with the matching nodes */
356 tree_for_each(tree, tree_finds_cb, &sf);
357
358 return nmatch;
359}