]> git.saurik.com Git - wxWidgets.git/blame - src/common/dircmn.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / dircmn.cpp
CommitLineData
35332784
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/dircmn.cpp
3// Purpose: wxDir methods common to all implementations
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 19.05.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
526954c5 9// Licence: wxWindows licence
35332784
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
35332784
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28 #include "wx/string.h"
29 #include "wx/log.h"
30 #include "wx/intl.h"
bdfeadca 31 #include "wx/filefn.h"
aaa6d89a 32 #include "wx/arrstr.h"
35332784
VZ
33#endif //WX_PRECOMP
34
35#include "wx/dir.h"
23b8a262 36#include "wx/filename.h"
35332784
VZ
37
38// ============================================================================
39// implementation
40// ============================================================================
41
350777b6
VZ
42// ----------------------------------------------------------------------------
43// wxDirTraverser
44// ----------------------------------------------------------------------------
45
46wxDirTraverseResult
47wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname))
48{
49 return wxDIR_IGNORE;
50}
51
35332784 52// ----------------------------------------------------------------------------
1357a7dd
VZ
53// wxDir::HasFiles() and HasSubDirs()
54// ----------------------------------------------------------------------------
55
56// dumb generic implementation
57
106dcc2c 58bool wxDir::HasFiles(const wxString& spec) const
1357a7dd
VZ
59{
60 wxString s;
61 return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN);
62}
63
64// we have a (much) faster version for Unix
420b39aa 65#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__EMX__) || defined(__WINE__)
1357a7dd 66
106dcc2c 67bool wxDir::HasSubDirs(const wxString& spec) const
1357a7dd
VZ
68{
69 wxString s;
70 return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN);
71}
72
73#endif // !Unix
74
c9f6f0a8
VZ
75// ----------------------------------------------------------------------------
76// wxDir::GetNameWithSep()
77// ----------------------------------------------------------------------------
78
79wxString wxDir::GetNameWithSep() const
80{
81 // Note that for historical reasons (i.e. because GetName() was there
82 // first) we implement this one in terms of GetName() even though it might
83 // actually make more sense to reverse this logic.
84
85 wxString name = GetName();
86 if ( !name.empty() )
87 {
88 // Notice that even though GetName() isn't supposed to return the
89 // separator, it can still be present for the root directory name.
90 if ( name.Last() != wxFILE_SEP_PATH )
91 name += wxFILE_SEP_PATH;
92 }
93
94 return name;
95}
96
1357a7dd 97// ----------------------------------------------------------------------------
35332784
VZ
98// wxDir::Traverse()
99// ----------------------------------------------------------------------------
100
101size_t wxDir::Traverse(wxDirTraverser& sink,
102 const wxString& filespec,
103 int flags) const
104{
105 wxCHECK_MSG( IsOpened(), (size_t)-1,
9a83f860 106 wxT("dir must be opened before traversing it") );
35332784
VZ
107
108 // the total number of files found
109 size_t nFiles = 0;
110
111 // the name of this dir with path delimiter at the end
c9f6f0a8 112 const wxString prefix = GetNameWithSep();
35332784
VZ
113
114 // first, recurse into subdirs
115 if ( flags & wxDIR_DIRS )
116 {
117 wxString dirname;
6bf11d67
VZ
118 for ( bool cont = GetFirst(&dirname, wxEmptyString,
119 (flags & ~(wxDIR_FILES | wxDIR_DOTDOT))
120 | wxDIR_DIRS);
350777b6 121 cont;
51485b76 122 cont = cont && GetNext(&dirname) )
35332784 123 {
350777b6 124 const wxString fulldirname = prefix + dirname;
35332784 125
350777b6 126 switch ( sink.OnDir(fulldirname) )
35332784 127 {
350777b6 128 default:
9a83f860 129 wxFAIL_MSG(wxT("unexpected OnDir() return value") );
350777b6
VZ
130 // fall through
131
132 case wxDIR_STOP:
133 cont = false;
134 break;
135
136 case wxDIR_CONTINUE:
137 {
138 wxDir subdir;
139
140 // don't give the error messages for the directories
141 // which we can't open: there can be all sorts of good
142 // reason for this (e.g. insufficient privileges) and
143 // this shouldn't be treated as an error -- instead
144 // let the user code decide what to do
145 bool ok;
146 do
147 {
148 wxLogNull noLog;
149 ok = subdir.Open(fulldirname);
150 if ( !ok )
151 {
152 // ask the user code what to do
153 bool tryagain;
154 switch ( sink.OnOpenError(fulldirname) )
155 {
156 default:
9a83f860 157 wxFAIL_MSG(wxT("unexpected OnOpenError() return value") );
350777b6
VZ
158 // fall through
159
160 case wxDIR_STOP:
161 cont = false;
162 // fall through
163
164 case wxDIR_IGNORE:
165 tryagain = false;
166 break;
167
168 case wxDIR_CONTINUE:
169 tryagain = true;
170 }
171
172 if ( !tryagain )
173 break;
174 }
175 }
176 while ( !ok );
177
178 if ( ok )
179 {
180 nFiles += subdir.Traverse(sink, filespec, flags);
181 }
182 }
183 break;
184
185 case wxDIR_IGNORE:
186 // nothing to do
187 ;
35332784 188 }
35332784
VZ
189 }
190 }
191
192 // now enum our own files
193 if ( flags & wxDIR_FILES )
194 {
195 flags &= ~wxDIR_DIRS;
196
197 wxString filename;
198 bool cont = GetFirst(&filename, filespec, flags);
199 while ( cont )
200 {
201 wxDirTraverseResult res = sink.OnFile(prefix + filename);
202 if ( res == wxDIR_STOP )
203 break;
204
205 wxASSERT_MSG( res == wxDIR_CONTINUE,
9a83f860 206 wxT("unexpected OnFile() return value") );
35332784
VZ
207
208 nFiles++;
209
210 cont = GetNext(&filename);
211 }
212 }
213
214 return nFiles;
215}
216
217// ----------------------------------------------------------------------------
218// wxDir::GetAllFiles()
219// ----------------------------------------------------------------------------
220
221class wxDirTraverserSimple : public wxDirTraverser
222{
223public:
224 wxDirTraverserSimple(wxArrayString& files) : m_files(files) { }
225
226 virtual wxDirTraverseResult OnFile(const wxString& filename)
227 {
df5168c4 228 m_files.push_back(filename);
35332784
VZ
229 return wxDIR_CONTINUE;
230 }
231
232 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
233 {
234 return wxDIR_CONTINUE;
235 }
236
237private:
238 wxArrayString& m_files;
fc7a2a60 239
c0c133e1 240 wxDECLARE_NO_COPY_CLASS(wxDirTraverserSimple);
35332784
VZ
241};
242
243/* static */
244size_t wxDir::GetAllFiles(const wxString& dirname,
245 wxArrayString *files,
246 const wxString& filespec,
247 int flags)
248{
9a83f860 249 wxCHECK_MSG( files, (size_t)-1, wxT("NULL pointer in wxDir::GetAllFiles") );
35332784
VZ
250
251 size_t nFiles = 0;
252
253 wxDir dir(dirname);
254 if ( dir.IsOpened() )
255 {
256 wxDirTraverserSimple traverser(*files);
257
258 nFiles += dir.Traverse(traverser, filespec, flags);
259 }
260
261 return nFiles;
262}
d1af8e2d
VZ
263
264// ----------------------------------------------------------------------------
265// wxDir::FindFirst()
266// ----------------------------------------------------------------------------
267
268class wxDirTraverserFindFirst : public wxDirTraverser
269{
270public:
271 wxDirTraverserFindFirst() { }
272
273 virtual wxDirTraverseResult OnFile(const wxString& filename)
274 {
275 m_file = filename;
276 return wxDIR_STOP;
277 }
278
279 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
280 {
281 return wxDIR_CONTINUE;
282 }
283
284 const wxString& GetFile() const
285 {
286 return m_file;
287 }
288
289private:
290 wxString m_file;
291
c0c133e1 292 wxDECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst);
d1af8e2d
VZ
293};
294
295/* static */
296wxString wxDir::FindFirst(const wxString& dirname,
297 const wxString& filespec,
298 int flags)
299{
300 wxDir dir(dirname);
301 if ( dir.IsOpened() )
302 {
303 wxDirTraverserFindFirst traverser;
304
305 dir.Traverse(traverser, filespec, flags | wxDIR_FILES);
306 return traverser.GetFile();
307 }
308
309 return wxEmptyString;
310}
23b8a262
JS
311
312
313// ----------------------------------------------------------------------------
314// wxDir::GetTotalSize()
315// ----------------------------------------------------------------------------
316
bd08f2f7
VZ
317#if wxUSE_LONGLONG
318
23b8a262
JS
319class wxDirTraverserSumSize : public wxDirTraverser
320{
321public:
a8df8389 322 wxDirTraverserSumSize() { }
23b8a262
JS
323
324 virtual wxDirTraverseResult OnFile(const wxString& filename)
325 {
23b8a262
JS
326 // wxFileName::GetSize won't use this class again as
327 // we're passing it a file and not a directory;
328 // thus we are sure to avoid an endless loop
191d6608
VZ
329 wxULongLong sz = wxFileName::GetSize(filename);
330
23b8a262
JS
331 if (sz == wxInvalidSize)
332 {
333 // if the GetSize() failed (this can happen because e.g. a
334 // file is locked by another process), we can proceed but
335 // we need to at least warn the user that the resulting
336 // final size could be not reliable (if e.g. the locked
337 // file is very big).
338 m_skippedFiles.Add(filename);
339 return wxDIR_CONTINUE;
340 }
341
342 m_sz += sz;
343 return wxDIR_CONTINUE;
344 }
345
346 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
347 {
348 return wxDIR_CONTINUE;
349 }
350
351 wxULongLong GetTotalSize() const
352 { return m_sz; }
191d6608 353 const wxArrayString& GetSkippedFiles() const
23b8a262
JS
354 { return m_skippedFiles; }
355
356protected:
357 wxULongLong m_sz;
358 wxArrayString m_skippedFiles;
359};
360
361wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped)
362{
363 if (!wxDirExists(dirname))
364 return wxInvalidSize;
365
366 // to get the size of this directory and its contents we need
367 // to recursively walk it...
368 wxDir dir(dirname);
369 if ( !dir.IsOpened() )
370 return wxInvalidSize;
371
372 wxDirTraverserSumSize traverser;
852febd8 373 if (dir.Traverse(traverser) == (size_t)-1 )
23b8a262
JS
374 return wxInvalidSize;
375
376 if (filesSkipped)
191d6608 377 *filesSkipped = traverser.GetSkippedFiles();
23b8a262
JS
378
379 return traverser.GetTotalSize();
380}
381
f422aafe
VZ
382#endif // wxUSE_LONGLONG
383
d38315df
FM
384// ----------------------------------------------------------------------------
385// wxDir helpers
386// ----------------------------------------------------------------------------
387
388/* static */
389bool wxDir::Exists(const wxString& dir)
390{
391 return wxFileName::DirExists(dir);
392}
393
394/* static */
395bool wxDir::Make(const wxString &dir, int perm, int flags)
396{
397 return wxFileName::Mkdir(dir, perm, flags);
398}
399
400/* static */
401bool wxDir::Remove(const wxString &dir, int flags)
402{
403 return wxFileName::Rmdir(dir, flags);
404}
ce00f59b 405