1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
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
9  later version.
10
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.
15
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
19  02111-1307, USA.
20*/
21
22#include <NGExtensions/NGCustomFileManager.h>
23#include "common.h"
24
25typedef struct {
26  NSString                *sourcePath;
27  NSString                *absolutePath;
28  NSString                *path;
29  NGCustomFileManagerInfo *info;
30  id                      fileManager;
31} NGCustomFMPath;
32
33@interface NGCustomFileManager(Helpers)
34- (NGCustomFMPath)_resolvePath:(NSString *)_path;
35- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path;
36- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path handler:(id)_handler;
37- (id)_do:(SEL)_sel onPath:(NSString *)_path;
38@end
39
40@implementation NGCustomFileManager
41
42/* customization */
43
44- (NSString *)makeAbsolutePath:(NSString *)_path {
45  if ([_path isAbsolutePath])
46    return _path;
47
48  return [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
49}
50
51- (NGCustomFileManagerInfo *)fileManagerInfoForPath:(NSString *)_path {
52  return nil;
53}
54
55/* common ops */
56
57- (NGCustomFMPath)_resolvePath:(NSString *)_path {
58  NGCustomFMPath p;
59
60  p.sourcePath   = _path;
61  p.absolutePath = [self makeAbsolutePath:_path];
62  p.info         = [self fileManagerInfoForPath:_path];
63  p.path         = [p.info rewriteAbsolutePath:p.absolutePath];
64  p.fileManager  = [p.info fileManager];
65  return p;
66}
67
68- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path {
69  NGCustomFMPath p;
70  BOOL (*op)(id,SEL,NSString *);
71
72  if (_sel == NULL) return NO;
73  p = [self _resolvePath:_path];
74  if ((_path = p.path) == nil) return NO;
75  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return NO;
76
77  return op(p.fileManager, _sel, _path);
78}
79- (BOOL)_boolDo:(SEL)_sel onPath:(NSString *)_path handler:(id)_handler {
80  NGCustomFMPath p;
81  BOOL (*op)(id,SEL,NSString *,id);
82
83  if (_sel == NULL) return NO;
84  p = [self _resolvePath:_path];
85  if ((_path = p.path) == nil) return NO;
86  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return NO;
87
88  return op(p.fileManager, _sel, _path, _handler);
89}
90- (id)_do:(SEL)_sel onPath:(NSString *)_path {
91  NGCustomFMPath p;
92  id (*op)(id,SEL,NSString *);
93
94  if (_sel == NULL) return nil;
95  p = [self _resolvePath:_path];
96  if ((_path = p.path) == nil) return nil;
97  if ((op = (void *)[p.fileManager methodForSelector:_sel]) == NULL) return nil;
98
99  return op(p.fileManager, _sel, _path);
100}
101
102/* directory operations */
103
104- (BOOL)changeCurrentDirectoryPath:(NSString *)_path {
105  BOOL isDir = NO;
106  if ((_path = [self makeAbsolutePath:_path]) == nil) return NO;
107
108  if (![self fileExistsAtPath:_path isDirectory:&isDir]) return NO;
109  if (!isDir) return NO;
110
111  ASSIGNCOPY(self->cwd, _path);
112  return YES;
113}
114- (NSString *)currentDirectoryPath {
115  return self->cwd;
116}
117
118- (BOOL)createDirectoryAtPath:(NSString *)_path
119  attributes:(NSDictionary *)_ats
120{
121  NGCustomFMPath p;
122  p = [self _resolvePath:_path];
123  if (p.path == nil) return NO;
124
125  return [p.fileManager createDirectoryAtPath:p.path attributes:_ats];
126}
127
128/* file operations */
129
130- (BOOL)copyPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
131  NGCustomFileManagerInfo *sinfo, *dinfo;
132
133  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
134  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
135  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
136  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
137  _s = [sinfo rewriteAbsolutePath:_s];
138  _d = [dinfo rewriteAbsolutePath:_d];
139
140  if ([sinfo isEqual:dinfo]) /* same filemanager */
141    return [[sinfo fileManager] copyPath:_s toPath:_d handler:_handler];
142
143  /* operation between different filemanagers ... */
144  return NO;
145}
146
147- (BOOL)movePath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
148  NGCustomFileManagerInfo *sinfo, *dinfo;
149
150  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
151  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
152  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
153  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
154  _s = [sinfo rewriteAbsolutePath:_s];
155  _d = [dinfo rewriteAbsolutePath:_d];
156
157  if ([sinfo isEqual:dinfo]) /* same filemanager */
158    return [[sinfo fileManager] movePath:_s toPath:_d handler:_handler];
159
160  /* operation between different filemanagers ... */
161  return NO;
162}
163
164- (BOOL)linkPath:(NSString *)_s toPath:(NSString *)_d handler:(id)_handler {
165  NGCustomFileManagerInfo *sinfo, *dinfo;
166
167  if ((_s = [self makeAbsolutePath:_s]) == nil) return NO;
168  if ((_d = [self makeAbsolutePath:_d]) == nil) return NO;
169  if ((sinfo = [self fileManagerInfoForPath:_s]) == nil) return NO;
170  if ((dinfo = [self fileManagerInfoForPath:_d]) == nil) return NO;
171  _s = [sinfo rewriteAbsolutePath:_s];
172  _d = [dinfo rewriteAbsolutePath:_d];
173
174  if ([sinfo isEqual:dinfo]) /* same filemanager */
175    return [[sinfo fileManager] linkPath:_s toPath:_d handler:_handler];
176
177  /* operation between different filemanagers ... */
178  return NO;
179}
180
181- (BOOL)removeFileAtPath:(NSString *)_path handler:(id)_handler {
182  return [self _boolDo:_cmd onPath:_path handler:_handler];
183}
184
185- (BOOL)createFileAtPath:(NSString *)_path contents:(NSData *)_contents
186  attributes:(NSDictionary *)_attributes
187{
188  NGCustomFMPath p;
189  p = [self _resolvePath:_path];
190  if (p.path == nil) return NO;
191
192  return [p.fileManager
193                createFileAtPath:p.path
194                contents:_contents
195                attributes:_attributes];
196}
197
198/* getting and comparing file contents */
199
200- (NSData *)contentsAtPath:(NSString *)_path {
201  return [self _do:_cmd onPath:_path];
202}
203
204- (BOOL)contentsEqualAtPath:(NSString *)_path1 andPath:(NSString *)_path2 {
205  NGCustomFileManagerInfo *info1, *info2;
206
207  if ((_path1 = [self makeAbsolutePath:_path1]) == nil) return NO;
208  if ((_path2 = [self makeAbsolutePath:_path2]) == nil) return NO;
209  if ((info1 = [self fileManagerInfoForPath:_path1]) == nil) return NO;
210  if ((info2 = [self fileManagerInfoForPath:_path2]) == nil) return NO;
211  _path1 = [info1 rewriteAbsolutePath:_path1];
212  _path2 = [info2 rewriteAbsolutePath:_path2];
213
214  if ([info1 isEqual:info2]) /* same filemanager */
215    return [[info1 fileManager] contentsEqualAtPath:_path1 andPath:_path2];
216
217  /* operation between different filemanagers ... */
218  return NO;
219}
220
221/* determining access to files */
222
223- (BOOL)fileExistsAtPath:(NSString *)_path {
224  return [self _boolDo:_cmd onPath:_path];
225}
226- (BOOL)fileExistsAtPath:(NSString *)_path isDirectory:(BOOL *)_isDirectory {
227  NGCustomFMPath p;
228  p = [self _resolvePath:_path];
229  if (p.path == nil) return NO;
230
231  return [p.fileManager fileExistsAtPath:p.path isDirectory:_isDirectory];
232}
233- (BOOL)isReadableFileAtPath:(NSString *)_path {
234  return [self _boolDo:_cmd onPath:_path];
235}
236- (BOOL)isWritableFileAtPath:(NSString *)_path {
237  return [self _boolDo:_cmd onPath:_path];
238}
239- (BOOL)isExecutableFileAtPath:(NSString *)_path {
240  return [self _boolDo:_cmd onPath:_path];
241}
242- (BOOL)isDeletableFileAtPath:(NSString *)_path {
243  return [self _boolDo:_cmd onPath:_path];
244}
245
246/* Getting and setting attributes */
247
248- (NSDictionary *)fileAttributesAtPath:(NSString *)_p traverseLink:(BOOL)_flag{
249  NGCustomFMPath p;
250  p = [self _resolvePath:_p];
251  if (p.path == nil) return nil;
252
253  /* special link handling required ??? */
254  return [p.fileManager fileAttributesAtPath:p.path traverseLink:_flag];
255}
256
257- (NSDictionary *)fileSystemAttributesAtPath:(NSString *)_p {
258  return [self _do:_cmd onPath:_p];
259}
260
261- (BOOL)changeFileAttributes:(NSDictionary *)_attributes atPath:(NSString *)_p{
262  NGCustomFMPath p;
263  p = [self _resolvePath:_p];
264  if (p.path == nil) return NO;
265
266  return [p.fileManager changeFileAttributes:_attributes atPath:p.path];
267}
268
269/* discovering directory contents */
270
271- (NSArray *)directoryContentsAtPath:(NSString *)_path {
272  /* this returns relative path's, can be passed back */
273  return [self _do:_cmd onPath:_path];
274}
275
276- (NSDirectoryEnumerator *)enumeratorAtPath:(NSString *)_path {
277  /* this needs to be wrapped ! */
278  return nil;
279}
280
281- (NSArray *)subpathsAtPath:(NSString *)_path {
282  /* this returns relative path's, can be passed back */
283  return [self _do:_cmd onPath:_path];
284}
285
286/* symbolic-link operations */
287
288- (BOOL)createSymbolicLinkAtPath:(NSString *)_p pathContent:(NSString *)_dpath{
289  /* should that process the link-path somehow ??? */
290  NGCustomFMPath p;
291  p = [self _resolvePath:_p];
292  if (p.path == nil) return NO;
293
294  return [p.fileManager createSymbolicLinkAtPath:p.path pathContent:_dpath];
295}
296- (NSString *)pathContentOfSymbolicLinkAtPath:(NSString *)_path {
297  /* should that process the link-path somehow ??? */
298  return [self _do:_cmd onPath:_path];
299}
300
301/* feature check */
302
303- (BOOL)supportsVersioningAtPath:(NSString *)_path {
304  return [self _boolDo:_cmd onPath:_path];
305}
306- (BOOL)supportsLockingAtPath:(NSString *)_path {
307  return [self _boolDo:_cmd onPath:_path];
308}
309- (BOOL)supportsFolderDataSourceAtPath:(NSString *)_path {
310  return [self _boolDo:_cmd onPath:_path];
311}
312
313- (BOOL)supportsFeature:(NSString *)_featureURI atPath:(NSString *)_path {
314  NGCustomFMPath p;
315  p = [self _resolvePath:_path];
316  if (p.path == nil) return NO;
317
318  return [p.fileManager supportsFeature:_featureURI atPath:p.path];
319}
320
321/* writing */
322
323- (BOOL)writeContents:(NSData *)_content atPath:(NSString *)_path {
324  NGCustomFMPath p;
325  p = [self _resolvePath:_path];
326  if (p.path == nil) return NO;
327
328  return [p.fileManager writeContents:_content atPath:p.path];
329}
330
331/* global-IDs */
332
333- (EOGlobalID *)globalIDForPath:(NSString *)_path {
334  NGCustomFileManagerInfo *info;
335  if ((_path = [self makeAbsolutePath:_path])      == nil) return nil;
336  if ((info = [self fileManagerInfoForPath:_path]) == nil) return nil;
337
338  if (![info supportsGlobalIDs])
339    return nil;
340
341  if ((_path = [info rewriteAbsolutePath:_path]) == nil)
342    return nil;
343
344  return [[info fileManager] globalIDForPath:_path];
345}
346
347- (NSString *)pathForGlobalID:(EOGlobalID *)_gid {
348  return nil;
349}
350
351/* trash */
352
353- (BOOL)supportsTrashFolderAtPath:(NSString *)_path {
354  return [self _boolDo:_cmd onPath:_path];
355}
356- (NSString *)trashFolderForPath:(NSString *)_path {
357  return nil;
358}
359
360@end /* NGCustomFileManager */
361
362@implementation NGCustomFileManager(NGFileManagerVersioning)
363
364/* versioning */
365
366- (BOOL)checkoutFileAtPath:(NSString *)_path handler:(id)_handler {
367  return [self _boolDo:_cmd onPath:_path handler:_handler];
368}
369- (BOOL)releaseFileAtPath:(NSString *)_path handler:(id)_handler {
370  return [self _boolDo:_cmd onPath:_path handler:_handler];
371}
372- (BOOL)rejectFileAtPath:(NSString *)_path handler:(id)_handler {
373  return [self _boolDo:_cmd onPath:_path handler:_handler];
374}
375- (BOOL)checkoutFileAtPath:(NSString *)_path version:(NSString *)_version
376  handler:(id)_handler
377{
378  NGCustomFMPath p;
379  p = [self _resolvePath:_path];
380  if (p.path == nil) return NO;
381
382  return [p.fileManager
383           checkoutFileAtPath:p.path version:_version handler:_handler];
384}
385
386/* versioning data */
387
388- (NSString *)lastVersionAtPath:(NSString *)_path {
389  return [self _do:_cmd onPath:_path];
390}
391- (NSArray *)versionsAtPath:(NSString *)_path {
392  return [self _do:_cmd onPath:_path];
393}
394
395- (NSData *)contentsAtPath:(NSString *)_path version:(NSString *)_version {
396  NGCustomFMPath p;
397  p = [self _resolvePath:_path];
398  if (p.path == nil) return nil;
399
400  return [p.fileManager contentsAtPath:p.path version:_version];
401}
402
403- (NSDictionary *)fileAttributesAtPath:(NSString *)_path
404  traverseLink:(BOOL)_followLink
405  version:(NSString *)_version
406{
407  NGCustomFMPath p;
408  p = [self _resolvePath:_path];
409  if (p.path == nil) return nil;
410
411  /* do something special to symlink ??? */
412
413  return [p.fileManager
414           fileAttributesAtPath:p.path
415           traverseLink:_followLink
416           version:_version];
417}
418
419@end /* NGCustomFileManager(NGFileManagerVersioning) */
420
421@implementation NGCustomFileManager(NGFileManagerLocking)
422
423- (BOOL)lockFileAtPath:(NSString *)_path handler:(id)_handler {
424  return [self _boolDo:_cmd onPath:_path handler:_handler];
425}
426- (BOOL)unlockFileAtPath:(NSString *)_path handler:(id)_handler {
427  return [self _boolDo:_cmd onPath:_path handler:_handler];
428}
429- (BOOL)isFileLockedAtPath:(NSString *)_path {
430  return [self _boolDo:_cmd onPath:_path];
431}
432
433/* access rights */
434
435- (BOOL)isLockableFileAtPath:(NSString *)_path {
436  return [self _boolDo:_cmd onPath:_path];
437}
438- (BOOL)isUnlockableFileAtPath:(NSString *)_path {
439  return [self _boolDo:_cmd onPath:_path];
440}
441
442@end /* NGCustomFileManager(NGFileManagerLocking) */
443
444@implementation NGCustomFileManager(NGFileManagerDataSources)
445
446/* datasources (work on folders) */
447
448- (EODataSource *)dataSourceAtPath:(NSString *)_path {
449  return [self _do:_cmd onPath:_path];
450}
451
452- (EODataSource *)dataSource {
453  return [self dataSourceAtPath:[self currentDirectoryPath]];
454}
455
456@end /* NGCustomFileManager(NGFileManagerDataSources) */
457
458@implementation NGCustomFileManagerInfo
459
460- (id)initWithCustomFileManager:(NGCustomFileManager *)_master
461  fileManager:(id<NGFileManager,NSObject>)_fm
462{
463  self->master      = _master;
464  self->fileManager = [_fm retain];
465  return self;
466}
467- (id)init {
468  return [self initWithCustomFileManager:nil fileManager:nil];
469}
470
471- (void)dealloc {
472  [self->fileManager release];
473  [super dealloc];
474}
475
476- (void)resetMaster {
477  self->master = nil;
478}
479
480/* accessors */
481
482- (NGCustomFileManager *)master {
483  return self->master;
484}
485- (id<NGFileManager,NSObject>)fileManager {
486  return self->fileManager;
487}
488
489/* operations */
490
491- (NSString *)rewriteAbsolutePath:(NSString *)_path {
492  return _path;
493}
494
495/* capabilities */
496
497- (BOOL)supportsGlobalIDs {
498  return [self->fileManager respondsToSelector:@selector(globalIDForPath:)];
499}
500
501@end /* NGCustomFileManagerInfo */
502