gliv-1.1.3
[gliv.git] / ftw.c
blobe205b4187afc0ee96747fa9b78778861097b6038
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <booh@altern.org>
21 /*******************************************************
22 * FTW implementation that your system shouldn't lack. *
23 *******************************************************/
25 /* No #include <...> as this file is #included in loading.c */
27 #define FTW_F 0
28 #define FTW_D 1
29 #define FTW_DNR 2
30 #define FTW_NS 3
32 typedef struct {
33 dev_t st_dev;
34 ino_t st_ino;
35 } mini_stat;
37 typedef int (*ftw_func) (const char *name, const struct stat * st, int unused);
39 int ftw(const char *filename, ftw_func func, int unused);
40 static void ftw_rec(const char *filename, ftw_func func);
42 static int list_length;
43 static mini_stat *list;
45 static void append_to_list(dev_t dev, ino_t ino)
47 list_length++;
48 list = realloc(list, list_length * sizeof(mini_stat));
49 list[list_length - 1].st_dev = dev;
50 list[list_length - 1].st_ino = ino;
53 static int is_in_list(dev_t dev, ino_t ino)
55 int i = 0;
57 for (i = 0; i < list_length; i++) {
58 if (list[i].st_ino == ino && list[i].st_dev == dev)
59 return 1;
61 return 0;
64 /* Returns 0 if path is neither ".." nor "." to avoid infinite recursion. */
65 static int path_ok(const char *path)
67 if (path == NULL)
68 return -1;
69 if (path[0] == '.') {
70 if ((path[1] == '\0') || (path[1] == '.' && path[2] == '\0'))
71 return -1;
73 return 0;
76 static void ftw_dir(const char *dirname, ftw_func func)
78 struct dirent *dir_ent;
79 DIR *dir;
80 int dir_len;
81 char *name;
82 struct stat st;
84 stat(dirname, &st);
85 append_to_list(st.st_dev, st.st_ino);
87 /* 2 = (1 for '/') + (1 for '\0') */
88 dir_len = strlen(dirname) + 2;
90 dir = opendir(dirname);
91 if (dir == NULL) {
92 (*func) (dirname, &st, FTW_DNR);
93 return;
96 dir_ent = readdir(dir);
98 while (dir_ent != NULL) {
99 if (path_ok(dir_ent->d_name) == 0) {
100 name = malloc((dir_len + strlen(dir_ent->d_name)) * sizeof(char));
101 sprintf(name, "%s/%s", dirname, dir_ent->d_name);
102 ftw_rec(name, func);
103 free(name);
105 dir_ent = readdir(dir);
107 closedir(dir);
110 static void ftw_rec(const char *filename, ftw_func func)
112 struct stat st;
114 lstat(filename, &st);
115 if (S_ISLNK(st.st_mode)) {
116 /* We have a symbolic link. */
117 stat(filename, &st);
118 if (S_ISDIR(st.st_mode) && is_in_list(st.st_dev, st.st_ino)) {
120 * We already traversed this directory so
121 * adding it may cause infinite recursion.
123 return;
127 if (S_ISDIR(st.st_mode)) {
128 ftw_dir(filename, func);
129 (*func) (filename, &st, FTW_D);
130 } else
131 (*func) (filename, &st, FTW_F);
134 int ftw(const char *filename, ftw_func func, int unused)
136 struct stat st;
138 if (lstat(filename, &st) == -1) {
139 (*func) (filename, &st, FTW_NS);
140 return -1;
143 list = NULL;
144 list_length = 0;
146 ftw_rec(filename, func);
148 free(list);
149 return 0;