blob: a7f42497e52c547c82ed86dfb97a63de9fb71d4a [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/exception.h>
42#include <cc++/file.h>
43#include "private.h"
44
45#ifdef WIN32
46#include <sys/stat.h>
47#include <malloc.h>
48#endif
49
50#ifdef CCXX_NAMESPACES
51namespace ost {
52using namespace std;
53#endif
54
55Dir::Dir(const char *fname) :
56#ifdef WIN32
57hDir(INVALID_HANDLE_VALUE), name(NULL)
58#else
59dir(NULL)
60#endif
61{
62#ifdef HAVE_READDIR_R
63 save = reinterpret_cast<struct dirent*>(save_space);
64#endif
65 if(fname)
66 open(fname);
67}
68
69bool Dir::create(const char *path, Attr attr)
70{
71 long xmask = 0;
72 bool rtn = true;
73#ifdef WIN32
74
75 // fixme: make it form a security attributes structure
76
77 if(!CreateDirectory(path, NULL))
78 rtn = false;
79#else
80 switch(attr) {
81 case attrPublic:
82 xmask |= S_IXOTH;
83 case attrGroup:
84 xmask |= S_IXGRP;
85 case attrPrivate:
86 xmask |= S_IXUSR;
87 break;
88 default:
89 return false;
90 }
91 if(mkdir(path, (long)attr | xmask))
92 rtn = false;
93#endif
94 return rtn;
95}
96
97bool Dir::remove(const char *path)
98{
99 bool rtn = true;
100#ifdef WIN32
101 if(!RemoveDirectory(path))
102 rtn = false;
103#else
104 if(rmdir(path))
105 rtn = false;
106#endif
107 return rtn;
108}
109
110bool Dir::setPrefix(const char *prefix)
111{
112 bool rtn = true;
113
114#ifdef WIN32
115 if(!SetCurrentDirectory(prefix))
116 rtn = false;
117#else
118 if(chdir(prefix))
119 rtn = false;
120#endif
121 return rtn;
122}
123
124bool Dir::getPrefix(char *prefix, size_t size)
125{
126 bool rtn = true;
127
128#ifdef WIN32
129 if(!GetCurrentDirectory((DWORD)size, prefix))
130 rtn = false;
131#else
132 if(getcwd(prefix, size) == NULL)
133 rtn = false;
134#endif
135 return rtn;
136}
137
138void Dir::open(const char *fname)
139{
140#ifdef WIN32
141 size_t len = strlen(fname) + 4;
142 char *path;
143#endif
144
145 close();
146#ifdef WIN32
147 DWORD attr = GetFileAttributes(fname);
148 if( (attr == (DWORD)~0l) || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) {
149#ifdef CCXX_EXCEPTIONS
150 if(Thread::getException() == Thread::throwObject)
151 throw(this);
152#ifdef COMMON_STD_EXCEPTION
153 else if(Thread::getException() == Thread::throwException)
154 throw(DirException(String(fname) + ": failed"));
155#endif
156#endif
157 }
158
159 path = (char *)alloca(len + 1);
160 if(path)
161 snprintf(path, len + 1, "%s", fname);
162#ifdef CCXX_EXCEPTIONS
163 if (!path && Thread::getException() == Thread::throwObject)
164 throw(this);
165#ifdef COMMON_STD_EXCEPTION
166 else if(!path && Thread::getException() == Thread::throwException)
167 throw(DirException(String(fname) + ": failed"));
168#endif
169#endif
170 addString(path, len, "\\*");
171 hDir = FindFirstFile(path, &fdata);
172 if(hDir != INVALID_HANDLE_VALUE)
173 name = fdata.cFileName;
174 memcpy(&data, &fdata, sizeof(fdata));
175
176#else // WIN32
177 entry = NULL;
178 dir = opendir(fname);
179#ifdef CCXX_EXCEPTIONS
180 if(!dir && Thread::getException() == Thread::throwObject)
181 throw(this);
182#ifdef COMMON_STD_EXCEPTION
183 else if(!dir && Thread::getException() == Thread::throwException)
184 throw(DirException(String(fname) + ": failed"));
185#endif
186#endif
187#endif // WIN32
188}
189
190Dir::~Dir()
191{
192 close();
193}
194
195void Dir::close(void)
196{
197#ifdef WIN32
198 if(hDir != INVALID_HANDLE_VALUE)
199 FindClose(hDir);
200 hDir = INVALID_HANDLE_VALUE;
201#else
202 if(dir)
203 closedir(dir);
204 dir = NULL;
205 entry = NULL;
206#endif
207}
208
209bool Dir::rewind(void)
210{
211 bool rtn = true;
212#ifdef WIN32
213 memcpy(&data, &fdata, sizeof(data));
214 name = fdata.cFileName;
215#else
216 if(!dir)
217 rtn = false;
218 else
219 rewinddir(dir);
220#endif
221 return rtn;
222}
223
224bool Dir::isValid(void)
225{
226#ifdef WIN32
227 if(hDir == INVALID_HANDLE_VALUE)
228#else
229 if(!dir)
230#endif
231 return false;
232
233 return true;
234}
235
236const char *Dir::operator*()
237{
238#ifdef WIN32
239 return name;
240#else
241 if(!dir)
242 return NULL;
243
244 if(!entry)
245 return getName();
246
247 return entry->d_name;
248#endif
249}
250
251const char *Dir::getName(void)
252{
253#ifdef WIN32
254 char *retname = name;
255
256 if(hDir == INVALID_HANDLE_VALUE)
257 return NULL;
258
259 if(retname) {
260 name = NULL;
261 if(FindNextFile(hDir, &data))
262 name = data.cFileName;
263 }
264 return retname;
265
266#else
267 if(!dir)
268 return NULL;
269
270#ifdef HAVE_READDIR_R
271 readdir_r(dir, save, &entry);
272#else
273 entry = readdir(dir);
274#endif
275 if(!entry)
276 return NULL;
277
278 return entry->d_name;
279#endif // WIN32
280}
281
282DirTree::DirTree(const char *prefix, unsigned depth)
283{
284 max = ++depth;
285 dir = new Dir[depth];
286 current = 0;
287
288 open(prefix);
289}
290
291DirTree::DirTree(unsigned depth)
292{
293 max = ++depth;
294 dir = new Dir[depth];
295 current = 0;
296}
297
298void DirTree::open(const char *prefix)
299{
300 char *cp;
301
302 close();
303
304 if(!isDir(prefix))
305 return;
306
307 snprintf(path, sizeof(path), "%s/", prefix);
308 prefixpos = (unsigned)strlen(path) - 1;
309
310 while(NULL != (cp = strchr(path, '\\')))
311 *cp = '/';
312
313 while(prefixpos && path[prefixpos - 1] == '/')
314 path[prefixpos--] = 0;
315
316 dir[current++].open(prefix);
317}
318
319DirTree::~DirTree()
320{
321 close();
322
323 if(dir)
324 delete[] dir;
325
326 dir = NULL;
327}
328
329unsigned DirTree::perform(const char *prefix)
330{
331 unsigned count = 0;
332
333 open(prefix);
334 while(NULL != (getPath()))
335 ++count;
336 close();
337 return count;
338}
339
340void DirTree::close(void)
341{
342 while(current--)
343 dir[current].close();
344
345 current = 0;
346}
347
348
349bool DirTree::filter(const char *path, struct stat *ino)
350{
351 path = strrchr(path, '/');
352
353 if(path)
354 ++path;
355 else
356 return false;
357
358 if(!strcmp(path, "."))
359 return false;
360
361 if(!strcmp(path, ".."))
362 return false;
363
364 if(!ino)
365 return false;
366
367 return true;
368}
369
370char *DirTree::getPath(void)
371{
372 char *cp;
373 const char *name;
374 struct stat ino;
375 bool flag;
376
377 while(current) {
378 cp = strrchr(path, '/');
379 name = dir[current - 1].getName();
380 if(!name) {
381 *cp = 0;
382 dir[--current].close();
383 continue;
384 }
385 snprintf(cp + 1, sizeof(path) - strlen(path) - 2, "%s", name);
386
387 if(::stat(path, &ino)) {
388 ino.st_mode = 0;
389 flag = filter(path, NULL);
390 }
391 else
392 flag = filter(path, &ino);
393
394 if(!flag)
395 continue;
396
397 if((ino.st_mode & S_IFMT) == S_IFDIR) {
398 if(!canAccess(path))
399 break;
400
401 if(current < max)
402 dir[current++].open(path);
403
404 snprintf(path + strlen(path), sizeof(path) - strlen(path), "/");
405 }
406 break;
407 }
408 if(!current)
409 return NULL;
410
411 return path;
412}
413
414#ifdef CCXX_NAMESPACES
415}
416#endif
417
418/** EMACS **
419 * Local variables:
420 * mode: c++
421 * c-basic-offset: 4
422 * End:
423 */