blob: e681f4f4050fb8080c88e961097a360bafd9c037 [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>
20#include <string.h>
21#include <dirent.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25
26#include "tree.h"
27
28/*
29 * Allocate a tree structure and initialize the different fields.
30 *
31 * @path : the absolute path to the directory
32 * @depth : the depth in the tree
33 * Returns a tree structure on success, NULL otherwise
34 */
35static inline struct tree *tree_alloc(const char *path, int depth)
36{
37 struct tree *t;
38
39 t = malloc(sizeof(*t));
40 if (!t)
41 return NULL;
42
43 /* Full pathname */
44 t->path = strdup(path);
45 if (!t->path) {
46 free(t);
47 return NULL;
48 }
49
50 /* Basename pointer on the full path name */
51 t->name = strrchr(t->path, '/') + 1;
52
53 t->depth = depth;
54 t->tail = t;
55 t->child = NULL;
56 t->parent = NULL;
57 t->next = NULL;
58 t->prev = NULL;
59 t->private = NULL;
60
61 return t;
62}
63
64/*
65 * Free a tree structure and the fields we allocated in the
66 * tree_alloc function.
67 *
68 * @t : the tree structure to be freed
69 */
70static inline void tree_free(struct tree *t)
71{
72 free(t->path);
73 free(t);
74}
75
76/*
77 * Add at the end of the list the new list element.
78 *
79 * @head : the list to be appened
80 * @new : the new element to be added at the end of the list
81 */
82static inline void tree_add_tail(struct tree *head, struct tree *new)
83{
84 new->prev = head->tail;
85 head->tail->next = new;
86 head->tail = new;
87}
88
89/*
90 * Add a child in to a parent list, at the end of this list.
91 *
92 * @parent : the parent list to add the child
93 * @child : the child to be added
94 */
95static inline void tree_add_child(struct tree *parent, struct tree *child)
96{
97 child->parent = parent;
98
99 if (parent->child)
100 return tree_add_tail(parent->child, child);
101
102 parent->child = child;
103}
104
105/*
106 * This function will browse the directory structure and build a
107 * tree reflecting the content of the directory tree.
108 *
109 * @tree : the root node of the tree
110 * @filter : a callback to filter out the directories
111 * Returns 0 on success, -1 otherwise
112 */
113static int tree_scan(struct tree *tree, tree_filter_t filter)
114{
115 DIR *dir;
116 char *basedir, *newpath;
117 struct dirent dirent, *direntp;
118 struct stat s;
119 int ret = 0;
120
121 dir = opendir(tree->path);
122 if (!dir)
123 return -1;
124
125 while (!readdir_r(dir, &dirent, &direntp)) {
126
127 struct tree *child;
128
129 if (!direntp)
130 break;
131
132 if (direntp->d_name[0] == '.')
133 continue;
134
135 if (filter && filter(direntp->d_name))
136 continue;
137
138 ret = asprintf(&basedir, "%s", tree->path);
139 if (ret < 0)
140 return -1;
141
142 ret = basename(basedir) ? 0 : -1;
143 if (ret < 0)
144 goto out_free_basedir;
145
146 ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
147 if (ret < 0)
148 goto out_free_basedir;
149
150 ret = stat(newpath, &s);
151 if (ret)
152 goto out_free_newpath;
153
154 if (S_ISDIR(s.st_mode)) {
155
156 ret = -1;
157
158 child = tree_alloc(newpath, tree->depth + 1);
159 if (!child)
160 goto out_free_newpath;
161
162 tree_add_child(tree, child);
163
164 ret = tree_scan(child, filter);
165 }
166
167 out_free_newpath:
168 free(newpath);
169
170 out_free_basedir:
171 free(basedir);
172
173 if (ret)
174 break;
175 }
176
177 closedir(dir);
178
179 return ret;
180}
181
182/*
183 * This function takes the topmost directory path and populate the
184 * directory tree structures.
185 *
186 * @tree : a path to the topmost directory path
187 * Returns a tree structure corresponding to the root node of the
188 * directory tree representation on success, NULL otherwise
189 */
190struct tree *tree_load(const char *path, tree_filter_t filter)
191{
192 struct tree *tree;
193
194 tree = tree_alloc(path, 0);
195 if (!tree)
196 return NULL;
197
198 if (tree_scan(tree, filter)) {
199 tree_free(tree);
200 return NULL;
201 }
202
203 return tree;
204}
205
206/*
207 * This function will go over the tree passed as parameter and
208 * will call the callback passed as parameter for each node.
209 *
210 * @tree : the topmost node where we begin to browse the tree
211 * Returns 0 on success, < 0 otherwise
212 */
213int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
214{
215 if (!tree)
216 return 0;
217
218 if (cb(tree, data))
219 return -1;
220
221 if (tree_for_each(tree->child, cb, data))
222 return -1;
223
224 return tree_for_each(tree->next, cb, data);
225}