]> git.saurik.com Git - wxWidgets.git/blob - src/common/dircmn.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / dircmn.cpp
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>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
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"
31 #include "wx/filefn.h"
32 #include "wx/arrstr.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/dir.h"
36 #include "wx/filename.h"
37
38 // ============================================================================
39 // implementation
40 // ============================================================================
41
42 // ----------------------------------------------------------------------------
43 // wxDirTraverser
44 // ----------------------------------------------------------------------------
45
46 wxDirTraverseResult
47 wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname))
48 {
49 return wxDIR_IGNORE;
50 }
51
52 // ----------------------------------------------------------------------------
53 // wxDir::HasFiles() and HasSubDirs()
54 // ----------------------------------------------------------------------------
55
56 // dumb generic implementation
57
58 bool wxDir::HasFiles(const wxString& spec) const
59 {
60 wxString s;
61 return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN);
62 }
63
64 // we have a (much) faster version for Unix
65 #if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__EMX__) || defined(__WINE__)
66
67 bool wxDir::HasSubDirs(const wxString& spec) const
68 {
69 wxString s;
70 return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN);
71 }
72
73 #endif // !Unix
74
75 // ----------------------------------------------------------------------------
76 // wxDir::GetNameWithSep()
77 // ----------------------------------------------------------------------------
78
79 wxString 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
97 // ----------------------------------------------------------------------------
98 // wxDir::Traverse()
99 // ----------------------------------------------------------------------------
100
101 size_t wxDir::Traverse(wxDirTraverser& sink,
102 const wxString& filespec,
103 int flags) const
104 {
105 wxCHECK_MSG( IsOpened(), (size_t)-1,
106 wxT("dir must be opened before traversing it") );
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
112 const wxString prefix = GetNameWithSep();
113
114 // first, recurse into subdirs
115 if ( flags & wxDIR_DIRS )
116 {
117 wxString dirname;
118 for ( bool cont = GetFirst(&dirname, wxEmptyString,
119 (flags & ~(wxDIR_FILES | wxDIR_DOTDOT))
120 | wxDIR_DIRS);
121 cont;
122 cont = cont && GetNext(&dirname) )
123 {
124 const wxString fulldirname = prefix + dirname;
125
126 switch ( sink.OnDir(fulldirname) )
127 {
128 default:
129 wxFAIL_MSG(wxT("unexpected OnDir() return value") );
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:
157 wxFAIL_MSG(wxT("unexpected OnOpenError() return value") );
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 ;
188 }
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,
206 wxT("unexpected OnFile() return value") );
207
208 nFiles++;
209
210 cont = GetNext(&filename);
211 }
212 }
213
214 return nFiles;
215 }
216
217 // ----------------------------------------------------------------------------
218 // wxDir::GetAllFiles()
219 // ----------------------------------------------------------------------------
220
221 class wxDirTraverserSimple : public wxDirTraverser
222 {
223 public:
224 wxDirTraverserSimple(wxArrayString& files) : m_files(files) { }
225
226 virtual wxDirTraverseResult OnFile(const wxString& filename)
227 {
228 m_files.push_back(filename);
229 return wxDIR_CONTINUE;
230 }
231
232 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
233 {
234 return wxDIR_CONTINUE;
235 }
236
237 private:
238 wxArrayString& m_files;
239
240 wxDECLARE_NO_COPY_CLASS(wxDirTraverserSimple);
241 };
242
243 /* static */
244 size_t wxDir::GetAllFiles(const wxString& dirname,
245 wxArrayString *files,
246 const wxString& filespec,
247 int flags)
248 {
249 wxCHECK_MSG( files, (size_t)-1, wxT("NULL pointer in wxDir::GetAllFiles") );
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 }
263
264 // ----------------------------------------------------------------------------
265 // wxDir::FindFirst()
266 // ----------------------------------------------------------------------------
267
268 class wxDirTraverserFindFirst : public wxDirTraverser
269 {
270 public:
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
289 private:
290 wxString m_file;
291
292 wxDECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst);
293 };
294
295 /* static */
296 wxString 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 }
311
312
313 // ----------------------------------------------------------------------------
314 // wxDir::GetTotalSize()
315 // ----------------------------------------------------------------------------
316
317 #if wxUSE_LONGLONG
318
319 class wxDirTraverserSumSize : public wxDirTraverser
320 {
321 public:
322 wxDirTraverserSumSize() { }
323
324 virtual wxDirTraverseResult OnFile(const wxString& filename)
325 {
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
329 wxULongLong sz = wxFileName::GetSize(filename);
330
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; }
353 const wxArrayString& GetSkippedFiles() const
354 { return m_skippedFiles; }
355
356 protected:
357 wxULongLong m_sz;
358 wxArrayString m_skippedFiles;
359 };
360
361 wxULongLong 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;
373 if (dir.Traverse(traverser) == (size_t)-1 )
374 return wxInvalidSize;
375
376 if (filesSkipped)
377 *filesSkipped = traverser.GetSkippedFiles();
378
379 return traverser.GetTotalSize();
380 }
381
382 #endif // wxUSE_LONGLONG
383
384 // ----------------------------------------------------------------------------
385 // wxDir helpers
386 // ----------------------------------------------------------------------------
387
388 /* static */
389 bool wxDir::Exists(const wxString& dir)
390 {
391 return wxFileName::DirExists(dir);
392 }
393
394 /* static */
395 bool wxDir::Make(const wxString &dir, int perm, int flags)
396 {
397 return wxFileName::Mkdir(dir, perm, flags);
398 }
399
400 /* static */
401 bool wxDir::Remove(const wxString &dir, int flags)
402 {
403 return wxFileName::Rmdir(dir, flags);
404 }
405