4 // Copyright (C) 2005 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 using System
.Collections
;
30 using System
.Runtime
.InteropServices
;
33 namespace Beagle
.Util
{
35 public class DirectoryWalker
{
37 public delegate bool FileFilter (string path
, string name
);
38 private delegate object FileObjectifier (string path
, string name
);
40 [DllImport ("libc", SetLastError
= true)]
41 private static extern IntPtr
opendir (string name
);
43 [DllImport ("libc", SetLastError
= true)]
44 private static extern int closedir (IntPtr dir
);
46 [DllImport ("libbeagleglue", EntryPoint
= "beagled_utils_readdir", SetLastError
= true)]
47 private static extern int sys_readdir (IntPtr dir
, [Out
] StringBuilder name
, int max_len
);
49 private static string readdir (IntPtr dir
, StringBuilder buffer
)
53 while (r
== 0 && buffer
.Length
== 0) {
54 r
= sys_readdir (dir
, buffer
, buffer
.Capacity
);
60 return buffer
.ToString ();
63 private class FileEnumerator
: IEnumerator
{
66 FileFilter file_filter
;
67 FileObjectifier file_objectifier
;
68 IntPtr dir_handle
= IntPtr
.Zero
;
70 StringBuilder name_buffer
= new StringBuilder (256);
72 public bool NamesOnly
= false;
74 public FileEnumerator (string path
,
75 FileFilter file_filter
,
76 FileObjectifier file_objectifier
)
79 this.file_filter
= file_filter
;
80 this.file_objectifier
= file_objectifier
;
86 if (dir_handle
!= IntPtr
.Zero
)
87 closedir (dir_handle
);
90 public object Current
{
92 object current_obj
= null;
93 if (current
!= null) {
94 if (file_objectifier
!= null)
95 current_obj
= file_objectifier (path
, current
);
97 current_obj
= current
;
99 current_obj
= Path
.Combine (path
, current
);
106 public bool MoveNext ()
108 bool skip_file
= false;
111 // FIXME? I think this might be a bug in mono, but the
112 // capacity of the StringBuilder can apparently shrink
113 // from underneath us. This leads to truncated filenames,
114 // and the DirectoryWalker drops them because the file
115 // doesn't exist. Adding an EnsureCapacity() here fixes
117 name_buffer
.EnsureCapacity (256);
119 current
= readdir (dir_handle
, name_buffer
);
125 if (current
== "." || current
== "..") {
128 } else if (file_filter
!= null) {
130 if (! file_filter (path
, current
))
133 } catch (Exception ex
) {
134 Logger
.Log
.Debug (ex
, "Caught exception in file_filter");
136 // If we have a filter that fails on a file,
137 // it is probably safest to skip that file.
144 if (current
== null) {
145 closedir (dir_handle
);
146 dir_handle
= IntPtr
.Zero
;
149 return current
!= null;
155 if (dir_handle
!= IntPtr
.Zero
)
156 closedir (dir_handle
);
157 dir_handle
= opendir (path
);
158 if (dir_handle
== IntPtr
.Zero
)
159 throw new DirectoryNotFoundException (path
);
163 private class FileEnumerable
: IEnumerable
{
166 FileFilter file_filter
;
167 FileObjectifier file_objectifier
;
169 public bool NamesOnly
= false;
171 public FileEnumerable (string path
,
172 FileFilter file_filter
,
173 FileObjectifier file_objectifier
)
176 this.file_filter
= file_filter
;
177 this.file_objectifier
= file_objectifier
;
180 public IEnumerator
GetEnumerator ()
183 e
= new FileEnumerator (path
, file_filter
, file_objectifier
);
184 e
.NamesOnly
= this.NamesOnly
;
189 static private bool IsFile (string path
, string name
)
191 return File
.Exists (Path
.Combine (path
, name
));
194 static private object FileInfoObjectifier (string path
, string name
)
196 return new FileInfo (Path
.Combine (path
, name
));
199 /////////////////////////////////////////////////////////////////////////////////
201 static public bool IsWalkable (string path
)
204 dir_handle
= opendir (path
);
205 if (dir_handle
== IntPtr
.Zero
)
207 closedir (dir_handle
);
211 /////////////////////////////////////////////////////////////////////////////////
213 static public IEnumerable
GetFiles (string path
)
215 return new FileEnumerable (path
, new FileFilter (IsFile
), null);
218 static public IEnumerable
GetFiles (DirectoryInfo dirinfo
)
220 return GetFiles (dirinfo
.FullName
);
223 static public IEnumerable
GetFileInfos (string path
)
225 return new FileEnumerable (path
,
226 new FileFilter (IsFile
),
227 new FileObjectifier (FileInfoObjectifier
));
230 static public IEnumerable
GetFileInfos (DirectoryInfo dirinfo
)
232 return GetFileInfos (dirinfo
.FullName
);
235 static private bool IsDirectory (string path
, string name
)
237 return Directory
.Exists (Path
.Combine (path
, name
));
240 static private object DirectoryInfoObjectifier (string path
, string name
)
242 return new DirectoryInfo (Path
.Combine (path
, name
));
245 static public IEnumerable
GetDirectories (string path
)
247 return new FileEnumerable (path
, new FileFilter (IsDirectory
), null);
250 static public IEnumerable
GetDirectories (DirectoryInfo dirinfo
)
252 return GetDirectories (dirinfo
.FullName
);
255 static public IEnumerable
GetDirectoryNames (string path
)
258 fe
= new FileEnumerable (path
, new FileFilter (IsDirectory
), null);
263 static public IEnumerable
GetDirectoryInfos (string path
)
265 return new FileEnumerable (path
,
266 new FileFilter (IsDirectory
),
267 new FileObjectifier (DirectoryInfoObjectifier
));
270 static public IEnumerable
GetDirectoryInfos (DirectoryInfo dirinfo
)
272 return GetDirectoryInfos (dirinfo
.FullName
);
275 static public IEnumerable
GetItems (string path
, FileFilter filter
)
277 return new FileEnumerable (path
, filter
, null);
280 static public IEnumerable
GetFileInfosRecursive (string path
)
282 foreach (FileInfo i
in DirectoryWalker
.GetFileInfos (path
))
285 foreach (string dir
in DirectoryWalker
.GetDirectories (path
)) {
286 foreach (FileInfo i
in GetFileInfosRecursive (dir
))
293 static public IEnumerable
GetFileInfosRecursive (DirectoryInfo dirinfo
)
295 return GetFileInfosRecursive (dirinfo
.FullName
);