2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NGDirectoryEnumerator.h"
23 #import <Foundation/NSFileManager.h>
26 @interface NGDirectoryEnumerator(PrivateMethods)
27 - (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)_name;
32 @interface NGDirEntry : NSObject
40 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
41 path:(NSString *)_path;
43 - (NSString *)readdir;
47 @implementation NGDirectoryEnumerator
49 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
50 directoryPath:(NSString *)_path
51 recurseIntoSubdirectories:(BOOL)_recurse
52 followSymlinks:(BOOL)_follow
53 prefixFiles:(BOOL)_prefix
55 self->fileManager = _fm
57 : [[NSFileManager defaultManager] retain];
59 self->pathStack = [[NSMutableArray alloc] init];
60 self->enumStack = [[NSMutableArray alloc] init];
61 self->flags.isRecursive = _recurse;
62 self->flags.isFollowing = _follow;
64 self->topPath = [_path copy];
66 [self recurseIntoDirectory:_path relativeName:@""];
71 - (id)initWithDirectoryPath:(NSString *)_path
72 recurseIntoSubdirectories:(BOOL)_recurse
73 followSymlinks:(BOOL)_follow
74 prefixFiles:(BOOL)_prefix
76 return [self initWithFileManager:nil
78 recurseIntoSubdirectories:_recurse
79 followSymlinks:_follow
83 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm {
84 return [self initWithFileManager:_fm
86 recurseIntoSubdirectories:YES
90 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
91 directoryPath:(NSString *)_path
93 return [self initWithFileManager:_fm
95 recurseIntoSubdirectories:YES
101 while ([self->pathStack count])
104 [self->pathStack release];
105 [self->enumStack release];
106 [self->currentFileName release];
107 [self->currentFilePath release];
108 [self->topPath release];
115 - (id<NSObject,NGFileManager>)fileManager {
116 return self->fileManager;
121 - (NSDictionary *)directoryAttributes {
122 return [self->fileManager
123 fileAttributesAtPath:self->topPath
124 traverseLink:self->flags.isFollowing];
127 - (NSDictionary *)fileAttributes {
128 return [self->fileManager
129 fileAttributesAtPath:self->currentFilePath
130 traverseLink:self->flags.isFollowing];
133 - (void)skipDescendents {
134 if ([self->pathStack count])
142 return self->currentFileName;
147 - (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)name {
149 recurses into directory `path'
150 - pushes relative path (relative to root of search) on pathStack
151 - pushes system dir enumerator on enumPath
155 //NSLog(@"RECURSE INTO: %@", _path);
157 dir = [[NGDirEntry alloc] initWithFileManager:self->fileManager path:_path];
160 [pathStack addObject:name];
161 [enumStack addObject:dir];
167 backtracks enumeration to the previous dir
168 - pops current dir relative path from pathStack
169 - pops system dir enumerator from enumStack
170 - sets currentFile* to nil
172 //NSLog(@"BACKTRACK: %@", [self->pathStack lastObject]);
173 [self->enumStack removeLastObject];
174 [self->pathStack removeLastObject];
175 [self->currentFileName release]; self->currentFileName = nil;
176 [self->currentFilePath release]; self->currentFilePath = nil;
179 - (void)findNextFile {
181 finds the next file according to the top enumerator
182 - if there is a next file it is put in currentFile
183 - if the current file is a directory and if isRecursive calls
184 recurseIntoDirectory:currentFile
185 - if the current file is a symlink to a directory and if isRecursive
186 and isFollowing calls recurseIntoDirectory:currentFile
187 - if at end of current directory pops stack and attempts to
188 find the next entry in the parent
189 - sets currentFile to nil if there are no more files to enumerate
193 [self->currentFileName release]; self->currentFileName = nil;
194 [self->currentFilePath release]; self->currentFilePath = nil;
196 while ([self->pathStack count]) {
200 dir = [enumStack lastObject];
202 if ((dname = [dir readdir]) == nil) {
203 /* If we reached the end of this directory, go back to the upper one */
208 /* Skip "." and ".." directory entries */
210 if ([dname isEqualToString:@"."]) continue;
211 if ([dname isEqualToString:@".."]) continue;
213 /* Name of current file */
215 self->currentFileName =
216 [[[pathStack lastObject]
217 stringByAppendingPathComponent:dname]
220 /* Full path of current file */
222 self->currentFilePath =
223 [[self->topPath stringByAppendingPathComponent:self->currentFileName]
226 dtype = [[self->fileManager
227 fileAttributesAtPath:self->currentFilePath
228 traverseLink:self->flags.isFollowing]
229 objectForKey:NSFileType];
231 // do not follow links
233 if (!flags.isFollowing) {
234 if ([dtype isEqualToString:NSFileTypeSymbolicLink])
235 /* if link then return it as link */
239 /* Follow links - check for directory */
241 if ([dtype isEqualToString:NSFileTypeDirectory] &&
242 self->flags.isRecursive) {
243 [self recurseIntoDirectory:self->currentFilePath
244 relativeName:self->currentFileName];
251 - (NSString *)description {
254 ms = [NSMutableString stringWithCapacity:128];
256 [ms appendFormat:@"<%@[0x%p]: ", NSStringFromClass([self class]), self];
258 [ms appendFormat:@" dir='%@'", self->topPath];
259 [ms appendFormat:@" cname='%@'", self->currentFileName];
260 [ms appendFormat:@" cpath='%@'", self->currentFilePath];
261 [ms appendString:@">"];
266 @end /* NGDirectoryEnumerator */
268 @implementation NGDirEntry
270 - (id)initWithFileManager:(id<NSObject, NGFileManager>)_fm path:(NSString *)_p{
271 self->fileManager = [_fm retain];
272 self->path = [_p copy];
278 [self->path release];
279 [self->fileManager release];
285 - (NSString *)readdir {
288 if (self->e == nil) {
289 self->e = [[[self->fileManager directoryContentsAtPath:self->path]
290 sortedArrayUsingSelector:
293 self->e = [self->e retain];
296 s = [self->e nextObject];
297 // [self logWithFormat:@"readdir: %@", s];
302 @end /* NGDirEntry */