modified: n.fq
[GalaxyCodeBases.git] / tools / torrent / mktorrent_crc / ftw.c
bloba7f013d55dd5b7a11f3fa08f65529499ef3390c0
1 /*
2 This file is part of mktorrent
3 Copyright (C) 2009 Emil Renner Berthing
5 mktorrent is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mktorrent is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #ifndef ALLINONE
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <dirent.h>
29 #ifdef _WIN32
30 #define DIRSEP_CHAR '\\'
31 #else
32 #define DIRSEP_CHAR '/'
33 #endif /* _WIN32 */
35 #define EXPORT
36 #endif /* ALLINONE */
38 #include "ftw.h"
40 struct dir_state {
41 struct dir_state *next;
42 struct dir_state *prev;
43 size_t length;
44 DIR *dir;
45 off_t offset;
48 static struct dir_state *dir_state_new(struct dir_state *prev,
49 struct dir_state *next)
51 struct dir_state *ds = malloc(sizeof(struct dir_state));
53 if (ds == NULL) {
54 fprintf(stderr, "Out of memory.\n");
55 return NULL;
58 ds->prev = prev;
59 ds->next = next;
61 return ds;
64 static unsigned int dir_state_open(struct dir_state *ds, const char *name,
65 size_t length)
67 ds->dir = opendir(name);
68 if (ds->dir == NULL) {
69 fprintf(stderr, "Error opening '%s': %s\n",
70 name, strerror(errno));
71 return 1;
74 ds->length = length;
76 return 0;
79 static unsigned int dir_state_reopen(struct dir_state *ds, char *name)
81 name[ds->length] = '\0';
82 ds->dir = opendir(name);
83 if (ds->dir == NULL) {
84 fprintf(stderr, "Error opening '%s': %s\n",
85 name, strerror(errno));
86 return 1;
89 name[ds->length] = DIRSEP_CHAR;
91 seekdir(ds->dir, ds->offset);
93 return 0;
96 static unsigned int dir_state_close(struct dir_state *ds)
98 ds->offset = telldir(ds->dir);
99 if (ds->offset < 0) {
100 fprintf(stderr, "Error getting dir offset: %s\n",
101 strerror(errno));
102 return 1;
105 if (closedir(ds->dir)) {
106 fprintf(stderr, "Error closing directory: %s\n",
107 strerror(errno));
108 return 1;
111 ds->dir = NULL;
113 return 0;
116 static unsigned int cleanup(struct dir_state *ds, char *path, int ret)
118 while (ds->prev)
119 ds = ds->prev;
121 do {
122 struct dir_state *next = ds->next;
123 free(ds);
124 ds = next;
125 } while (ds);
127 if (path)
128 free(path);
130 return ret;
133 EXPORT int file_tree_walk(const char *dirname, unsigned int nfds,
134 file_tree_walk_cb callback, void *data)
136 size_t path_size = 256;
137 char *path;
138 char *path_max;
139 char *end;
140 struct dir_state *ds = dir_state_new(NULL, NULL);
141 struct dir_state *first_open;
142 unsigned int nopen;
144 if (ds == NULL)
145 return -1;
147 path = malloc(path_size);
148 if (path == NULL) {
149 fprintf(stderr, "Out of memory.\n");
150 return cleanup(ds, NULL, -1);
152 path_max = path + path_size;
154 /* copy dirname to path */
155 end = path;
156 while ((*end = *dirname)) {
157 dirname++;
158 end++;
159 if (end == path_max) {
160 char *new_path;
162 new_path = realloc(path, 2*path_size);
163 if (new_path == NULL) {
164 fprintf(stderr, "Out of memory.\n");
165 return cleanup(ds, path, -1);
167 end = new_path + path_size;
168 path_size *= 2;
169 path = new_path;
170 path_max = path + path_size;
174 /* strip ending directory separators */
175 while (end > path && *(end-1) == DIRSEP_CHAR) {
176 end--;
177 *end = '\0';
180 if (dir_state_open(ds, path, end - path))
181 return cleanup(ds, path, -1);
183 first_open = ds;
184 nopen = 1;
186 *end = DIRSEP_CHAR;
188 while (1) {
189 struct dirent *de = readdir(ds->dir);
191 if (de) {
192 struct stat sbuf;
193 const char *p;
194 int r;
196 if (de->d_name[0] == '.'
197 && (de->d_name[1] == '\0'
198 || (de->d_name[1] == '.'
199 && de->d_name[2] == '\0'))) {
200 continue;
203 end = path + ds->length + 1;
204 p = de->d_name;
205 while ((*end = *p)) {
206 p++;
207 end++;
208 if (end == path_max) {
209 char *new_path;
211 new_path = realloc(path, 2*path_size);
212 if (new_path == NULL) {
213 fprintf(stderr, "Out of memory.\n");
214 return cleanup(ds, path, -1);
216 end = new_path + path_size;
217 path_size *= 2;
218 path = new_path;
219 path_max = path + path_size;
223 if (stat(path, &sbuf)) {
224 fprintf(stderr, "Error stat'ing '%s': %s\n",
225 path, strerror(errno));
226 return cleanup(ds, path, -1);
229 r = callback(path, &sbuf, data);
230 if (r)
231 return cleanup(ds, path, r);
233 if (S_ISDIR(sbuf.st_mode)) {
234 if (ds->next == NULL &&
235 (ds->next = dir_state_new(ds, NULL)) == NULL)
236 return cleanup(ds, path, -1);
238 ds = ds->next;
240 if (nopen == nfds) {
241 if (dir_state_close(first_open))
242 return cleanup(ds, path, -1);
243 first_open = first_open->next;
244 nopen--;
247 if (dir_state_open(ds, path, end - path))
248 return cleanup(ds, path, -1);
250 nopen++;
252 *end = DIRSEP_CHAR;
254 } else {
255 if (closedir(ds->dir)) {
256 path[ds->length] = '\0';
257 fprintf(stderr, "Error closing '%s': %s\n",
258 path, strerror(errno));
259 return cleanup(ds, path, -1);
262 if (ds->prev == NULL)
263 break;
265 ds = ds->prev;
266 nopen--;
268 if (ds->dir == NULL) {
269 if (dir_state_reopen(ds, path))
270 return cleanup(ds, path, -1);
271 first_open = ds;
272 nopen++;
277 return cleanup(ds, path, 0);