~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSFileManager.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** 
 
1
/**
2
2
   NSFileManager.m
3
3
 
4
 
   Copyright (C) 1997-1999 Free Software Foundation, Inc.
 
4
   Copyright (C) 1997-2002 Free Software Foundation, Inc.
5
5
 
6
6
   Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
7
7
   Author: Ovidiu Predescu <ovidiu@net-community.com>
12
12
   Date: Apr 2001
13
13
   Rewritten NSDirectoryEnumerator
14
14
 
 
15
   Author: Richard frith-Macdonald <rfm@gnu.org>
 
16
   Date: Sep 2002
 
17
   Rewritten attribute handling code
 
18
 
15
19
   This file is part of the GNUstep Base Library.
16
20
 
17
21
   This library is free software; you can redistribute it and/or
18
22
   modify it under the terms of the GNU Library General Public
19
23
   License as published by the Free Software Foundation; either
20
24
   version 2 of the License, or (at your option) any later version.
21
 
   
 
25
 
22
26
   This library is distributed in the hope that it will be useful,
23
27
   but WITHOUT ANY WARRANTY; without even the implied warranty of
24
28
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29
33
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
30
34
 
31
35
   <title>NSFileManager class reference</title>
32
 
   $Date: 2002/03/09 12:10:08 $ $Revision: 1.67 $
 
36
   $Date: 2005/03/18 04:17:39 $ $Revision: 1.108.2.1 $
33
37
*/
34
38
 
35
 
#include <config.h>
 
39
#if defined(__MINGW32__)
 
40
#define UNICODE
 
41
#define _UNICODE
 
42
#endif
 
43
 
 
44
#include "config.h"
36
45
#include <string.h>
37
 
#include <base/preface.h>
38
 
#include <Foundation/NSFileManager.h>
39
 
#include <Foundation/NSException.h>
40
 
#include <Foundation/NSAutoreleasePool.h>
41
 
#include <Foundation/NSLock.h>
42
 
#include <Foundation/NSDebug.h>
43
 
#include <Foundation/NSProcessInfo.h>
 
46
#include "GNUstepBase/preface.h"
 
47
#include "Foundation/NSFileManager.h"
 
48
#include "Foundation/NSException.h"
 
49
#include "Foundation/NSAutoreleasePool.h"
 
50
#include "Foundation/NSLock.h"
 
51
#include "Foundation/NSDebug.h"
 
52
#include "Foundation/NSProcessInfo.h"
 
53
#include "Foundation/NSEnumerator.h"
 
54
#include "Foundation/NSSet.h"
 
55
#include "GSPrivate.h"
44
56
 
45
57
#include <stdio.h>
46
58
 
56
68
# include <ndir.h>
57
69
#endif
58
70
 
59
 
#if HAVE_UNISTD_H
 
71
#ifdef HAVE_UNISTD_H
60
72
#include <unistd.h>
61
73
#endif
62
 
#if HAVE_WINDOWS_H
 
74
#ifdef HAVE_WINDOWS_H
63
75
#  include <windows.h>
64
76
#endif
65
77
 
66
78
#if     defined(__MINGW__)
 
79
#include <stdio.h>
 
80
#ifdef  UNICODE
 
81
#include <wchar.h>
 
82
#endif
67
83
#define WIN32ERR        ((DWORD)0xFFFFFFFF)
68
84
#endif
69
85
 
77
93
#   include <utime.h>
78
94
# endif
79
95
#else
80
 
# if HAVE_SYS_PARAM_H
 
96
# ifdef HAVE_SYS_PARAM_H
81
97
#  include <sys/param.h>                /* for MAXPATHLEN */
82
98
# endif
83
99
#endif
98
114
 
99
115
#ifdef HAVE_SYS_VFS_H
100
116
# include <sys/vfs.h>
101
 
# ifdef HAVE_SYS_STATVFS_H
102
 
#  include <sys/statvfs.h>
103
 
# endif
 
117
#endif
 
118
 
 
119
#ifdef HAVE_SYS_STATVFS_H
 
120
# include <sys/statvfs.h>
104
121
#endif
105
122
 
106
123
#ifdef HAVE_SYS_STATFS_H
107
124
# include <sys/statfs.h>
108
125
#endif
109
126
 
110
 
#if HAVE_SYS_FILE_H
 
127
#ifdef HAVE_SYS_FILE_H
111
128
#include <sys/file.h>
112
129
#endif
113
130
 
114
 
#if HAVE_SYS_MOUNT_H
 
131
#ifdef HAVE_SYS_MOUNT_H
115
132
#include <sys/mount.h>
116
133
#endif
117
134
 
122
139
#endif
123
140
 
124
141
#include <fcntl.h>
125
 
#if HAVE_PWD_H
 
142
#ifdef HAVE_PWD_H
126
143
#include <pwd.h>     /* For struct passwd */
127
144
#endif
128
 
#if HAVE_GRP_H
 
145
#ifdef HAVE_GRP_H
129
146
#include <grp.h>     /* For struct group */
130
147
#endif
131
 
#if HAVE_UTIME_H
 
148
#ifdef HAVE_UTIME_H
132
149
# include <utime.h>
133
150
#endif
134
151
 
143
160
 
144
161
/* include usual headers */
145
162
 
146
 
#include <Foundation/NSArray.h>
147
 
#include <Foundation/NSDictionary.h>
148
 
#include <Foundation/NSData.h>
149
 
#include <Foundation/NSDate.h>
150
 
#include <Foundation/NSString.h>
151
 
#include <Foundation/NSValue.h>
152
 
#include <Foundation/NSPathUtilities.h>
153
 
#include <Foundation/NSFileManager.h>
 
163
#include "Foundation/NSArray.h"
 
164
#include "Foundation/NSDictionary.h"
 
165
#include "Foundation/NSData.h"
 
166
#include "Foundation/NSDate.h"
 
167
#include "Foundation/NSString.h"
 
168
#include "Foundation/NSValue.h"
 
169
#include "Foundation/NSPathUtilities.h"
 
170
#include "Foundation/NSFileManager.h"
 
171
 
 
172
 
 
173
 
 
174
 
 
175
/*
 
176
 * Macros to handle unichar filesystem support.
 
177
 */
 
178
 
 
179
#if     defined(__MINGW__) && defined(UNICODE)
 
180
 
 
181
#define _CHMOD(A,B)     _wchmod(A,B)
 
182
#define _CLOSEDIR(A)    _wclosedir(A)
 
183
#define _OPENDIR(A)     _wopendir(A)
 
184
#define _READDIR(A)     _wreaddir(A)
 
185
#define _RENAME(A,B)    _wrename(A,B)
 
186
#define _RMDIR(A)       _wrmdir(A)
 
187
#define _STAT(A,B)      _wstat(A,B)
 
188
#define _UTIME(A,B)     _wutime(A,B)
 
189
 
 
190
#define _CHAR           unichar
 
191
#define _DIR            _WDIR
 
192
#define _DIRENT         _wdirent
 
193
#define _STATB          _stat
 
194
#define _UTIMB          _utimbuf
 
195
 
 
196
#define _NUL            L'\0'
 
197
 
 
198
#define OS2LOCAL(M,P)   [[M localFromOpenStepPath: P] unicharString]
 
199
 
 
200
#else
 
201
 
 
202
#define _CHMOD(A,B)     chmod(A,B)
 
203
#define _CLOSEDIR(A)    closedir(A)
 
204
#define _OPENDIR(A)     opendir(A)
 
205
#define _READDIR(A)     readdir(A)
 
206
#define _RENAME(A,B)    rename(A,B)
 
207
#define _RMDIR(A)       rmdir(A)
 
208
#define _STAT(A,B)      stat(A,B)
 
209
#define _UTIME(A,B)     utime(A,B)
 
210
 
 
211
#define _CHAR           char
 
212
#define _DIR            DIR
 
213
#define _DIRENT         dirent
 
214
#define _STATB          stat
 
215
#define _UTIMB          utimbuf
 
216
 
 
217
#define _NUL            '\0'
 
218
 
 
219
#define OS2LOCAL(M,P)   [M fileSystemRepresentationWithPath: P]
 
220
 
 
221
#endif
 
222
 
 
223
 
 
224
 
 
225
 
 
226
 
 
227
/*
 
228
 * GSAttrDictionary is a private NSDictionary subclass used to
 
229
 * handle file attributes efficiently ...  using lazy evaluation
 
230
 * to ensure that we only do the minimum work necessary at any time.
 
231
 */
 
232
@interface      GSAttrDictionary : NSDictionary
 
233
{
 
234
  struct _STATB statbuf;
 
235
}
 
236
+ (NSDictionary*) attributesAt: (const _CHAR*)lpath
 
237
                  traverseLink: (BOOL)traverse;
 
238
@end
 
239
 
 
240
/*
 
241
 * We also need a special enumerator class to enumerate the dictionary.
 
242
 */
 
243
@interface      GSAttrDictionaryEnumerator : NSEnumerator
 
244
{
 
245
  NSDictionary  *dictionary;
 
246
  NSEnumerator  *enumerator;
 
247
}
 
248
+ (NSEnumerator*) enumeratorFor: (NSDictionary*)d;
 
249
@end
 
250
 
 
251
 
154
252
 
155
253
@interface NSFileManager (PrivateMethods)
156
254
 
165
263
            toPath: (NSString*)destination
166
264
           handler: (id)handler;
167
265
 
168
 
- (NSDictionary*) _attributesAtPath: (NSString*)path
169
 
                       traverseLink: (BOOL)traverse
170
 
                            forCopy: (BOOL)copy;
 
266
/* Recursively links the contents of source directory to destination. */
 
267
- (BOOL) _linkPath: (NSString*)source
 
268
            toPath: (NSString*)destination
 
269
           handler: handler;
 
270
 
 
271
/* encapsulates the will Process check for existence of selector. */
 
272
- (void) _sendToHandler: (id) handler
 
273
        willProcessPath: (NSString*) path;
 
274
 
 
275
/* methods to encapsulates setting up and calling the handler
 
276
   in case of an error */
 
277
- (BOOL) _proceedAccordingToHandler: (id) handler
 
278
                           forError: (NSString*) error
 
279
                             inPath: (NSString*) path;
 
280
 
 
281
- (BOOL) _proceedAccordingToHandler: (id) handler
 
282
                           forError: (NSString*) error
 
283
                             inPath: (NSString*) path
 
284
                           fromPath: (NSString*) frompath
 
285
                             toPath: (NSString*) toPath;
 
286
 
 
287
 
 
288
 
 
289
 
171
290
@end /* NSFileManager (PrivateMethods) */
172
291
 
173
 
@interface NSDirectoryEnumerator (PrivateMethods)
174
 
- (NSDictionary*) _attributesForCopy;
175
 
@end
176
 
 
177
 
 
178
 
/*
179
 
 * NSFileManager implementation
 
292
/**
 
293
 *  This is the main class for platform-independent management of the local
 
294
 *  filesystem, which allows you to read and save files, create/list
 
295
 *  directories, and move or delete files and directories.  In addition to
 
296
 *  simply listing directories, you may obtain an [NSDirectoryEnumerator]
 
297
 *  instance for recursive directory contents enumeration.
180
298
 */
181
 
 
182
299
@implementation NSFileManager
183
300
 
184
301
// Getting the default manager
185
302
 
186
303
static NSFileManager* defaultManager = nil;
187
304
 
 
305
/**
 
306
 * Returns a shared default file manager which may be used throughout an
 
307
 * application.
 
308
 */
188
309
+ (NSFileManager*) defaultManager
189
310
{
190
 
  if (!defaultManager)
 
311
  if (defaultManager == nil)
191
312
    {
192
313
      NS_DURING
193
314
        {
194
315
          [gnustep_global_lock lock];
195
 
          defaultManager = [[self alloc] init];
 
316
          if (defaultManager == nil)
 
317
            {
 
318
              defaultManager = [[self alloc] init];
 
319
            }
196
320
          [gnustep_global_lock unlock];
197
321
        }
198
322
      NS_HANDLER
212
336
  [super dealloc];
213
337
}
214
338
 
215
 
// Directory operations
216
 
 
 
339
/**
 
340
 * Changes the current directory used for all subsequent operations.<br />
 
341
 * All non-absolute paths are interpreted relative to this directory.<br />
 
342
 * The current directory is set on a per-task basis, so the current
 
343
 * directory for other file manager instances will also be changed
 
344
 * by this method.
 
345
 */
217
346
- (BOOL) changeCurrentDirectoryPath: (NSString*)path
218
347
{
219
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
220
 
    
 
348
  const _CHAR   *lpath = OS2LOCAL(self, path);
221
349
#if defined(__MINGW__)
222
 
  return SetCurrentDirectory(cpath) == TRUE ? YES : NO;
223
 
#else
224
 
  return (chdir(cpath) == 0);
225
 
#endif
226
 
}
227
 
 
 
350
  return SetCurrentDirectory(lpath) == TRUE ? YES : NO;
 
351
#else
 
352
  return (chdir(lpath) == 0) ? YES : NO;
 
353
#endif
 
354
}
 
355
 
 
356
/**
 
357
 * Change the attributes of the file at path to those specified.<br />
 
358
 * Returns YES if all requested changes were made (or if the dictionary
 
359
 * was nil or empty, so no changes were requested), NO otherwise.<br />
 
360
 * On failure, some fo the requested changes may have taken place.<br />
 
361
 */
 
362
- (BOOL) changeFileAttributes: (NSDictionary*)attributes atPath: (NSString*)path
 
363
{
 
364
  const _CHAR   *lpath = 0;
 
365
  unsigned long num;
 
366
  NSString      *str;
 
367
  NSDate        *date;
 
368
  BOOL          allOk = YES;
 
369
 
 
370
  if (attributes == nil)
 
371
    {
 
372
      return YES;
 
373
    }
 
374
  lpath = OS2LOCAL(defaultManager, path);
 
375
 
 
376
#ifndef __MINGW__
 
377
  num = [attributes fileOwnerAccountID];
 
378
  if (num != NSNotFound)
 
379
    {
 
380
      if (chown(lpath, num, -1) != 0)
 
381
        {
 
382
          allOk = NO;
 
383
          str = [NSString stringWithFormat:
 
384
            @"Unable to change NSFileOwnerAccountID to '%u' - %s",
 
385
            num, GSLastErrorStr(errno)];
 
386
          ASSIGN(_lastError, str);
 
387
        }
 
388
    }
 
389
  else
 
390
    {
 
391
      if ((str = [attributes fileOwnerAccountName]) != nil)
 
392
        {
 
393
          BOOL  ok = NO;
 
394
#ifdef HAVE_PWD_H
 
395
          struct passwd *pw = getpwnam([str cString]);
 
396
 
 
397
          if (pw != 0)
 
398
            {
 
399
              ok = (chown(lpath, pw->pw_uid, -1) == 0);
 
400
              chown(lpath, -1, pw->pw_gid);
 
401
            }
 
402
#endif
 
403
          if (ok == NO)
 
404
            {
 
405
              allOk = NO;
 
406
              str = [NSString stringWithFormat:
 
407
                @"Unable to change NSFileOwnerAccountName to '%@' - %s",
 
408
                str, GSLastErrorStr(errno)];
 
409
              ASSIGN(_lastError, str);
 
410
            }
 
411
        }
 
412
    }
 
413
 
 
414
  num = [attributes fileGroupOwnerAccountID];
 
415
  if (num != NSNotFound)
 
416
    {
 
417
      if (chown(lpath, -1, num) != 0)
 
418
        {
 
419
          allOk = NO;
 
420
          str = [NSString stringWithFormat:
 
421
            @"Unable to change NSFileGroupOwnerAccountID to '%u' - %s",
 
422
            num, GSLastErrorStr(errno)];
 
423
          ASSIGN(_lastError, str);
 
424
        }
 
425
    }
 
426
  else if ((str = [attributes fileGroupOwnerAccountName]) != nil)
 
427
    {
 
428
      BOOL      ok = NO;
 
429
#ifdef HAVE_GRP_H
 
430
      struct group *gp = getgrnam([str cString]);
 
431
 
 
432
      if (gp)
 
433
        {
 
434
          if (chown(lpath, -1, gp->gr_gid) == 0)
 
435
            ok = YES;
 
436
        }
 
437
#endif
 
438
      if (ok == NO)
 
439
        {
 
440
          allOk = NO;
 
441
          str = [NSString stringWithFormat:
 
442
            @"Unable to change NSFileGroupOwnerAccountName to '%@' - %s",
 
443
            str, GSLastErrorStr(errno)];
 
444
          ASSIGN(_lastError, str);
 
445
        }
 
446
    }
 
447
#endif  /* __MINGW__ */
 
448
 
 
449
  num = [attributes filePosixPermissions];
 
450
  if (num != NSNotFound)
 
451
    {
 
452
      if (_CHMOD(lpath, num) != 0)
 
453
        {
 
454
          allOk = NO;
 
455
          str = [NSString stringWithFormat:
 
456
            @"Unable to change NSFilePosixPermissions to '%o' - %s",
 
457
            num, GSLastErrorStr(errno)];
 
458
          ASSIGN(_lastError, str);
 
459
        }
 
460
    }
 
461
 
 
462
  date = [attributes fileModificationDate];
 
463
  if (date != nil)
 
464
    {
 
465
      BOOL              ok = NO;
 
466
      struct _STATB     sb;
 
467
 
 
468
#if  defined(__WIN32__) || defined(_POSIX_VERSION)
 
469
      struct _UTIMB ub;
 
470
#else
 
471
      time_t ub[2];
 
472
#endif
 
473
 
 
474
      if (_STAT(lpath, &sb) != 0)
 
475
        {
 
476
          ok = NO;
 
477
        }
 
478
#if  defined(__WIN32__)
 
479
      else if (sb.st_mode & _S_IFDIR)
 
480
        {
 
481
          ok = YES;     // Directories don't have modification times.
 
482
        }
 
483
#endif
 
484
      else
 
485
        {
 
486
#if  defined(__WIN32__) || defined(_POSIX_VERSION)
 
487
          ub.actime = sb.st_atime;
 
488
          ub.modtime = [date timeIntervalSince1970];
 
489
          ok = (_UTIME(lpath, &ub) == 0);
 
490
#else
 
491
          ub[0] = sb.st_atime;
 
492
          ub[1] = [date timeIntervalSince1970];
 
493
          ok = (_UTIME(lpath, ub) == 0);
 
494
#endif
 
495
        }
 
496
      if (ok == NO)
 
497
        {
 
498
          allOk = NO;
 
499
          str = [NSString stringWithFormat:
 
500
            @"Unable to change NSFileModificationDate to '%@' - %s",
 
501
            date, GSLastErrorStr(errno)];
 
502
          ASSIGN(_lastError, str);
 
503
        }
 
504
    }
 
505
 
 
506
  return allOk;
 
507
}
 
508
 
 
509
/**
 
510
 * Returns an array of path components suitably modified for display
 
511
 * to the end user.  This modification may render the returned strings
 
512
 * unusable for path manipulation, so you should work with two arrays ...
 
513
 * one returned by this method (for display tio the user), and a
 
514
 * parallel one returned by [NSString-pathComponents] (for path
 
515
 * manipulation).
 
516
 */
 
517
- (NSArray*) componentsToDisplayForPath: (NSString*)path
 
518
{
 
519
  return [path pathComponents];
 
520
}
 
521
 
 
522
/**
 
523
 * Reads the file at path an returns its contents as an NSData object.<br />
 
524
 * If an error occurs or if path specifies a directory etc then nil is
 
525
 * returned.
 
526
 */
 
527
- (NSData*) contentsAtPath: (NSString*)path
 
528
{
 
529
  return [NSData dataWithContentsOfFile: path];
 
530
}
 
531
 
 
532
/**
 
533
 * Returns YES if the contents of the file or directory at path1 are the same
 
534
 * as those at path2.<br />
 
535
 * If path1 and path2 are files, this is a simple comparison.  If they are
 
536
 * directories, the contents of the files in those subdirectories are
 
537
 * compared recursively.<br />
 
538
 * Symbolic links are not followed.<br />
 
539
 * A comparison checks first file identity, then size, then content.
 
540
 */
 
541
- (BOOL) contentsEqualAtPath: (NSString*)path1 andPath: (NSString*)path2
 
542
{
 
543
  NSDictionary  *d1;
 
544
  NSDictionary  *d2;
 
545
  NSString      *t;
 
546
 
 
547
  if ([path1 isEqual: path2])
 
548
    return YES;
 
549
  d1 = [self fileAttributesAtPath: path1 traverseLink: NO];
 
550
  d2 = [self fileAttributesAtPath: path2 traverseLink: NO];
 
551
  t = [d1 fileType];
 
552
  if ([t isEqual: [d2 fileType]] == NO)
 
553
    {
 
554
      return NO;
 
555
    }
 
556
  if ([t isEqual: NSFileTypeRegular])
 
557
    {
 
558
      if ([d1 fileSize] == [d2 fileSize])
 
559
        {
 
560
          NSData        *c1 = [NSData dataWithContentsOfFile: path1];
 
561
          NSData        *c2 = [NSData dataWithContentsOfFile: path2];
 
562
 
 
563
          if ([c1 isEqual: c2])
 
564
            {
 
565
              return YES;
 
566
            }
 
567
        }
 
568
      return NO;
 
569
    }
 
570
  else if ([t isEqual: NSFileTypeDirectory])
 
571
    {
 
572
      NSArray   *a1 = [self directoryContentsAtPath: path1];
 
573
      NSArray   *a2 = [self directoryContentsAtPath: path2];
 
574
      unsigned  index, count = [a1 count];
 
575
      BOOL      ok = YES;
 
576
 
 
577
      if ([a1 isEqual: a2] == NO)
 
578
        {
 
579
          return NO;
 
580
        }
 
581
      for (index = 0; ok == YES && index < count; index++)
 
582
        {
 
583
          NSString      *n = [a1 objectAtIndex: index];
 
584
          NSString      *p1;
 
585
          NSString      *p2;
 
586
          CREATE_AUTORELEASE_POOL(pool);
 
587
 
 
588
          p1 = [path1 stringByAppendingPathComponent: n];
 
589
          p2 = [path2 stringByAppendingPathComponent: n];
 
590
          d1 = [self fileAttributesAtPath: p1 traverseLink: NO];
 
591
          d2 = [self fileAttributesAtPath: p2 traverseLink: NO];
 
592
          t = [d1 fileType];
 
593
          if ([t isEqual: [d2 fileType]] == NO)
 
594
            {
 
595
              ok = NO;
 
596
            }
 
597
          else if ([t isEqual: NSFileTypeDirectory])
 
598
            {
 
599
              ok = [self contentsEqualAtPath: p1 andPath: p2];
 
600
            }
 
601
          RELEASE(pool);
 
602
        }
 
603
      return ok;
 
604
    }
 
605
  else
 
606
    {
 
607
      return YES;
 
608
    }
 
609
}
 
610
 
 
611
/**
 
612
 * Creates a new directory, and sets its attributes as specified.<br />
 
613
 * Creates other directories in the path as necessary.<br />
 
614
 * Returns YES on success, NO on failure.
 
615
 */
228
616
- (BOOL) createDirectoryAtPath: (NSString*)path
229
617
                    attributes: (NSDictionary*)attributes
230
618
{
231
619
#if defined(__MINGW__)
232
 
  NSEnumerator *paths = [[path pathComponents] objectEnumerator];
233
 
  NSString *subPath;
234
 
  NSString *completePath = nil;
235
 
 
 
620
  NSEnumerator  *paths = [[path pathComponents] objectEnumerator];
 
621
  NSString      *subPath;
 
622
  NSString      *completePath = nil;
 
623
#else
 
624
  const char    *lpath;
 
625
  char          dirpath[PATH_MAX+1];
 
626
  struct _STATB statbuf;
 
627
  int           len, cur;
 
628
  NSDictionary  *needChown = nil;
 
629
#endif
 
630
 
 
631
  /* This is consistent with MacOSX - just return NO for an invalid path. */
 
632
  if ([path length] == 0)
 
633
    return NO;
 
634
 
 
635
#if defined(__MINGW__)
236
636
  while ((subPath = [paths nextObject]))
237
637
    {
238
638
      BOOL isDir = NO;
 
639
 
239
640
      if (completePath == nil)
240
641
        completePath = subPath;
241
642
      else
242
 
        completePath = [completePath stringByAppendingPathComponent:subPath];
 
643
        completePath = [completePath stringByAppendingPathComponent: subPath];
243
644
 
244
 
      if ([self fileExistsAtPath:completePath isDirectory:&isDir]) 
 
645
      if ([self fileExistsAtPath: completePath isDirectory: &isDir])
245
646
        {
246
 
          if (!isDir) 
 
647
          if (!isDir)
247
648
            NSLog(@"WARNING: during creation of directory %@:"
248
649
                  @" sub path %@ exists, but is not a directory !",
249
650
                  path, completePath);
250
651
        }
251
 
      else 
 
652
      else
252
653
        {
253
 
          const char *cpath;
254
 
          cpath = [self fileSystemRepresentationWithPath: completePath];
255
 
          if (CreateDirectory(cpath, NULL) == FALSE)
256
 
            return NO;
 
654
          const _CHAR *lpath;
 
655
 
 
656
          lpath = OS2LOCAL(self, completePath);
 
657
          if (CreateDirectory(lpath, 0) == FALSE)
 
658
            {
 
659
              return NO;
 
660
            }
257
661
        }
258
662
    }
259
663
 
260
 
  // change attributes of last directory
261
 
  return [self changeFileAttributes: attributes atPath: path];
262
 
 
263
664
#else
264
 
  const char    *cpath;
265
 
  char          dirpath[PATH_MAX+1];
266
 
  struct stat   statbuf;
267
 
  int           len, cur;
268
 
  NSDictionary  *needChown = nil;
269
 
    
 
665
 
270
666
  /*
271
667
   * If there is no file owner specified, and we are running setuid to
272
668
   * root, then we assume we need to change ownership to correct user.
273
669
   */
274
 
  if ([attributes objectForKey: NSFileOwnerAccountName] == nil 
275
 
    && [attributes objectForKey: NSFileOwnerAccountNumber] == nil 
276
 
    && geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
 
670
  if (attributes == nil || ([attributes fileOwnerAccountID] == NSNotFound
 
671
    && [attributes fileOwnerAccountName] == nil))
277
672
    {
278
 
      needChown = [NSDictionary dictionaryWithObjectsAndKeys: 
279
 
                        NSFileOwnerAccountName, NSUserName(), nil];
 
673
      if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
 
674
        {
 
675
          needChown = [NSDictionary dictionaryWithObjectsAndKeys:
 
676
            NSFileOwnerAccountName, NSUserName(), nil];
 
677
        }
280
678
    }
281
 
 
282
 
  cpath = [self fileSystemRepresentationWithPath: path];
283
 
  len = strlen(cpath);
 
679
  lpath = [self fileSystemRepresentationWithPath: path];
 
680
  len = strlen(lpath);
284
681
  if (len > PATH_MAX) // name too long
285
682
    {
286
683
      ASSIGN(_lastError, @"Could not create directory - name too long");
287
684
      return NO;
288
685
    }
289
 
    
290
 
  if (strcmp(cpath, "/") == 0 || len == 0) // cannot use "/" or ""
 
686
 
 
687
  if (strcmp(lpath, "/") == 0 || len == 0) // cannot use "/" or ""
291
688
    {
292
689
      ASSIGN(_lastError, @"Could not create directory - no name given");
293
690
      return NO;
294
691
    }
295
 
    
296
 
  strcpy(dirpath, cpath);
 
692
 
 
693
  strcpy(dirpath, lpath);
297
694
  dirpath[len] = '\0';
298
695
  if (dirpath[len-1] == '/')
299
696
    dirpath[len-1] = '\0';
300
697
  cur = 0;
301
 
    
 
698
 
302
699
  do
303
700
    {
304
701
      // find next '/'
312
709
        }
313
710
      // check if path from 0 to cur is valid
314
711
      dirpath[cur] = '\0';
315
 
      if (stat(dirpath, &statbuf) == 0)
 
712
      if (_STAT(dirpath, &statbuf) == 0)
316
713
        {
317
714
          if (cur == len)
318
715
            {
319
 
              ASSIGN(_lastError, @"Could not create directory - already exists");
 
716
              ASSIGN(_lastError,
 
717
                @"Could not create directory - already exists");
320
718
              return NO;
321
719
            }
322
720
        }
333
731
              return NO;
334
732
            }
335
733
          // if last directory and attributes then change
336
 
          if (cur == len && attributes)
 
734
          if (cur == len && attributes != nil)
337
735
            {
338
 
              if ([self changeFileAttributes: attributes 
 
736
              if ([self changeFileAttributes: attributes
339
737
                atPath: [self stringWithFileSystemRepresentation: dirpath
340
738
                        length: cur]] == NO)
341
739
                return NO;
342
 
              if (needChown)
 
740
              if (needChown != nil)
343
741
                {
344
 
                  if ([self changeFileAttributes: needChown 
 
742
                  if ([self changeFileAttributes: needChown
345
743
                    atPath: [self stringWithFileSystemRepresentation: dirpath
346
744
                      length: cur]] == NO)
347
745
                    {
357
755
    }
358
756
  while (cur < len);
359
757
 
360
 
  return YES;
361
758
#endif /* !MINGW */
362
 
}
363
 
 
 
759
 
 
760
  // change attributes of last directory
 
761
  if ([attributes count] == 0)
 
762
    {
 
763
      return YES;
 
764
    }
 
765
  return [self changeFileAttributes: attributes atPath: path];
 
766
}
 
767
 
 
768
/**
 
769
 * Creates a new file, and sets its attributes as specified.<br />
 
770
 * Initialises the file content with the specified data.<br />
 
771
 * Returns YES on success, NO on failure.
 
772
 */
 
773
- (BOOL) createFileAtPath: (NSString*)path
 
774
                 contents: (NSData*)contents
 
775
               attributes: (NSDictionary*)attributes
 
776
{
 
777
#if     defined(__MINGW__)
 
778
  const _CHAR *lpath = OS2LOCAL(self, path);
 
779
  HANDLE fh;
 
780
  DWORD written = 0;
 
781
  DWORD len = [contents length];
 
782
#else
 
783
  const char    *lpath;
 
784
  int   fd;
 
785
  int   len;
 
786
  int   written;
 
787
#endif
 
788
 
 
789
  /* This is consitent with MacOSX - just return NO for an invalid path. */
 
790
  if ([path length] == 0)
 
791
    return NO;
 
792
 
 
793
#if     defined(__MINGW__)
 
794
  fh = CreateFile(lpath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
 
795
    FILE_ATTRIBUTE_NORMAL, 0);
 
796
  if (fh == INVALID_HANDLE_VALUE)
 
797
    {
 
798
      return NO;
 
799
    }
 
800
  else
 
801
    {
 
802
      if (len > 0)
 
803
        {
 
804
          WriteFile(fh, [contents bytes], len, &written, 0);
 
805
        }
 
806
      CloseHandle(fh);
 
807
      if (attributes != nil
 
808
        && [self changeFileAttributes: attributes atPath: path] == NO)
 
809
        {
 
810
          return NO;
 
811
        }
 
812
      return YES;
 
813
    }
 
814
#else
 
815
  lpath = [self fileSystemRepresentationWithPath: path];
 
816
 
 
817
  fd = open(lpath, GSBINIO|O_WRONLY|O_TRUNC|O_CREAT, 0644);
 
818
  if (fd < 0)
 
819
    {
 
820
      return NO;
 
821
    }
 
822
  if (attributes != nil
 
823
    && [self changeFileAttributes: attributes atPath: path] == NO)
 
824
    {
 
825
      close (fd);
 
826
      return NO;
 
827
    }
 
828
 
 
829
  /*
 
830
   * If there is no file owner specified, and we are running setuid to
 
831
   * root, then we assume we need to change ownership to correct user.
 
832
   */
 
833
  if (attributes == nil || ([attributes fileOwnerAccountID] == NSNotFound
 
834
    && [attributes fileOwnerAccountName] == nil))
 
835
    {
 
836
      if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
 
837
        {
 
838
          attributes = [NSDictionary dictionaryWithObjectsAndKeys:
 
839
            NSFileOwnerAccountName, NSUserName(), nil];
 
840
          if (![self changeFileAttributes: attributes atPath: path])
 
841
            {
 
842
              NSLog(@"Failed to change ownership of '%@' to '%@'",
 
843
                path, NSUserName());
 
844
            }
 
845
        }
 
846
    }
 
847
  len = [contents length];
 
848
  if (len > 0)
 
849
    {
 
850
      written = write(fd, [contents bytes], len);
 
851
    }
 
852
  else
 
853
    {
 
854
      written = 0;
 
855
    }
 
856
  close (fd);
 
857
#endif
 
858
  return written == len;
 
859
}
 
860
 
 
861
/**
 
862
 * Returns the current working directory used by all instance of the file
 
863
 * manager in the current task.
 
864
 */
364
865
- (NSString*) currentDirectoryPath
365
866
{
 
867
  NSString *currentDir = nil;
 
868
 
 
869
#if defined(__MINGW__)
 
870
  int len = GetCurrentDirectory(0, 0);
 
871
  if (len > 0)
 
872
    {
 
873
      _CHAR *lpath = (_CHAR*)calloc(len+10,sizeof(_CHAR));
 
874
 
 
875
      if (lpath != 0)
 
876
        {
 
877
          if (GetCurrentDirectory(len, lpath)>0)
 
878
            {
 
879
              NSString  *path;
 
880
 
 
881
#ifdef  UNICODE
 
882
              path = [NSString stringWithCharacters: lpath length: len];
 
883
#else
 
884
              path = [NSString stringWithCString: lpath length: len];
 
885
#endif
 
886
 
 
887
              currentDir = [self openStepPathFromLocal: path];
 
888
            }
 
889
          free(lpath);
 
890
        }
 
891
    }
 
892
#else
366
893
  char path[PATH_MAX];
367
 
 
368
 
#if defined(__MINGW__)
369
 
  if (GetCurrentDirectory(PATH_MAX, path) > PATH_MAX)
370
 
    return nil;
371
 
#else
372
894
#ifdef HAVE_GETCWD
373
 
  if (getcwd(path, PATH_MAX-1) == NULL)
 
895
  if (getcwd(path, PATH_MAX-1) == 0)
374
896
    return nil;
375
897
#else
376
 
  if (getwd(path) == NULL)
 
898
  if (getwd(path) == 0)
377
899
    return nil;
378
900
#endif /* HAVE_GETCWD */
 
901
  currentDir = [self stringWithFileSystemRepresentation: path
 
902
                                                 length: strlen(path)];
379
903
#endif /* !MINGW */
380
904
 
381
 
  return [self stringWithFileSystemRepresentation: path length: strlen(path)];
 
905
  return currentDir;
382
906
}
383
907
 
384
 
// File operations
385
 
 
 
908
/**
 
909
 * Copies the file or directory at source to destination, using a
 
910
 * handler object which should respond to
 
911
 * [NSObject-fileManager:willProcessPath:] and
 
912
 * [NSObject-fileManager:shouldProceedAfterError:] messages.<br />
 
913
 * Will not copy to a destination which already exists.
 
914
 */
386
915
- (BOOL) copyPath: (NSString*)source
387
916
           toPath: (NSString*)destination
388
 
          handler: handler
 
917
          handler: (id)handler
389
918
{
390
 
  BOOL          fileExists;
391
919
  NSDictionary  *attrs;
392
920
  NSString      *fileType;
393
921
 
394
 
  attrs = [self _attributesAtPath: source traverseLink: NO forCopy: YES];
 
922
  if ([self fileExistsAtPath: destination] == YES)
 
923
    {
 
924
      return NO;
 
925
    }
 
926
  attrs = [self fileAttributesAtPath: source traverseLink: NO];
395
927
  if (attrs == nil)
396
928
    {
397
929
      return NO;
398
930
    }
399
 
  fileExists = [self fileExistsAtPath: destination];
400
 
  if (fileExists)
401
 
    {
402
 
      return NO;
403
 
    }
404
 
  fileType = [attrs objectForKey: NSFileType];
 
931
  fileType = [attrs fileType];
405
932
  if ([fileType isEqualToString: NSFileTypeDirectory] == YES)
406
933
    {
407
934
      /* If destination directory is a descendant of source directory copying
412
939
          return NO;
413
940
        }
414
941
 
415
 
      [handler fileManager: self willProcessPath: destination];
 
942
      [self _sendToHandler: handler willProcessPath: destination];
 
943
 
416
944
      if ([self createDirectoryAtPath: destination attributes: attrs] == NO)
417
945
        {
418
 
          if (handler)
419
 
            {
420
 
              NSDictionary* errorInfo
421
 
                = [NSDictionary dictionaryWithObjectsAndKeys: 
422
 
                  destination, @"Path", _lastError, @"Error", nil];
423
 
              return [handler fileManager: self
424
 
                  shouldProceedAfterError: errorInfo];
425
 
            }
426
 
          else
427
 
            {
428
 
              return NO;
429
 
            }
 
946
          return [self _proceedAccordingToHandler: handler
 
947
                                         forError: _lastError
 
948
                                           inPath: destination
 
949
                                         fromPath: source
 
950
                                           toPath: destination];
430
951
        }
431
952
 
432
953
      if ([self _copyPath: source toPath: destination handler: handler] == NO)
439
960
      NSString  *path;
440
961
      BOOL      result;
441
962
 
442
 
      [handler fileManager: self willProcessPath: source];
 
963
      [self _sendToHandler: handler willProcessPath: source];
 
964
 
443
965
      path = [self pathContentOfSymbolicLinkAtPath: source];
444
966
      result = [self createSymbolicLinkAtPath: destination pathContent: path];
445
967
      if (result == NO)
446
968
        {
447
 
          if (handler != nil)
448
 
            {
449
 
              NSDictionary      *errorInfo
450
 
                = [NSDictionary dictionaryWithObjectsAndKeys: 
451
 
                  source, @"Path", destination, @"ToPath",
452
 
                          @"cannot link to file", @"Error",
453
 
                          nil];
454
 
              result = [handler fileManager: self
455
 
                    shouldProceedAfterError: errorInfo];
456
 
            }
 
969
          result = [self _proceedAccordingToHandler: handler
 
970
                                           forError: @"cannot link to file"
 
971
                                             inPath: source
 
972
                                           fromPath: source
 
973
                                             toPath: destination];
 
974
 
457
975
          if (result == NO)
458
976
            {
459
977
              return NO;
462
980
    }
463
981
  else
464
982
    {
465
 
      [handler fileManager: self willProcessPath: source];
 
983
      [self _sendToHandler: handler willProcessPath: source];
 
984
 
466
985
      if ([self _copyFile: source toFile: destination handler: handler] == NO)
467
986
        {
468
987
          return NO;
472
991
  return YES;
473
992
}
474
993
 
 
994
/**
 
995
 * Moves the file or directory at source to destination, using a
 
996
 * handler object which should respond to
 
997
 * [NSObject-fileManager:willProcessPath:] and
 
998
 * [NSObject-fileManager:shouldProceedAfterError:] messages.
 
999
 * Will not move to a destination which already exists.<br />
 
1000
 */
475
1001
- (BOOL) movePath: (NSString*)source
476
 
           toPath: (NSString*)destination 
477
 
          handler: handler
 
1002
           toPath: (NSString*)destination
 
1003
          handler: (id)handler
478
1004
{
479
 
  BOOL sourceIsDir, fileExists;
480
 
  const char* sourcePath = [self fileSystemRepresentationWithPath: source];
481
 
  const char* destPath = [self fileSystemRepresentationWithPath: destination];
482
 
  NSString* destinationParent;
483
 
  unsigned int sourceDevice, destinationDevice;
484
 
 
 
1005
  BOOL          sourceIsDir;
 
1006
  BOOL          fileExists;
 
1007
  NSString      *destinationParent;
 
1008
  unsigned int  sourceDevice;
 
1009
  unsigned int  destinationDevice;
 
1010
  const _CHAR   *sourcePath;
 
1011
  const _CHAR   *destPath;
 
1012
 
 
1013
  sourcePath = OS2LOCAL(self, source);
 
1014
  destPath = OS2LOCAL(self, destination);
 
1015
 
 
1016
  if ([self fileExistsAtPath: destination] == YES)
 
1017
    {
 
1018
      return NO;
 
1019
    }
485
1020
  fileExists = [self fileExistsAtPath: source isDirectory: &sourceIsDir];
486
1021
  if (!fileExists)
487
 
    return NO;
488
 
 
489
 
  fileExists = [self fileExistsAtPath: destination];
490
 
  if (fileExists)
491
 
    return NO;
 
1022
    {
 
1023
      return NO;
 
1024
    }
492
1025
 
493
1026
  /* Check to see if the source and destination's parent are on the same
494
1027
     physical device so we can perform a rename syscall directly. */
495
 
  sourceDevice = [[[self fileSystemAttributesAtPath: source]
496
 
                          objectForKey: NSFileSystemNumber]
497
 
                          unsignedIntValue];
 
1028
  sourceDevice = [[self fileSystemAttributesAtPath: source] fileSystemNumber];
498
1029
  destinationParent = [destination stringByDeletingLastPathComponent];
499
1030
  if ([destinationParent isEqual: @""])
500
1031
    destinationParent = @".";
501
1032
  destinationDevice
502
 
    = [[[self fileSystemAttributesAtPath: destinationParent]
503
 
                objectForKey: NSFileSystemNumber]
504
 
                unsignedIntValue];
 
1033
    = [[self fileSystemAttributesAtPath: destinationParent] fileSystemNumber];
505
1034
 
506
1035
  if (sourceDevice != destinationDevice)
507
1036
    {
509
1038
          isn't possible. */
510
1039
      if (sourceIsDir && [[destination stringByAppendingString: @"/"]
511
1040
        hasPrefix: [source stringByAppendingString: @"/"]])
512
 
        return NO;
 
1041
        {
 
1042
          return NO;
 
1043
        }
513
1044
 
514
1045
      if ([self copyPath: source toPath: destination handler: handler])
515
1046
        {
516
 
          NSDictionary* attributes;
 
1047
          NSDictionary  *attributes;
517
1048
 
518
 
          attributes = [self _attributesAtPath: source
519
 
                                  traverseLink: NO
520
 
                                       forCopy: YES];
 
1049
          attributes = [self fileAttributesAtPath: source
 
1050
                                     traverseLink: NO];
521
1051
          [self changeFileAttributes: attributes atPath: destination];
522
1052
          return [self removeFileAtPath: source handler: handler];
523
1053
        }
524
1054
      else
525
 
        return NO;
 
1055
        {
 
1056
          return NO;
 
1057
        }
526
1058
    }
527
1059
  else
528
1060
    {
529
1061
      /* source and destination are on the same device so we can simply
530
1062
         invoke rename on source. */
531
 
      [handler fileManager: self willProcessPath: source];
532
 
      if (rename (sourcePath, destPath) == -1)
 
1063
      [self _sendToHandler: handler willProcessPath: source];
 
1064
 
 
1065
      if (_RENAME (sourcePath, destPath) == -1)
533
1066
        {
534
 
          if (handler)
535
 
            {
536
 
              NSDictionary* errorInfo
537
 
                  = [NSDictionary dictionaryWithObjectsAndKeys: 
538
 
                      source, @"Path",
539
 
                      destination, @"ToPath",
540
 
                      @"cannot move file", @"Error",
541
 
                      nil];
542
 
              if ([handler fileManager: self
543
 
                shouldProceedAfterError: errorInfo])
544
 
                return YES;
545
 
            }
546
 
          return NO;
 
1067
          return [self _proceedAccordingToHandler: handler
 
1068
                                         forError: @"cannot move file"
 
1069
                                           inPath: source
 
1070
                                         fromPath: source
 
1071
                                           toPath: destination];
547
1072
        }
548
1073
      return YES;
549
1074
    }
551
1076
  return NO;
552
1077
}
553
1078
 
 
1079
/**
 
1080
 * <p>Links the file or directory at source to destination, using a
 
1081
 * handler object which should respond to
 
1082
 * [NSObject-fileManager:willProcessPath:] and
 
1083
 * [NSObject-fileManager:shouldProceedAfterError:] messages.
 
1084
 * </p>
 
1085
 * <p>If the destination is a directory, the source path is linked
 
1086
 * into that directory, otherwise the destination must not exist,
 
1087
 * but its parent directory must exist and the source will be linked
 
1088
 * into the parent as the name specified by the destination.
 
1089
 * </p>
 
1090
 * <p>If the source is a symbolic link, it is copied to the destination.<br />
 
1091
 * If the source is a directory, it is copied to the destination and its
 
1092
 * contents are linked into the new directory.<br />
 
1093
 * Otherwise, a hard link is made from the destination to the source.
 
1094
 * </p>
 
1095
 */
554
1096
- (BOOL) linkPath: (NSString*)source
555
1097
           toPath: (NSString*)destination
556
 
          handler: handler
 
1098
          handler: (id)handler
557
1099
{
558
 
  // TODO
559
 
  [self notImplemented: _cmd];
560
 
  return NO;
 
1100
#ifdef HAVE_LINK
 
1101
  NSDictionary  *attrs;
 
1102
  NSString      *fileType;
 
1103
  BOOL          isDir;
 
1104
 
 
1105
  if ([self fileExistsAtPath: destination isDirectory: &isDir] == YES
 
1106
    && isDir == YES)
 
1107
    {
 
1108
      destination = [destination stringByAppendingPathComponent:
 
1109
        [source lastPathComponent]];
 
1110
    }
 
1111
 
 
1112
  attrs = [self fileAttributesAtPath: source traverseLink: NO];
 
1113
  if (attrs == nil)
 
1114
    {
 
1115
      return NO;
 
1116
    }
 
1117
 
 
1118
  [self _sendToHandler: handler willProcessPath: destination];
 
1119
 
 
1120
  fileType = [attrs fileType];
 
1121
  if ([fileType isEqualToString: NSFileTypeDirectory] == YES)
 
1122
    {
 
1123
      /* If destination directory is a descendant of source directory linking
 
1124
          isn't possible because of recursion. */
 
1125
      if ([[destination stringByAppendingString: @"/"]
 
1126
        hasPrefix: [source stringByAppendingString: @"/"]])
 
1127
        {
 
1128
          return NO;
 
1129
        }
 
1130
 
 
1131
      if ([self createDirectoryAtPath: destination attributes: attrs] == NO)
 
1132
        {
 
1133
          return [self _proceedAccordingToHandler: handler
 
1134
                                         forError: _lastError
 
1135
                                           inPath: destination
 
1136
                                         fromPath: source
 
1137
                                           toPath: destination];
 
1138
        }
 
1139
 
 
1140
      if ([self _linkPath: source toPath: destination handler: handler] == NO)
 
1141
        {
 
1142
          return NO;
 
1143
        }
 
1144
    }
 
1145
  else if ([fileType isEqual: NSFileTypeSymbolicLink])
 
1146
    {
 
1147
      NSString  *path;
 
1148
 
 
1149
      path = [self pathContentOfSymbolicLinkAtPath: source];
 
1150
      if ([self createSymbolicLinkAtPath: destination
 
1151
                             pathContent: path] == NO)
 
1152
        {
 
1153
          if ([self _proceedAccordingToHandler: handler
 
1154
                                      forError: @"cannot create symbolic link"
 
1155
                                        inPath: source
 
1156
                                      fromPath: source
 
1157
                                        toPath: destination] == NO)
 
1158
            {
 
1159
              return NO;
 
1160
            }
 
1161
        }
 
1162
    }
 
1163
  else
 
1164
    {
 
1165
      if (link([source fileSystemRepresentation],
 
1166
        [destination fileSystemRepresentation]) < 0)
 
1167
        {
 
1168
          if ([self _proceedAccordingToHandler: handler
 
1169
                                      forError: @"cannot create hard link"
 
1170
                                        inPath: source
 
1171
                                      fromPath: source
 
1172
                                        toPath: destination] == NO)
 
1173
            {
 
1174
              return NO;
 
1175
            }
 
1176
        }
 
1177
    }
 
1178
  [self changeFileAttributes: attrs atPath: destination];
 
1179
  return YES;
 
1180
#else
 
1181
  return NO;    // Links not supported on this platform
 
1182
#endif
561
1183
}
562
1184
 
 
1185
/**
 
1186
 * Removes the file or directory at path, using a
 
1187
 * handler object which should respond to
 
1188
 * [NSObject-fileManager:willProcessPath:] and
 
1189
 * [NSObject-fileManager:shouldProceedAfterError:] messages.
 
1190
 */
563
1191
- (BOOL) removeFileAtPath: (NSString*)path
564
1192
                  handler: handler
565
1193
{
566
1194
  BOOL          is_dir;
567
 
  const char    *cpath;
 
1195
  const _CHAR   *lpath;
568
1196
 
569
1197
  if ([path isEqualToString: @"."] || [path isEqualToString: @".."])
570
1198
    {
572
1200
                  format: @"Attempt to remove illegal path"];
573
1201
    }
574
1202
 
575
 
  if (handler != nil)
576
 
    {
577
 
      [handler fileManager: self willProcessPath: path];
578
 
    }
579
 
  cpath = [self fileSystemRepresentationWithPath: path];
580
 
  if (cpath == 0 || *cpath == '\0')
 
1203
  [self _sendToHandler: handler willProcessPath: path];
 
1204
 
 
1205
  lpath = OS2LOCAL(self, path);
 
1206
  if (lpath == 0 || *lpath == 0)
581
1207
    {
582
1208
      return NO;
583
1209
    }
586
1212
#if defined(__MINGW__)
587
1213
      DWORD res;
588
1214
 
589
 
      res = GetFileAttributes(cpath);
 
1215
      res = GetFileAttributes(lpath);
590
1216
      if (res == WIN32ERR)
591
 
        return NO;
592
 
 
 
1217
        {
 
1218
          return NO;
 
1219
        }
593
1220
      if (res & FILE_ATTRIBUTE_DIRECTORY)
594
 
        is_dir = YES;
 
1221
        {
 
1222
          is_dir = YES;
 
1223
        }
595
1224
      else
596
 
        is_dir = NO;
 
1225
        {
 
1226
          is_dir = NO;
 
1227
        }
597
1228
#else
598
 
      struct stat statbuf;
 
1229
      struct _STATB statbuf;
599
1230
 
600
 
      if (lstat(cpath, &statbuf) != 0)
601
 
        return NO;
602
 
    
 
1231
      if (lstat(lpath, &statbuf) != 0)
 
1232
        {
 
1233
          return NO;
 
1234
        }
603
1235
      is_dir = ((statbuf.st_mode & S_IFMT) == S_IFDIR);
604
1236
#endif /* MINGW */
605
1237
    }
607
1239
  if (!is_dir)
608
1240
    {
609
1241
#if defined(__MINGW__)
610
 
      if (DeleteFile(cpath) == FALSE)
 
1242
      if (DeleteFile(lpath) == FALSE)
611
1243
#else
612
 
      if (unlink(cpath) < 0)
 
1244
      if (unlink(lpath) < 0)
613
1245
#endif
614
1246
        {
615
 
          BOOL  result;
616
 
 
617
 
          if (handler)
618
 
            {
619
 
              NSMutableDictionary       *info;
620
 
 
621
 
              info = [[NSMutableDictionary alloc] initWithCapacity: 3];
622
 
              [info setObject: path forKey: @"Path"];
623
 
              [info setObject: [NSString stringWithCString:
624
 
                GSLastErrorStr(errno)]
625
 
                       forKey: @"Error"];
626
 
              result = [handler fileManager: self
627
 
                    shouldProceedAfterError: info];
628
 
              RELEASE(info);
629
 
            }
630
 
          else
631
 
            result = NO;
632
 
          return result;
 
1247
          return [self _proceedAccordingToHandler: handler
 
1248
            forError: [NSString stringWithCString: GSLastErrorStr (errno)]
 
1249
            inPath: path];
633
1250
        }
634
1251
      else
635
 
        return YES;
 
1252
        {
 
1253
          return YES;
 
1254
        }
636
1255
    }
637
1256
  else
638
1257
    {
652
1271
          result = [self removeFileAtPath: next handler: handler];
653
1272
          RELEASE(arp);
654
1273
          if (result == NO)
655
 
            return NO;
656
 
        }
657
 
 
658
 
      if (rmdir([path fileSystemRepresentation]) < 0)
659
 
        {
660
 
          BOOL  result;
661
 
 
662
 
          if (handler)
663
1274
            {
664
 
              NSMutableDictionary       *info;
665
 
 
666
 
              info = [[NSMutableDictionary alloc] initWithCapacity: 3];
667
 
              [info setObject: path forKey: @"Path"];
668
 
              [info setObject: [NSString stringWithCString:
669
 
                GSLastErrorStr(errno)]
670
 
                       forKey: @"Error"];
671
 
              result = [handler fileManager: self
672
 
                    shouldProceedAfterError: info];
673
 
              RELEASE(info);
 
1275
              return NO;
674
1276
            }
675
 
          else
676
 
            result = NO;
677
 
          return result;
 
1277
        }
 
1278
 
 
1279
      if (_RMDIR(OS2LOCAL(self, path)) < 0)
 
1280
        {
 
1281
          return [self _proceedAccordingToHandler: handler
 
1282
            forError: [NSString stringWithCString: GSLastErrorStr (errno)]
 
1283
            inPath: path];
678
1284
        }
679
1285
      else
680
 
        return YES;
681
 
    }
682
 
}
683
 
 
684
 
- (BOOL) createFileAtPath: (NSString*)path
685
 
                 contents: (NSData*)contents
686
 
               attributes: (NSDictionary*)attributes
687
 
{
688
 
  const char    *cpath = [self fileSystemRepresentationWithPath: path];
689
 
 
690
 
#if     defined(__MINGW__)
691
 
  HANDLE fh;
692
 
  DWORD written = 0;
693
 
  DWORD len = [contents length];
694
 
 
695
 
  fh = CreateFile(cpath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
696
 
    FILE_ATTRIBUTE_NORMAL, 0);
697
 
  if (fh == INVALID_HANDLE_VALUE)
698
 
    {
699
 
      return NO;
700
 
    }
701
 
  else
702
 
    {
703
 
 
704
 
      if (len > 0)
705
 
        {
706
 
          WriteFile(fh, [contents bytes], len, &written, NULL);
707
 
        }
708
 
      CloseHandle(fh);
709
 
      if ([self changeFileAttributes: attributes atPath: path] == NO)
710
 
        {
711
 
          return NO;
712
 
        }
713
 
    }
714
 
#else
715
 
  int   fd;
716
 
  int           len;
717
 
  int           written;
718
 
 
719
 
  fd = open(cpath, GSBINIO|O_WRONLY|O_TRUNC|O_CREAT, 0644);
720
 
  if (fd < 0)
721
 
    {
722
 
      return NO;
723
 
    }
724
 
  if ([self changeFileAttributes: attributes atPath: path] == NO)
725
 
    {
726
 
      close (fd);
727
 
      return NO;
728
 
    }
729
 
 
730
 
  /*
731
 
   * If there is no file owner specified, and we are running setuid to
732
 
   * root, then we assume we need to change ownership to correct user.
733
 
   */
734
 
  if ([attributes objectForKey: NSFileOwnerAccountName] == nil 
735
 
    && [attributes objectForKey: NSFileOwnerAccountNumber] == nil 
736
 
    && geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
737
 
    {
738
 
      attributes = [NSDictionary dictionaryWithObjectsAndKeys: 
739
 
                        NSFileOwnerAccountName, NSUserName(), nil];
740
 
      if (![self changeFileAttributes: attributes atPath: path])
741
 
        {
742
 
          NSLog(@"Failed to change ownership of '%@' to '%@'",
743
 
                path, NSUserName());
744
 
        }
745
 
    }
746
 
 
747
 
  len = [contents length];
748
 
  if (len > 0)
749
 
    {
750
 
      written = write(fd, [contents bytes], len);
751
 
    }
752
 
  else
753
 
    {
754
 
      written = 0;
755
 
    }
756
 
  close (fd);
757
 
#endif
758
 
  return written == len;
759
 
}
760
 
 
761
 
// Getting and comparing file contents
762
 
 
763
 
- (NSData*) contentsAtPath: (NSString*)path
764
 
{
765
 
  return [NSData dataWithContentsOfFile: path];
766
 
}
767
 
 
768
 
- (BOOL) contentsEqualAtPath: (NSString*)path1 andPath: (NSString*)path2
769
 
{
770
 
  NSDictionary  *d1;
771
 
  NSDictionary  *d2;
772
 
  NSString      *t;
773
 
 
774
 
  if ([path1 isEqual: path2])
775
 
    return YES;
776
 
  d1 = [self fileAttributesAtPath: path1 traverseLink: NO];
777
 
  d2 = [self fileAttributesAtPath: path2 traverseLink: NO];
778
 
  t = [d1 objectForKey: NSFileType];
779
 
  if ([t isEqual: [d2 objectForKey: NSFileType]] == NO)
780
 
    return NO;
781
 
  if ([t isEqual: NSFileTypeRegular])
782
 
    {
783
 
      id        s1 = [d1 objectForKey: NSFileSize];
784
 
      id        s2 = [d2 objectForKey: NSFileSize];
785
 
 
786
 
      if ([s1 isEqual: s2] == YES)
787
 
        {
788
 
          NSData        *c1 = [NSData dataWithContentsOfFile: path1];
789
 
          NSData        *c2 = [NSData dataWithContentsOfFile: path2];
790
 
 
791
 
          if ([c1 isEqual: c2])
792
 
            return YES;
793
 
        }
794
 
      return NO;
795
 
    }
796
 
  else if ([t isEqual: NSFileTypeDirectory])
797
 
    {
798
 
      NSArray   *a1 = [self directoryContentsAtPath: path1];
799
 
      NSArray   *a2 = [self directoryContentsAtPath: path2];
800
 
      unsigned  index, count = [a1 count];
801
 
      BOOL      ok = YES;
802
 
 
803
 
      if ([a1 isEqual: a2] == NO)
804
 
        return NO;
805
 
 
806
 
      for (index = 0; ok == YES && index < count; index++)
807
 
        {
808
 
          NSString      *n = [a1 objectAtIndex: index];
809
 
          NSString      *p1;
810
 
          NSString      *p2;
811
 
          CREATE_AUTORELEASE_POOL(pool);
812
 
 
813
 
          p1 = [path1 stringByAppendingPathComponent: n];
814
 
          p2 = [path2 stringByAppendingPathComponent: n];
815
 
          d1 = [self fileAttributesAtPath: p1 traverseLink: NO];
816
 
          d2 = [self fileAttributesAtPath: p2 traverseLink: NO];
817
 
          t = [d1 objectForKey: NSFileType];
818
 
          if ([t isEqual: [d2 objectForKey: NSFileType]] == NO)
819
 
            {
820
 
              ok = NO;
821
 
            }
822
 
          else if ([t isEqual: NSFileTypeDirectory])
823
 
            {
824
 
              ok = [self contentsEqualAtPath: p1 andPath: p2];
825
 
            }
826
 
          RELEASE(pool);
827
 
        }
828
 
      return ok;
829
 
    }
830
 
  else
831
 
    return YES;
832
 
}
833
 
 
834
 
// Determining access to files
835
 
 
 
1286
        {
 
1287
          return YES;
 
1288
        }
 
1289
    }
 
1290
}
 
1291
 
 
1292
/**
 
1293
 * Returns YES if a file (or directory etc) exists at the specified path.
 
1294
 */
836
1295
- (BOOL) fileExistsAtPath: (NSString*)path
837
1296
{
838
 
  return [self fileExistsAtPath: path isDirectory: NULL];
 
1297
  return [self fileExistsAtPath: path isDirectory: 0];
839
1298
}
840
1299
 
 
1300
/**
 
1301
 * Returns YES if a file (or directory etc) exists at the specified path.<br />
 
1302
 * If the isDirectory argument is not a nul pointer, stores a flag
 
1303
 * in the location it points to, indicating whether the file is a
 
1304
 * directory or not.<br />
 
1305
 */
841
1306
- (BOOL) fileExistsAtPath: (NSString*)path isDirectory: (BOOL*)isDirectory
842
1307
{
843
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
844
 
 
845
 
  if (cpath == 0 || *cpath == '\0')
 
1308
  const _CHAR *lpath = OS2LOCAL(self, path);
 
1309
 
 
1310
  if (isDirectory != 0)
 
1311
    {
 
1312
      *isDirectory = NO;
 
1313
    }
 
1314
 
 
1315
  if (lpath == 0 || *lpath == _NUL)
846
1316
    {
847
1317
      return NO;
848
1318
    }
849
 
  else
850
 
    {
 
1319
 
851
1320
#if defined(__MINGW__)
 
1321
    {
852
1322
      DWORD res;
853
1323
 
854
 
      res = GetFileAttributes(cpath);
 
1324
      res = GetFileAttributes(lpath);
855
1325
      if (res == WIN32ERR)
856
1326
        {
857
1327
          return NO;
862
1332
            {
863
1333
              *isDirectory = YES;
864
1334
            }
865
 
          else
866
 
            {
867
 
              *isDirectory = NO;
868
 
            }
869
1335
        }
870
1336
      return YES;
 
1337
    }
871
1338
#else
872
 
      struct stat statbuf;
873
 
 
874
 
      if (stat(cpath, &statbuf) != 0)
875
 
        return NO;
876
 
    
 
1339
    {
 
1340
      struct _STATB statbuf;
 
1341
 
 
1342
      if (_STAT(lpath, &statbuf) != 0)
 
1343
        {
 
1344
          return NO;
 
1345
        }
 
1346
 
877
1347
      if (isDirectory)
878
1348
        {
879
 
          *isDirectory = ((statbuf.st_mode & S_IFMT) == S_IFDIR);
 
1349
          if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
 
1350
            {
 
1351
              *isDirectory = YES;
 
1352
            }
880
1353
        }
881
 
    
 
1354
 
882
1355
      return YES;
 
1356
    }
883
1357
#endif /* MINGW */
884
 
    }
885
1358
}
886
1359
 
 
1360
/**
 
1361
 * Returns YES if a file (or directory etc) exists at the specified path
 
1362
 * and is readable.
 
1363
 */
887
1364
- (BOOL) isReadableFileAtPath: (NSString*)path
888
1365
{
889
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
 
1366
  const _CHAR* lpath = OS2LOCAL(self, path);
890
1367
 
891
 
  if (cpath == 0 || *cpath == '\0')
892
 
    return NO;
893
 
  else
 
1368
  if (lpath == 0 || *lpath == _NUL)
894
1369
    {
 
1370
      return NO;
 
1371
    }
 
1372
 
895
1373
#if defined(__MINGW__)
896
 
      DWORD res= GetFileAttributes(cpath);
 
1374
    {
 
1375
      DWORD res = GetFileAttributes(lpath);
897
1376
 
898
1377
      if (res == WIN32ERR)
899
 
        return NO;
 
1378
        {
 
1379
          return NO;
 
1380
        }
900
1381
      return YES;
 
1382
    }
901
1383
#else
902
 
      return (access(cpath, R_OK) == 0);
 
1384
    {
 
1385
      if (access(lpath, R_OK) == 0)
 
1386
        {
 
1387
          return YES;
 
1388
        }
 
1389
      return NO;
 
1390
    }
903
1391
#endif
904
 
    }
905
1392
}
906
1393
 
 
1394
/**
 
1395
 * Returns YES if a file (or directory etc) exists at the specified path
 
1396
 * and is writable.
 
1397
 */
907
1398
- (BOOL) isWritableFileAtPath: (NSString*)path
908
1399
{
909
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
 
1400
  const _CHAR* lpath = OS2LOCAL(self, path);
910
1401
 
911
 
  if (cpath == 0 || *cpath == '\0')
912
 
    return NO;
913
 
  else
 
1402
  if (lpath == 0 || *lpath == _NUL)
914
1403
    {
 
1404
      return NO;
 
1405
    }
 
1406
 
915
1407
#if defined(__MINGW__)
916
 
      DWORD res= GetFileAttributes(cpath);
 
1408
    {
 
1409
      DWORD res= GetFileAttributes(lpath);
917
1410
 
918
1411
      if (res == WIN32ERR)
919
 
        return NO;
920
 
      return (res & FILE_ATTRIBUTE_READONLY) ? NO : YES;
 
1412
        {
 
1413
          return NO;
 
1414
        }
 
1415
      if (res & FILE_ATTRIBUTE_READONLY)
 
1416
        {
 
1417
          return NO;
 
1418
        }
 
1419
      return YES;
 
1420
    }
921
1421
#else
922
 
      return (access(cpath, W_OK) == 0);
 
1422
    {
 
1423
      if (access(lpath, W_OK) == 0)
 
1424
        {
 
1425
          return YES;
 
1426
        }
 
1427
      return NO;
 
1428
    }
923
1429
#endif
924
 
    }
925
1430
}
926
1431
 
 
1432
/**
 
1433
 * Returns YES if a file (or directory etc) exists at the specified path
 
1434
 * and is executable (if a directory is executable, you can access its
 
1435
 * contents).
 
1436
 */
927
1437
- (BOOL) isExecutableFileAtPath: (NSString*)path
928
1438
{
929
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
 
1439
  const _CHAR* lpath = OS2LOCAL(self, path);
930
1440
 
931
 
  if (cpath == 0 || *cpath == '\0')
932
 
    return NO;
933
 
  else
 
1441
  if (lpath == 0 || *lpath == _NUL)
934
1442
    {
 
1443
      return NO;
 
1444
    }
 
1445
 
935
1446
#if defined(__MINGW__)
936
 
      DWORD res= GetFileAttributes(cpath);
937
 
      int len = strlen(cpath);
 
1447
    {
 
1448
      DWORD res= GetFileAttributes(lpath);
938
1449
 
939
1450
      if (res == WIN32ERR)
940
 
        return NO;
941
 
      if (len > 4 && strcmp(&cpath[len-4], ".exe") == 0)
942
 
        return YES;
 
1451
        {
 
1452
          return NO;
 
1453
        }
 
1454
      if ([[[path pathExtension] lowercaseString] isEqualToString: @"exe"])
 
1455
        {
 
1456
          return YES;
 
1457
        }
943
1458
      /* FIXME: On unix, directory accessable == executable, so we simulate that
944
 
         here for Windows. Is there a better check for directory access? */
 
1459
      here for Windows. Is there a better check for directory access? */
945
1460
      if (res & FILE_ATTRIBUTE_DIRECTORY)
946
 
        return YES;
 
1461
        {
 
1462
          return YES;
 
1463
        }
947
1464
      return NO;
 
1465
    }
948
1466
#else
949
 
      return (access(cpath, X_OK) == 0);
 
1467
    {
 
1468
      if (access(lpath, X_OK) == 0)
 
1469
        {
 
1470
          return YES;
 
1471
        }
 
1472
      return NO;
 
1473
    }
950
1474
#endif
951
 
    }
952
1475
}
953
1476
 
 
1477
/**
 
1478
 * Returns YES if a file (or directory etc) exists at the specified path
 
1479
 * and is deletable.
 
1480
 */
954
1481
- (BOOL) isDeletableFileAtPath: (NSString*)path
955
1482
{
956
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
 
1483
  const _CHAR* lpath = OS2LOCAL(self, path);
957
1484
 
958
 
  if (cpath == 0 || *cpath == '\0')
959
 
    return NO;
960
 
  else
 
1485
  if (lpath == 0 || *lpath == _NUL)
961
1486
    {
962
 
      // TODO - handle directories
 
1487
      return NO;
 
1488
    }
 
1489
 
963
1490
#if defined(__MINGW__)
964
 
      DWORD res= GetFileAttributes(cpath);
 
1491
    {
 
1492
      // TODO - handle directories
 
1493
      DWORD res= GetFileAttributes(lpath);
965
1494
 
966
1495
      if (res == WIN32ERR)
967
 
        return NO;
 
1496
        {
 
1497
          return NO;
 
1498
        }
968
1499
      return (res & FILE_ATTRIBUTE_READONLY) ? NO : YES;
 
1500
    }
969
1501
#else
970
 
      cpath = [self fileSystemRepresentationWithPath: 
971
 
        [path stringByDeletingLastPathComponent]];
972
 
    
973
 
      return  (access(cpath, X_OK || W_OK) != 0);
 
1502
    {
 
1503
      // TODO - handle directories
 
1504
      path = [path stringByDeletingLastPathComponent];
 
1505
      if ([path length] == 0)
 
1506
        {
 
1507
          path = @".";
 
1508
        }
 
1509
      lpath = OS2LOCAL(self, path);
 
1510
 
 
1511
      if (access(lpath, X_OK | W_OK) == 0)
 
1512
        {
 
1513
          return YES;
 
1514
        }
 
1515
      return NO;
 
1516
    }
974
1517
#endif
975
 
    }
976
1518
}
977
1519
 
 
1520
 
 
1521
/**
 
1522
 * If a file (or directory etc) exists at the specified path, and can be
 
1523
 * queried for its attributes, this method returns a dictionary containing
 
1524
 * the various attributes of that file.  Otherwise nil is returned.<br />
 
1525
 * If the flag is NO and the file is a symbolic link, the attributes of
 
1526
 * the link itself (rather than the file it points to) are returned.<br />
 
1527
 * <p>
 
1528
 *   The dictionary keys for attributes are -
 
1529
 * </p>
 
1530
 * <deflist>
 
1531
 *   <term><code>NSFileAppendOnly</code></term>
 
1532
 *   <desc>NSNumber ... boolean</desc>
 
1533
 *   <term><code>NSFileCreationDate</code></term>
 
1534
 *   <desc>NSDate when the file was created (if supported)</desc>
 
1535
 *   <term><code>NSFileDeviceIdentifier</code></term>
 
1536
 *   <desc>NSNumber (identifies the device on which the file is stored)</desc>
 
1537
 *   <term><code>NSFileExtensionHidden</code></term>
 
1538
 *   <desc>NSNumber ... boolean</desc>
 
1539
 *   <term><code>NSFileGroupOwnerAccountName</code></term>
 
1540
 *   <desc>NSString name of the file group</desc>
 
1541
 *   <term><code>NSFileGroupOwnerAccountID</code></term>
 
1542
 *   <desc>NSNumber ID of the file group</desc>
 
1543
 *   <term><code>NSFileHFSCreatorCode</code></term>
 
1544
 *   <desc>NSNumber not used</desc>
 
1545
 *   <term><code>NSFileHFSTypeCode</code></term>
 
1546
 *   <desc>NSNumber not used</desc>
 
1547
 *   <term><code>NSFileImmutable</code></term>
 
1548
 *   <desc>NSNumber ... boolean</desc>
 
1549
 *   <term><code>NSFileModificationDate</code></term>
 
1550
 *   <desc>NSDate when the file was last modified</desc>
 
1551
 *   <term><code>NSFileOwnerAccountName</code></term>
 
1552
 *   <desc>NSString name of the file owner</desc>
 
1553
 *   <term><code>NSFileOwnerAccountID</code></term>
 
1554
 *   <desc>NSNumber ID of the file owner</desc>
 
1555
 *   <term><code>NSFilePosixPermissions</code></term>
 
1556
 *   <desc>NSNumber posix access permissions mask</desc>
 
1557
 *   <term><code>NSFileReferenceCount</code></term>
 
1558
 *   <desc>NSNumber number of links to this file</desc>
 
1559
 *   <term><code>NSFileSize</code></term>
 
1560
 *   <desc>NSNumber size of the file in bytes</desc>
 
1561
 *   <term><code>NSFileSystemFileNumber</code></term>
 
1562
 *   <desc>NSNumber the identifier for the file on the filesystem</desc>
 
1563
 *   <term><code>NSFileSystemNumber</code></term>
 
1564
 *   <desc>NSNumber the filesystem on which the file is stored</desc>
 
1565
 *   <term><code>NSFileType</code></term>
 
1566
 *   <desc>NSString the type of file</desc>
 
1567
 * </deflist>
 
1568
 * <p>
 
1569
 *   The [NSDictionary] class also has a set of convenience accessor methods
 
1570
 *   which enable you to get at file attribute information more efficiently
 
1571
 *   than using the keys above to extract it.  You should generally
 
1572
 *   use the accessor methods where they are available.
 
1573
 * </p>
 
1574
 * <list>
 
1575
 *   <item>[NSDictionary-fileCreationDate]</item>
 
1576
 *   <item>[NSDictionary-fileExtensionHidden]</item>
 
1577
 *   <item>[NSDictionary-fileHFSCreatorCode]</item>
 
1578
 *   <item>[NSDictionary-fileHFSTypeCode]</item>
 
1579
 *   <item>[NSDictionary-fileIsAppendOnly]</item>
 
1580
 *   <item>[NSDictionary-fileIsImmutable]</item>
 
1581
 *   <item>[NSDictionary-fileSize]</item>
 
1582
 *   <item>[NSDictionary-fileType]</item>
 
1583
 *   <item>[NSDictionary-fileOwnerAccountName]</item>
 
1584
 *   <item>[NSDictionary-fileOwnerAccountID]</item>
 
1585
 *   <item>[NSDictionary-fileGroupOwnerAccountName]</item>
 
1586
 *   <item>[NSDictionary-fileGroupOwnerAccountID]</item>
 
1587
 *   <item>[NSDictionary-fileModificationDate]</item>
 
1588
 *   <item>[NSDictionary-filePosixPermissions]</item>
 
1589
 *   <item>[NSDictionary-fileSystemNumber]</item>
 
1590
 *   <item>[NSDictionary-fileSystemFileNumber]</item>
 
1591
 * </list>
 
1592
 */
978
1593
- (NSDictionary*) fileAttributesAtPath: (NSString*)path traverseLink: (BOOL)flag
979
1594
{
980
 
  return [self _attributesAtPath: path traverseLink: flag forCopy: NO];
 
1595
  const _CHAR   *lpath = OS2LOCAL(self, path);
 
1596
  NSDictionary  *d;
 
1597
 
 
1598
  d = [GSAttrDictionary attributesAt: lpath traverseLink: flag];
 
1599
  return d;
981
1600
}
982
1601
 
 
1602
/**
 
1603
 * Returns a dictionary containing the filesystem attributes for the
 
1604
 * specified path (or nil if the path is not valid).<br />
 
1605
 * <deflist>
 
1606
 *   <term><code>NSFileSystemSize</code></term>
 
1607
 *   <desc>NSNumber the size of the filesystem in bytes</desc>
 
1608
 *   <term><code>NSFileSystemFreeSize</code></term>
 
1609
 *   <desc>NSNumber the amount of unused space on the filesystem in bytes</desc>
 
1610
 *   <term><code>NSFileSystemNodes</code></term>
 
1611
 *   <desc>NSNumber the number of nodes in use to store files</desc>
 
1612
 *   <term><code>NSFileSystemFreeNodes</code></term>
 
1613
 *   <desc>NSNumber the number of nodes available to create files</desc>
 
1614
 *   <term><code>NSFileSystemNumber</code></term>
 
1615
 *   <desc>NSNumber the identifying number for the filesystem</desc>
 
1616
 * </deflist>
 
1617
 */
983
1618
- (NSDictionary*) fileSystemAttributesAtPath: (NSString*)path
984
1619
{
985
1620
#if defined(__MINGW__)
986
1621
  unsigned long long totalsize, freesize;
987
1622
  id  values[5];
988
1623
  id    keys[5] = {
989
 
          NSFileSystemSize,
990
 
          NSFileSystemFreeSize,
991
 
          NSFileSystemNodes,
992
 
          NSFileSystemFreeNodes,
993
 
          NSFileSystemNumber
994
 
      };
 
1624
    NSFileSystemSize,
 
1625
    NSFileSystemFreeSize,
 
1626
    NSFileSystemNodes,
 
1627
    NSFileSystemFreeNodes,
 
1628
    NSFileSystemNumber
 
1629
  };
995
1630
  DWORD SectorsPerCluster, BytesPerSector, NumberFreeClusters;
996
1631
  DWORD TotalNumberClusters;
997
 
  const char *cpath = [self fileSystemRepresentationWithPath: path];
 
1632
  const _CHAR *lpath = OS2LOCAL(self, path);
998
1633
 
999
 
  if (!GetDiskFreeSpace(cpath, &SectorsPerCluster,
 
1634
  if (!GetDiskFreeSpace(lpath, &SectorsPerCluster,
1000
1635
    &BytesPerSector, &NumberFreeClusters, &TotalNumberClusters))
1001
 
    return nil;
 
1636
    {
 
1637
      return nil;
 
1638
    }
1002
1639
 
1003
1640
  totalsize = (unsigned long long)TotalNumberClusters
1004
1641
    * (unsigned long long)SectorsPerCluster
1006
1643
  freesize = (unsigned long long)NumberFreeClusters
1007
1644
    * (unsigned long long)SectorsPerCluster
1008
1645
    * (unsigned long long)BytesPerSector;
1009
 
  
 
1646
 
1010
1647
  values[0] = [NSNumber numberWithUnsignedLongLong: totalsize];
1011
1648
  values[1] = [NSNumber numberWithUnsignedLongLong: freesize];
1012
1649
  values[2] = [NSNumber numberWithLong: LONG_MAX];
1013
1650
  values[3] = [NSNumber numberWithLong: LONG_MAX];
1014
1651
  values[4] = [NSNumber numberWithUnsignedInt: 0];
1015
 
  
 
1652
 
1016
1653
  return [NSDictionary dictionaryWithObjects: values forKeys: keys count: 5];
1017
 
  
 
1654
 
1018
1655
#else
1019
 
#if HAVE_SYS_VFS_H || HAVE_SYS_STATFS_H || HAVE_SYS_MOUNT_H
1020
 
  struct stat statbuf;
1021
 
#if HAVE_STATVFS
 
1656
#if defined(HAVE_SYS_VFS_H) || defined(HAVE_SYS_STATFS_H) \
 
1657
  || defined(HAVE_SYS_MOUNT_H)
 
1658
  struct _STATB statbuf;
 
1659
#ifdef HAVE_STATVFS
1022
1660
  struct statvfs statfsbuf;
1023
1661
#else
1024
1662
  struct statfs statfsbuf;
1025
1663
#endif
1026
1664
  unsigned long long totalsize, freesize;
1027
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
1028
 
  
 
1665
  const char* lpath = [self fileSystemRepresentationWithPath: path];
 
1666
 
1029
1667
  id  values[5];
1030
1668
  id    keys[5] = {
1031
 
          NSFileSystemSize,
1032
 
          NSFileSystemFreeSize,
1033
 
          NSFileSystemNodes,
1034
 
          NSFileSystemFreeNodes,
1035
 
          NSFileSystemNumber
1036
 
      };
1037
 
  
1038
 
  if (stat(cpath, &statbuf) != 0)
1039
 
    return nil;
 
1669
    NSFileSystemSize,
 
1670
    NSFileSystemFreeSize,
 
1671
    NSFileSystemNodes,
 
1672
    NSFileSystemFreeNodes,
 
1673
    NSFileSystemNumber
 
1674
  };
1040
1675
 
1041
 
#if HAVE_STATVFS
1042
 
  if (statvfs(cpath, &statfsbuf) != 0)
1043
 
    return nil;
 
1676
  if (_STAT(lpath, &statbuf) != 0)
 
1677
    {
 
1678
      return nil;
 
1679
    }
 
1680
#ifdef HAVE_STATVFS
 
1681
  if (statvfs(lpath, &statfsbuf) != 0)
 
1682
    {
 
1683
      return nil;
 
1684
    }
1044
1685
#else
1045
 
  if (statfs(cpath, &statfsbuf) != 0)
1046
 
    return nil;
 
1686
  if (statfs(lpath, &statfsbuf) != 0)
 
1687
    {
 
1688
      return nil;
 
1689
    }
1047
1690
#endif
1048
1691
 
1049
1692
  totalsize = (unsigned long long) statfsbuf.f_bsize
1050
1693
    * (unsigned long long) statfsbuf.f_blocks;
1051
1694
  freesize = (unsigned long long) statfsbuf.f_bsize
1052
1695
    * (unsigned long long) statfsbuf.f_bavail;
1053
 
  
 
1696
 
1054
1697
  values[0] = [NSNumber numberWithUnsignedLongLong: totalsize];
1055
1698
  values[1] = [NSNumber numberWithUnsignedLongLong: freesize];
1056
1699
  values[2] = [NSNumber numberWithLong: statfsbuf.f_files];
1057
1700
  values[3] = [NSNumber numberWithLong: statfsbuf.f_ffree];
1058
1701
  values[4] = [NSNumber numberWithUnsignedLong: statbuf.st_dev];
1059
 
  
 
1702
 
1060
1703
  return [NSDictionary dictionaryWithObjects: values forKeys: keys count: 5];
1061
1704
#else
1062
1705
  return nil;
1064
1707
#endif /* MINGW */
1065
1708
}
1066
1709
 
1067
 
- (BOOL) changeFileAttributes: (NSDictionary*)attributes atPath: (NSString*)path
1068
 
{
1069
 
  const char    *cpath = [self fileSystemRepresentationWithPath: path];
1070
 
  NSNumber      *num;
1071
 
  NSString      *str;
1072
 
  NSDate        *date;
1073
 
  BOOL          allOk = YES;
1074
 
 
1075
 
#ifndef __MINGW__
1076
 
  num = [attributes objectForKey: NSFileOwnerAccountNumber];
1077
 
  if (num)
1078
 
    {
1079
 
      if (chown(cpath, [num intValue], -1) != 0)
1080
 
        {
1081
 
          allOk = NO;
1082
 
          str = [NSString stringWithFormat:
1083
 
            @"Unable to change NSFileOwnerAccountNumber to '%@'", num];
1084
 
          ASSIGN(_lastError, str);
1085
 
        }
1086
 
    }
1087
 
  else
1088
 
    {
1089
 
      if ((str = [attributes objectForKey: NSFileOwnerAccountName]) != nil)
1090
 
        {
1091
 
          BOOL  ok = NO;
1092
 
#if HAVE_PWD_H  
1093
 
          struct passwd *pw = getpwnam([str cString]);
1094
 
 
1095
 
          if (pw)
1096
 
            {
1097
 
              ok = (chown(cpath, pw->pw_uid, -1) == 0);
1098
 
              chown(cpath, -1, pw->pw_gid);
1099
 
            }
1100
 
#endif
1101
 
          if (ok == NO)
1102
 
            {
1103
 
              allOk = NO;
1104
 
              str = [NSString stringWithFormat:
1105
 
                @"Unable to change NSFileOwnerAccountName to '%@'", str];
1106
 
              ASSIGN(_lastError, str);
1107
 
            }
1108
 
        }
1109
 
    }
1110
 
 
1111
 
  num = [attributes objectForKey: NSFileGroupOwnerAccountNumber];
1112
 
  if (num)
1113
 
    {
1114
 
      if (chown(cpath, -1, [num intValue]) != 0)
1115
 
        {
1116
 
          allOk = NO;
1117
 
          str = [NSString stringWithFormat:
1118
 
            @"Unable to change NSFileGroupOwnerAccountNumber to '%@'", num];
1119
 
          ASSIGN(_lastError, str);
1120
 
        }
1121
 
    }
1122
 
  else if ((str=[attributes objectForKey: NSFileGroupOwnerAccountName]) != nil)
1123
 
    {
1124
 
      BOOL      ok = NO;
1125
 
#if HAVE_GRP_H
1126
 
      struct group *gp = getgrnam([str cString]);
1127
 
 
1128
 
      if (gp)
1129
 
        {
1130
 
          if (chown(cpath, -1, gp->gr_gid) == 0)
1131
 
            ok = YES;
1132
 
        }
1133
 
#endif
1134
 
      if (ok == NO)
1135
 
        {
1136
 
          allOk = NO;
1137
 
          str = [NSString stringWithFormat:
1138
 
            @"Unable to change NSFileGroupOwnerAccountName to '%@'", str];
1139
 
          ASSIGN(_lastError, str);
1140
 
        }
1141
 
    }
1142
 
#endif  /* __MINGW__ */
1143
 
 
1144
 
  num = [attributes objectForKey: NSFilePosixPermissions];
1145
 
  if (num)
1146
 
    {
1147
 
      if (chmod(cpath, [num intValue]) != 0)
1148
 
        {
1149
 
          allOk = NO;
1150
 
          str = [NSString stringWithFormat:
1151
 
            @"Unable to change NSFilePosixPermissions to '%o'", [num intValue]];
1152
 
          ASSIGN(_lastError, str);
1153
 
        }
1154
 
    }
1155
 
    
1156
 
  date = [attributes objectForKey: NSFileModificationDate];
1157
 
  if (date)
1158
 
    {
1159
 
      BOOL      ok = NO;
1160
 
      struct stat sb;
1161
 
#if  defined(__WIN32__) || defined(_POSIX_VERSION)
1162
 
      struct utimbuf ub;
1163
 
#else
1164
 
      time_t ub[2];
1165
 
#endif
1166
 
 
1167
 
      if (stat(cpath, &sb) != 0)
1168
 
        {
1169
 
          ok = NO;
1170
 
        }
1171
 
#if  defined(__WIN32__)
1172
 
      else if (sb.st_mode & _S_IFDIR)
1173
 
        {
1174
 
          ok = YES;     // Directories don't have modification times.
1175
 
        }
1176
 
#endif
1177
 
      else
1178
 
        {
1179
 
#if  defined(__WIN32__) || defined(_POSIX_VERSION)
1180
 
          ub.actime = sb.st_atime;
1181
 
          ub.modtime = [date timeIntervalSince1970];
1182
 
          ok = (utime(cpath, &ub) == 0);
1183
 
#else
1184
 
          ub[0] = sb.st_atime;
1185
 
          ub[1] = [date timeIntervalSince1970];
1186
 
          ok = (utime((char*)cpath, ub) == 0);
1187
 
#endif
1188
 
        }
1189
 
      if (ok == NO)
1190
 
        {
1191
 
          allOk = NO;
1192
 
          str = [NSString stringWithFormat:
1193
 
            @"Unable to change NSFileModificationDate to '%@'", date];
1194
 
          ASSIGN(_lastError, str);
1195
 
        }
1196
 
    }
1197
 
    
1198
 
  return allOk;
1199
 
}
1200
 
 
1201
 
// Discovering directory contents
1202
 
 
 
1710
/**
 
1711
 * Returns an array of the contents of the specified directory.<br />
 
1712
 * The listing does <strong>not</strong> recursively list subdirectories.<br />
 
1713
 * The special files '.' and '..' are not listed.<br />
 
1714
 * Indicates an error by returning nil (eg. if path is not a directory or
 
1715
 * it can't be read for some reason).
 
1716
 */
1203
1717
- (NSArray*) directoryContentsAtPath: (NSString*)path
1204
1718
{
1205
1719
  NSDirectoryEnumerator *direnum;
1212
1726
   * See if this is a directory (don't follow links).
1213
1727
   */
1214
1728
  if ([self fileExistsAtPath: path isDirectory: &is_dir] == NO || is_dir == NO)
1215
 
    return nil;
1216
 
 
1217
 
  /* We initialize the directory enumerator with justContents == YES, 
1218
 
     which tells the NSDirectoryEnumerator code that we only enumerate 
1219
 
     the contents non-recursively once, and exit.  NSDirectoryEnumerator 
 
1729
    {
 
1730
      return nil;
 
1731
    }
 
1732
  /* We initialize the directory enumerator with justContents == YES,
 
1733
     which tells the NSDirectoryEnumerator code that we only enumerate
 
1734
     the contents non-recursively once, and exit.  NSDirectoryEnumerator
1220
1735
     can perform some optms using this assumption. */
1221
 
  direnum = [[NSDirectoryEnumerator alloc] initWithDirectoryPath: path 
 
1736
  direnum = [[NSDirectoryEnumerator alloc] initWithDirectoryPath: path
1222
1737
                                           recurseIntoSubdirectories: NO
1223
1738
                                           followSymlinks: NO
1224
1739
                                           justContents: YES];
1228
1743
  addImp = [content methodForSelector: @selector(addObject:)];
1229
1744
 
1230
1745
  while ((path = (*nxtImp)(direnum, @selector(nextObject))) != nil)
1231
 
    (*addImp)(content, @selector(addObject:), path);
1232
 
 
 
1746
    {
 
1747
      (*addImp)(content, @selector(addObject:), path);
 
1748
    }
1233
1749
  RELEASE(direnum);
1234
1750
 
1235
 
  return content;
1236
 
}
1237
 
 
 
1751
  return [content makeImmutableCopyOnFail: NO];
 
1752
}
 
1753
 
 
1754
/**
 
1755
 * Returns the name of the file or directory at path.  Converts it into
 
1756
 * a format for display to an end user.  This may render it unusable as
 
1757
 * part of a file/path name.<br />
 
1758
 * For instance, if a user has elected not to see file extensions, this
 
1759
 * method may return filenames with the extension removed.<br />
 
1760
 * The default operation is to return the result of calling
 
1761
 * [NSString-lastPathComponent] on the path.
 
1762
 */
 
1763
- (NSString*) displayNameAtPath: (NSString*)path
 
1764
{
 
1765
  return [path lastPathComponent];
 
1766
}
 
1767
 
 
1768
/**
 
1769
 * Returns an enumerator which can be used to return each item with
 
1770
 * the directory at path in turn.<br />
 
1771
 * The enumeration is recursive ... following all nested subdirectories.
 
1772
 */
1238
1773
- (NSDirectoryEnumerator*) enumeratorAtPath: (NSString*)path
1239
1774
{
1240
1775
  return AUTORELEASE([[NSDirectoryEnumerator alloc]
1241
 
                       initWithDirectoryPath: path 
 
1776
                       initWithDirectoryPath: path
1242
1777
                       recurseIntoSubdirectories: YES
1243
1778
                       followSymlinks: NO
1244
1779
                       justContents: NO]);
1245
1780
}
1246
1781
 
 
1782
/**
 
1783
 * Returns an array containing the (relative) paths of all the items
 
1784
 * in the directory at path.<br />
 
1785
 * The listing follows all subdirectories, so it can produce a very
 
1786
 * large array ... use with care.
 
1787
 */
1247
1788
- (NSArray*) subpathsAtPath: (NSString*)path
1248
1789
{
1249
1790
  NSDirectoryEnumerator *direnum;
1251
1792
  BOOL                  isDir;
1252
1793
  IMP                   nxtImp;
1253
1794
  IMP                   addImp;
1254
 
  
 
1795
 
1255
1796
  if (![self fileExistsAtPath: path isDirectory: &isDir] || !isDir)
1256
 
    return nil;
1257
 
 
1258
 
  direnum = [[NSDirectoryEnumerator alloc] initWithDirectoryPath: path 
 
1797
    {
 
1798
      return nil;
 
1799
    }
 
1800
  direnum = [[NSDirectoryEnumerator alloc] initWithDirectoryPath: path
1259
1801
                                           recurseIntoSubdirectories: YES
1260
1802
                                           followSymlinks: NO
1261
1803
                                           justContents: NO];
1262
1804
  content = [NSMutableArray arrayWithCapacity: 128];
1263
 
  
 
1805
 
1264
1806
  nxtImp = [direnum methodForSelector: @selector(nextObject)];
1265
1807
  addImp = [content methodForSelector: @selector(addObject:)];
1266
 
  
 
1808
 
1267
1809
  while ((path = (*nxtImp)(direnum, @selector(nextObject))) != nil)
1268
1810
    {
1269
1811
      (*addImp)(content, @selector(addObject:), path);
1270
1812
    }
1271
 
  
 
1813
 
1272
1814
  RELEASE(direnum);
1273
1815
 
1274
 
  return content;
 
1816
  return [content makeImmutableCopyOnFail: NO];
1275
1817
}
1276
1818
 
1277
 
// Symbolic-link operations
1278
 
 
 
1819
/**
 
1820
 * Creates a symbolic link at path which links to the location
 
1821
 * specified by otherPath.
 
1822
 */
1279
1823
- (BOOL) createSymbolicLinkAtPath: (NSString*)path
1280
1824
                      pathContent: (NSString*)otherPath
1281
1825
{
1282
 
#if HAVE_SYMLINK
 
1826
#ifdef HAVE_SYMLINK
1283
1827
  const char* newpath = [self fileSystemRepresentationWithPath: path];
1284
1828
  const char* oldpath = [self fileSystemRepresentationWithPath: otherPath];
1285
 
    
 
1829
 
1286
1830
  return (symlink(oldpath, newpath) == 0);
1287
1831
#else
1288
1832
  return NO;
1289
1833
#endif
1290
1834
}
1291
1835
 
 
1836
/**
 
1837
 * Returns the name of the file or directory that the symbolic link
 
1838
 * at path points to.
 
1839
 */
1292
1840
- (NSString*) pathContentOfSymbolicLinkAtPath: (NSString*)path
1293
1841
{
1294
 
#if HAVE_READLINK
1295
 
  char  lpath[PATH_MAX];
1296
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
1297
 
  int   llen = readlink(cpath, lpath, PATH_MAX-1);
1298
 
    
 
1842
#ifdef HAVE_READLINK
 
1843
  char  buf[PATH_MAX];
 
1844
  const char* lpath = [self fileSystemRepresentationWithPath: path];
 
1845
  int   llen = readlink(lpath, buf, PATH_MAX-1);
 
1846
 
1299
1847
  if (llen > 0)
1300
 
    return [self stringWithFileSystemRepresentation: lpath length: llen];
 
1848
    {
 
1849
      return [self stringWithFileSystemRepresentation: buf length: llen];
 
1850
    }
1301
1851
  else
1302
 
    return nil;
 
1852
    {
 
1853
      return nil;
 
1854
    }
1303
1855
#else
1304
1856
  return nil;
1305
1857
#endif
1306
1858
}
1307
1859
 
1308
 
// Converting file-system representations
1309
 
 
 
1860
/**
 
1861
 * Convert from OpenStep internal path format (Unix-style) to a string in
 
1862
 * the local filesystem format, suitable for passing to system functions.<br />
 
1863
 * Under Unix, this simply standardizes the path and converts to a
 
1864
 * C string.<br />
 
1865
 * Under Windoze, this attempts to use local conventions to convert to a
 
1866
 * windows path.  In GNUstep, the conventional unix syntax '~user/...' can
 
1867
 * be used to indicate a windoze drive specification by using the drive
 
1868
 * letter in place of the username, and the syntax '~@server/...' can be used
 
1869
 * to indicate a file located on the named windoze network server (the
 
1870
 * '~@' maps to the leading '//' in a windoze UNC path specification.
 
1871
 */
1310
1872
- (const char*) fileSystemRepresentationWithPath: (NSString*)path
1311
1873
{
 
1874
  NSString      *localPath;
 
1875
  const char    *local_c_path = 0;
 
1876
 
 
1877
  localPath = [self localFromOpenStepPath: path];
 
1878
  if (localPath
 
1879
    && [localPath canBeConvertedToEncoding: [NSString defaultCStringEncoding]])
 
1880
    {
 
1881
      local_c_path = [localPath cString];
 
1882
    }
 
1883
  return (local_c_path);
 
1884
}
 
1885
 
 
1886
/**
 
1887
 * Convert from OpenStep internal path format (Unix-style) to a NSString in
 
1888
 * the local filesystem format.
 
1889
 * Under Windoze, this attempts to use local conventions to convert to a
 
1890
 * windows path.  In GNUstep, the conventional unix syntax '~user/...' can
 
1891
 * be used to indicate a windoze drive specification by using the drive
 
1892
 * letter in place of the username, and the syntax '~@server/...' can be used
 
1893
 * to indicate a file located on the named windoze network server (the
 
1894
 * '~@' maps to the leading '//' in a windoze UNC path specification.
 
1895
 */
 
1896
- (NSString*) localFromOpenStepPath: (NSString*)path
 
1897
{
 
1898
  NSString      *newpath = nil;
1312
1899
#ifdef __MINGW__
1313
 
  /*
1314
 
   * If path is in Unix format, transmorgrify it so Windows functions
1315
 
   * can handle it
1316
 
   */  
1317
 
  NSString      *newpath = path;
1318
 
  const char    *c_path = [path cString];
1319
 
  int           len = [path length];
1320
 
 
1321
 
  if (c_path == 0)
1322
 
    {
1323
 
      return 0;
1324
 
    }
1325
 
  if (len >= 3 && c_path[0] == '/' && c_path[1] == '/' && isalpha(c_path[2]))
1326
 
    {
1327
 
      if (len == 3 || c_path[3] == '/')
1328
 
        {
1329
 
          /* Cygwin "//c/" type absolute path */
1330
 
          newpath = [NSString stringWithFormat: @"%c:%s", c_path[2],
1331
 
            &c_path[3]];
1332
 
          newpath = [newpath stringByReplacingString: @"/" withString: @"\\"];
1333
 
        }
 
1900
/*
 
1901
* If path is in Unix format, transmogrify it so Windows functions
 
1902
* can handle it
 
1903
*/
 
1904
  int           wcount;         // count unichars
 
1905
  unichar       *wc_path = 0;
 
1906
  int           l;
 
1907
 
 
1908
  path = [path stringByStandardizingPath];
 
1909
  wcount = [path length];
 
1910
  if (wcount != 0)
 
1911
    {
 
1912
      l = wcount;
 
1913
      wc_path = (unichar*)calloc(wcount+10,sizeof(unichar));
 
1914
      [path getCharacters: (unichar *)wc_path];
 
1915
 
 
1916
      if (l >= 2 && wc_path[0] == L'~' && wc_path[1] == L'@')
 
1917
        {
 
1918
          // Convert to windows UNC path.
 
1919
          wc_path[0] = L'/';
 
1920
          wc_path[1] = L'/';
 
1921
          newpath = [NSString stringWithCharacters: wc_path length: wcount];
 
1922
        }
 
1923
      else if (l >= 2 && wc_path[0] == L'~' && iswalpha(wc_path[1])
 
1924
        && (l == 2 || wc_path[2] == L'/'))
 
1925
        {
 
1926
          wc_path[0] = wc_path[1];
 
1927
          wc_path[1] = L':';
 
1928
          newpath = [NSString stringWithCharacters: wc_path length: wcount];
 
1929
        }
 
1930
      else if (l >= 3 && wc_path[0] == L'/' && wc_path[1] == L'/'
 
1931
        && iswalpha(wc_path[2]))
 
1932
        {
 
1933
          if (l == 3 || wc_path[3] == L'/')
 
1934
            {
 
1935
              /* Cygwin "//c/" type absolute path */
 
1936
              wc_path[1] = wc_path[2];
 
1937
              wc_path[2] = L':';
 
1938
              newpath = [NSString stringWithCharacters: &wc_path[1]
 
1939
                                                length: wcount-1];
 
1940
            }
 
1941
          else
 
1942
            {
 
1943
              /* Windows absolute UNC path "//name/" */
 
1944
              newpath = path;
 
1945
            }
 
1946
        }
 
1947
      else if (isalpha(wc_path[0]) && wc_path[1] == L':')
 
1948
        {
 
1949
          /* Windows absolute path */
 
1950
          newpath = path;
 
1951
        }
 
1952
      else if (wc_path[0] == L'/')
 
1953
        {
 
1954
#ifdef  __CYGWIN__
 
1955
          if (l > 11 && wcsncmp(wc_path, L"/cygdrive/", 10) == 0
 
1956
            && wc_path[11] == L'/')
 
1957
            {
 
1958
              wc_path[9] = wc_path[10];
 
1959
              wc_path[10] = L':';
 
1960
              newpath = [NSString stringWithCharacters: &wc_path[9]
 
1961
                                                length: wcount-9];
 
1962
            }
 
1963
          else
 
1964
            {
 
1965
              NSDictionary      *env;
 
1966
              NSString          *cyghome;
 
1967
 
 
1968
              env = [[NSProcessInfo processInfo] environment];
 
1969
              cyghome = [env objectForKey: @"CYGWIN_HOME"];
 
1970
              if (cyghome != nil)
 
1971
                {
 
1972
                  /* FIXME: Find cygwin drive? */
 
1973
                  newpath = cyghome;
 
1974
                  newpath = [newpath stringByAppendingPathComponent: path];
 
1975
                }
 
1976
              else
 
1977
                {
 
1978
                  newpath = path;
 
1979
                }
 
1980
            }
 
1981
#else
 
1982
          if (l >= 2 && wc_path[0] == L'/' && iswalpha(wc_path[1])
 
1983
            && (l == 2 || wc_path[2] == L'/'))
 
1984
            {
 
1985
              /* Mingw /drive/... format */
 
1986
              wc_path[2] = L':';
 
1987
              newpath = [NSString stringWithCharacters: &wc_path[1]
 
1988
                                                length: wcount-1];
 
1989
            }
 
1990
          else
 
1991
            {
 
1992
              newpath = path;
 
1993
            }
 
1994
#endif
 
1995
        }
1334
1996
      else
1335
 
        {
1336
 
          /* Windows absolute UNC path "//name/" */
1337
 
          newpath = [newpath stringByReplacingString: @"/" withString: @"\\"];
1338
 
        }
1339
 
    }
1340
 
  else if (isalpha(c_path[0]) && c_path[1] == ':')
1341
 
    {
1342
 
      /* Unix absolute path */
 
1997
        {
 
1998
          newpath = path;
 
1999
        }
1343
2000
      newpath = [newpath stringByReplacingString: @"/" withString: @"\\"];
 
2001
      if (wc_path)
 
2002
        {
 
2003
          free (wc_path);
 
2004
        }
1344
2005
    }
1345
 
  else if (c_path[0] == '/')
 
2006
  else
1346
2007
    {
1347
 
      NSDictionary      *env;
1348
 
      NSString          *cyghome;
1349
 
 
1350
 
      env = [[NSProcessInfo processInfo] environment];
1351
 
      cyghome = [env objectForKey: @"CYGWIN_HOME"];
1352
 
      if (cyghome != nil)
1353
 
        {
1354
 
          /* FIXME: Find cygwin drive? */
1355
 
          newpath = cyghome;
1356
 
          newpath = [newpath stringByAppendingPathComponent: path];
1357
 
          newpath = [newpath stringByReplacingString: @"/" withString: @"\\"];
1358
 
        }
 
2008
      newpath = path;
1359
2009
    }
1360
 
  /* FIXME: Should we translate relative paths? */
1361
 
  return [newpath cString];
1362
2010
#else
1363
 
  return [path cString];
 
2011
  /*
 
2012
   * NB ... Don't standardize path, since that would automatically
 
2013
   * follow symbolic links ... and mess up any code wishing to
 
2014
   * examine the link itsself.
 
2015
   * We just need the path in a form where it can be interpreted by
 
2016
   * operating system calls (no '~' abbreviations for user directories).
 
2017
   */
 
2018
  newpath = [path stringByExpandingTildeInPath];
1364
2019
#endif
 
2020
 
 
2021
  return (newpath);
1365
2022
}
1366
2023
 
 
2024
/**
 
2025
 * This method converts from a local system specific filename representation
 
2026
 * to the internal OpenStep representation (unix-style).  This should be used
 
2027
 * whenever a filename is read in from the local system.<br />
 
2028
 * In GNUstep, windoze drive specifiers are encoded in the internal path
 
2029
 * using the conventuional unix syntax of '~user/...' where the drive letter
 
2030
 * is used instead of a username.
 
2031
 */
1367
2032
- (NSString*) stringWithFileSystemRepresentation: (const char*)string
1368
2033
                                          length: (unsigned int)len
1369
2034
{
1370
 
  return [NSString stringWithCString: string length: len];
 
2035
  NSString *localPath = nil;
 
2036
 
 
2037
  if (string != 0)
 
2038
    {
 
2039
      localPath = [NSString stringWithCString: string length: len];
 
2040
    }
 
2041
 
 
2042
  return([self openStepPathFromLocal: localPath]);
 
2043
}
 
2044
 
 
2045
/**
 
2046
 * This method converts from a local system specific filename representation
 
2047
 * to the internal OpenStep representation (unix-style).  This should be used
 
2048
 * whenever a filename is read in from the local system.<br />
 
2049
 * In GNUstep, windoze drive specifiers are encoded in the internal path
 
2050
 * using the conventuional unix syntax of '~user/...' where the drive letter
 
2051
 * is used instead of a username.
 
2052
 */
 
2053
- (NSString*) openStepPathFromLocal: (NSString*)localPath
 
2054
{
 
2055
#ifdef __MINGW__
 
2056
 
 
2057
  int           len;            // count unichars
 
2058
  unichar       *wc_path = 0;
 
2059
 
 
2060
  len = [localPath length];
 
2061
  if (len != 0)
 
2062
    {
 
2063
      wc_path = (unichar*)calloc(len+10,sizeof(unichar));
 
2064
      [localPath getCharacters: (unichar *)wc_path];
 
2065
    }
 
2066
  if (wc_path)
 
2067
    {
 
2068
      const unichar     *ptr = wc_path;
 
2069
      unichar           buf[len + 20];
 
2070
      unsigned          i;
 
2071
      unsigned          j;
 
2072
 
 
2073
      /*
 
2074
       * If path is in Windows format, transmogrify it so Unix functions
 
2075
       * can handle it
 
2076
       */
 
2077
      if (len == 0)
 
2078
        {
 
2079
          free(wc_path);
 
2080
          return @"";
 
2081
        }
 
2082
      if (len >= 2 && ((ptr[1] == L'/' && ptr[0] == L'/')
 
2083
        || (ptr[1] == L'\\' && ptr[0] == L'\\')))
 
2084
        {
 
2085
          /*
 
2086
           * Convert '//<servername>/' to '~@<servername>/' sequences.
 
2087
           */
 
2088
          buf[0] = L'~';
 
2089
          buf[1] = L'@';
 
2090
          i = 2;
 
2091
        }
 
2092
      else if (len >= 2 && ptr[1] == L':' && iswalpha(ptr[0]))
 
2093
        {
 
2094
          /*
 
2095
           * Convert '<driveletter>:' to '~<driveletter>/' sequences.
 
2096
           */
 
2097
          buf[0] = L'~';
 
2098
          buf[1] = ptr[0];
 
2099
          buf[2] = L'/';
 
2100
          ptr -= 1;
 
2101
          len++;
 
2102
          i = 3;
 
2103
        }
 
2104
#ifdef  __CYGWIN__
 
2105
      else if (len > 9 && wcsncmp(ptr, L"/cygdrive/", 10) == 0)
 
2106
        {
 
2107
          buf[0] = L'~';
 
2108
          ptr += 9;
 
2109
          len -= 9;
 
2110
          i = 1;
 
2111
        }
 
2112
#else
 
2113
      else if (len >= 2 && ptr[0] == L'/' && iswalpha(ptr[1])
 
2114
         && (len == 2 || ptr[2] == L'/'))
 
2115
        {
 
2116
          /*
 
2117
           * Convert '/<driveletter>' to '~<driveletter>' sequences.
 
2118
           */
 
2119
          buf[0] = L'~';
 
2120
          i = 1;
 
2121
        }
 
2122
#endif
 
2123
      else
 
2124
        {
 
2125
          i = 0;
 
2126
        }
 
2127
      /*
 
2128
       * Convert backslashes to slashes, colaescing adjacent slashes.
 
2129
       *  Also elide '/./' sequences, because we can do so efficiently.
 
2130
       */
 
2131
      j = i;
 
2132
      while (i < len)
 
2133
        {
 
2134
          if (ptr[i] == L'\\')
 
2135
            {
 
2136
              if (j == 0 || buf[j-1] != L'/')
 
2137
                {
 
2138
                  if (j > 2 && buf[j-2] == L'/' && buf[j-1] == L'.')
 
2139
                    {
 
2140
                      j--;
 
2141
                    }
 
2142
                  else
 
2143
                    {
 
2144
                      buf[j++] = L'/';
 
2145
                    }
 
2146
                }
 
2147
            }
 
2148
          else
 
2149
            {
 
2150
              buf[j++] = ptr[i];
 
2151
            }
 
2152
          i++;
 
2153
        }
 
2154
      buf[j] = _NUL;
 
2155
      // NSLog(@"Map '%s' to '%s'", string, buf);
 
2156
      free(wc_path);
 
2157
      return [NSString stringWithCharacters: buf length: j];
 
2158
    }
 
2159
  else
 
2160
    {
 
2161
      return(@"");
 
2162
    }
 
2163
#endif
 
2164
 
 
2165
  return localPath;
1371
2166
}
1372
2167
 
1373
2168
@end /* NSFileManager */
1374
2169
 
1375
 
/*
1376
 
 * NSDirectoryEnumerator implementation
1377
 
 *
1378
 
 * The Objective-C interface hides a traditional C implementation.
1379
 
 * This was the only way I could get near the speed of standard unix
1380
 
 * tools for big directories.
1381
 
 */
1382
 
 
1383
2170
/* A directory to enumerate.  We keep a stack of the directories we
1384
2171
   still have to enumerate.  We start by putting the top-level
1385
2172
   directory into the stack, then we start reading files from it
1392
2179
   removed from the stack, so the top of the stack if the top
1393
2180
   directory again, and enumeration continues in there.  */
1394
2181
typedef struct  _GSEnumeratedDirectory {
1395
 
  char *path;
1396
 
  DIR *pointer;
 
2182
  NSString *path;
 
2183
  _DIR *pointer;
1397
2184
} GSEnumeratedDirectory;
1398
2185
 
1399
2186
 
1400
2187
inline void gsedRelease(GSEnumeratedDirectory X)
1401
2188
{
1402
 
  free(X.path);
1403
 
  closedir(X.pointer);
 
2189
  DESTROY(X.path);
 
2190
  _CLOSEDIR(X.pointer);
1404
2191
}
1405
2192
 
1406
2193
#define GSI_ARRAY_TYPES 0
1408
2195
#define GSI_ARRAY_RELEASE(A, X)   gsedRelease(X.ext)
1409
2196
#define GSI_ARRAY_RETAIN(A, X)
1410
2197
 
1411
 
#include <base/GSIArray.h>
1412
 
 
1413
 
/* Portable replacement for strdup - return a copy of original.  */
1414
 
inline char *custom_strdup (const char *original)
1415
 
{
1416
 
  char *result;
1417
 
  unsigned length = sizeof(char) * (strlen (original) + 1);
1418
 
  
1419
 
  result = NSZoneMalloc(NSDefaultMallocZone(), length);
1420
 
  memcpy(result, original, length);
1421
 
  return result;
1422
 
}
1423
 
 
1424
 
/* The return value of this function is to be freed by using NSZoneFree().
1425
 
   The function takes for granted that path and file are correct
1426
 
   filesystem paths; that path does not end with a path separator, and
1427
 
   file does not begin with a path separator. */
1428
 
inline char *append_file_to_path (const char *path, const char *file)
1429
 
{
1430
 
  unsigned path_length = strlen(path);
1431
 
  unsigned file_length = strlen(file);
1432
 
  unsigned total_length = path_length + 1 + file_length;
1433
 
  char *result;
1434
 
 
1435
 
  if (path_length == 0)
1436
 
    {
1437
 
      return custom_strdup(file);
1438
 
    }
1439
 
 
1440
 
  result = NSZoneMalloc(NSDefaultMallocZone(), 
1441
 
                        sizeof(char) * total_length  + 1);
1442
 
  
1443
 
  memcpy(result, path, sizeof(char) * path_length);
1444
 
  
1445
 
#ifdef __MINGW__
1446
 
  result[path_length] = '\\';
1447
 
#else
1448
 
  result[path_length] = '/';
1449
 
#endif
1450
 
 
1451
 
  memcpy(&result[path_length + 1], file, sizeof(char) * file_length);
1452
 
  
1453
 
  result[total_length] = '\0';
1454
 
 
1455
 
  return result;  
1456
 
}
1457
 
 
1458
 
static SEL swfsSel = 0;
1459
 
 
 
2198
#include "GNUstepBase/GSIArray.h"
 
2199
 
 
2200
 
 
2201
static SEL ospfl = 0;
 
2202
 
 
2203
/**
 
2204
 *  <p>This is a subclass of <code>NSEnumerator</code> which provides a full
 
2205
 *  listing of all the files beneath a directory and its subdirectories.
 
2206
 *  Instances can be obtained through [NSFileManager-enumeratorAtPath:],
 
2207
 *  or through an initializer in this class.  (For compatibility with OS X,
 
2208
 *  use the <code>NSFileManager</code> method.)</p>
 
2209
 *
 
2210
 *  <p>This implementation is optimized and performance should be comparable
 
2211
 *  to the speed of standard Unix tools for large directories.</p>
 
2212
 */
1460
2213
@implementation NSDirectoryEnumerator
 
2214
/*
 
2215
 * The Objective-C interface hides a traditional C implementation.
 
2216
 * This was the only way I could get near the speed of standard unix
 
2217
 * tools for big directories.
 
2218
 */
1461
2219
 
1462
2220
+ (void) initialize
1463
2221
{
1465
2223
    {
1466
2224
      /* Initialize the default manager which we access directly */
1467
2225
      [NSFileManager defaultManager];
1468
 
      swfsSel = @selector(stringWithFileSystemRepresentation:length:);
 
2226
      ospfl = @selector(openStepPathFromLocal:);
1469
2227
    }
1470
2228
}
1471
2229
 
1472
2230
// Initializing
1473
2231
 
1474
 
- (id) initWithDirectoryPath: (NSString*)path 
 
2232
/**
 
2233
 *  Initialize instance to enumerate contents at path, which should be a
 
2234
 *  directory and can be specified in relative or absolute, and may include
 
2235
 *  Unix conventions like '<code>~</code>' for user home directory, which will
 
2236
 *  be appropriately converted on Windoze systems.  The justContents flag, if
 
2237
 *  set, is equivalent to recurseIntoSubdirectories = NO and followSymlinks =
 
2238
 *  NO, but the implementation will be made more efficient.
 
2239
 */
 
2240
- (id) initWithDirectoryPath: (NSString*)path
1475
2241
   recurseIntoSubdirectories: (BOOL)recurse
1476
2242
              followSymlinks: (BOOL)follow
1477
2243
                justContents: (BOOL)justContents
1478
2244
{
1479
 
  DIR *dir_pointer;
1480
 
  const char *topPath;
1481
 
  
1482
 
  _stringWithFileSysImp = (NSString *(*)(id, SEL, char *, unsigned))
1483
 
    [defaultManager methodForSelector: swfsSel];
1484
 
  
 
2245
//TODO: the justContents flag is currently basically useless and should be
 
2246
//      removed
 
2247
  _DIR          *dir_pointer;
 
2248
  const _CHAR   *localPath;
 
2249
 
 
2250
  self = [super init];
 
2251
 
 
2252
  _openStepPathFromLocalImp = (NSString *(*)(id, SEL,id))
 
2253
    [defaultManager methodForSelector: ospfl];
 
2254
 
1485
2255
  _stack = NSZoneMalloc([self zone], sizeof(GSIArray_t));
1486
2256
  GSIArrayInitWithZoneAndCapacity(_stack, [self zone], 64);
1487
 
  
 
2257
 
1488
2258
  _flags.isRecursive = recurse;
1489
2259
  _flags.isFollowing = follow;
1490
2260
  _flags.justContents = justContents;
1491
 
  topPath = [defaultManager fileSystemRepresentationWithPath: path];
1492
 
  _top_path = custom_strdup(topPath);
1493
 
  
1494
 
  dir_pointer = opendir(_top_path);
1495
 
  
 
2261
 
 
2262
  _topPath = [[NSString alloc] initWithString: path];
 
2263
 
 
2264
  localPath = OS2LOCAL(defaultManager, path);
 
2265
  dir_pointer = _OPENDIR(localPath);
1496
2266
  if (dir_pointer)
1497
2267
    {
1498
2268
      GSIArrayItem item;
1499
 
      
1500
 
      item.ext.path = custom_strdup("");
 
2269
 
 
2270
      item.ext.path = @"";
1501
2271
      item.ext.pointer = dir_pointer;
1502
 
      
 
2272
 
1503
2273
      GSIArrayAddItem(_stack, item);
1504
2274
    }
1505
2275
  else
1506
2276
    {
1507
 
      NSLog(@"Failed to recurse into directory '%@' - %s", path, 
1508
 
            GSLastErrorStr(errno));
 
2277
      NSLog(@"Failed to recurse into directory '%@' - %s", path,
 
2278
        GSLastErrorStr(errno));
1509
2279
    }
1510
 
  
1511
2280
  return self;
1512
2281
}
1513
2282
 
1515
2284
{
1516
2285
  GSIArrayEmpty(_stack);
1517
2286
  NSZoneFree([self zone], _stack);
1518
 
  NSZoneFree(NSDefaultMallocZone(), _top_path);
1519
 
  if (_current_file_path != NULL)
1520
 
    {
1521
 
      NSZoneFree(NSDefaultMallocZone(), _current_file_path);
1522
 
    }
 
2287
  DESTROY(_topPath);
 
2288
  DESTROY(_currentFilePath);
1523
2289
  [super dealloc];
1524
2290
}
1525
2291
 
1526
 
// Getting attributes
1527
 
 
 
2292
/**
 
2293
 * Returns a dictionary containing the attributes of the directory
 
2294
 * at which enumeration started. <br />
 
2295
 * The contents of this dictionary are as produced by
 
2296
 * [NSFileManager-fileAttributesAtPath:traverseLink:]
 
2297
 */
1528
2298
- (NSDictionary*) directoryAttributes
1529
2299
{
1530
 
  NSString *topPath;
1531
 
  
1532
 
  topPath = _stringWithFileSysImp(defaultManager, swfsSel, _top_path, 
1533
 
                                  strlen(_top_path));
1534
 
 
1535
 
  return [defaultManager fileAttributesAtPath: topPath
1536
 
                         traverseLink: _flags.isFollowing];
 
2300
  return [defaultManager fileAttributesAtPath: _topPath
 
2301
                                 traverseLink: _flags.isFollowing];
1537
2302
}
1538
2303
 
 
2304
/**
 
2305
 * Returns a dictionary containing the attributes of the file
 
2306
 * currently being enumerated. <br />
 
2307
 * The contents of this dictionary are as produced by
 
2308
 * [NSFileManager-fileAttributesAtPath:traverseLink:]
 
2309
 */
1539
2310
- (NSDictionary*) fileAttributes
1540
2311
{
1541
 
  NSString *currentFilePath;
1542
 
  
1543
 
  currentFilePath = _stringWithFileSysImp(defaultManager, swfsSel, 
1544
 
                                          _current_file_path, 
1545
 
                                          strlen(_current_file_path));
1546
 
 
1547
 
  return [defaultManager fileAttributesAtPath: currentFilePath
1548
 
                         traverseLink: _flags.isFollowing];
 
2312
  return [defaultManager fileAttributesAtPath: _currentFilePath
 
2313
                                 traverseLink: _flags.isFollowing];
1549
2314
}
1550
2315
 
1551
 
// Skipping subdirectories
1552
 
 
 
2316
/**
 
2317
 * Informs the receiver that any descendents of the current directory
 
2318
 * should be skipped rather than enumerated.  Use this to avaoid enumerating
 
2319
 * the contents of directories you are not interested in.
 
2320
 */
1553
2321
- (void) skipDescendents
1554
2322
{
1555
2323
  if (GSIArrayCount(_stack) > 0)
1556
2324
    {
1557
2325
      GSIArrayRemoveLastItem(_stack);
1558
 
      if (_current_file_path != NULL)
 
2326
      if (_currentFilePath != 0)
1559
2327
        {
1560
 
          NSZoneFree(NSDefaultMallocZone(), _current_file_path);
1561
 
          _current_file_path = NULL;
 
2328
          DESTROY(_currentFilePath);
1562
2329
        }
1563
2330
    }
1564
2331
}
1565
2332
 
1566
 
// Enumerate next
1567
 
 
 
2333
/*
 
2334
 * finds the next file according to the top enumerator
 
2335
 * - if there is a next file it is put in currentFile
 
2336
 * - if the current file is a directory and if isRecursive calls
 
2337
 * recurseIntoDirectory: currentFile
 
2338
 * - if the current file is a symlink to a directory and if isRecursive
 
2339
 * and isFollowing calls recurseIntoDirectory: currentFile
 
2340
 * - if at end of current directory pops stack and attempts to
 
2341
 * find the next entry in the parent
 
2342
 * - sets currentFile to nil if there are no more files to enumerate
 
2343
 */
1568
2344
- (id) nextObject
1569
2345
{
1570
 
  /*
1571
 
    finds the next file according to the top enumerator
1572
 
    - if there is a next file it is put in currentFile
1573
 
    - if the current file is a directory and if isRecursive calls 
1574
 
    recurseIntoDirectory: currentFile
1575
 
    - if the current file is a symlink to a directory and if isRecursive 
1576
 
    and isFollowing calls recurseIntoDirectory: currentFile
1577
 
    - if at end of current directory pops stack and attempts to
1578
 
    find the next entry in the parent
1579
 
    - sets currentFile to nil if there are no more files to enumerate
1580
 
  */
1581
 
  char *return_file_name = NULL;
 
2346
  NSString *returnFileName = 0;
1582
2347
 
1583
 
  if (_current_file_path != NULL)
 
2348
  if (_currentFilePath != 0)
1584
2349
    {
1585
 
      NSZoneFree(NSDefaultMallocZone(), _current_file_path);
1586
 
      _current_file_path = NULL;
 
2350
      DESTROY(_currentFilePath);
1587
2351
    }
1588
2352
 
1589
2353
  while (GSIArrayCount(_stack) > 0)
1590
2354
    {
1591
2355
      GSEnumeratedDirectory dir = GSIArrayLastItem(_stack).ext;
1592
 
      struct dirent *dirbuf;
1593
 
      struct stat statbuf;
1594
 
      
1595
 
      dirbuf = readdir(dir.pointer);
 
2356
      struct _DIRENT    *dirbuf;
 
2357
      struct _STATB     statbuf;
 
2358
 
 
2359
      dirbuf = _READDIR(dir.pointer);
 
2360
 
1596
2361
      if (dirbuf)
1597
2362
        {
1598
 
          /* Skip "." and ".." directory entries */
1599
 
          if (strcmp(dirbuf->d_name, ".") == 0 
1600
 
              || strcmp(dirbuf->d_name, "..") == 0)
1601
 
            continue;
1602
 
          
1603
 
          /* Name of file to return  */
1604
 
          return_file_name = append_file_to_path(dir.path, dirbuf->d_name);
1605
 
          
 
2363
#if defined(__MINGW__) && defined(UNICODE)
 
2364
          /* Skip "." and ".." directory entries */
 
2365
          if (wcscmp(dirbuf->d_name, L".") == 0
 
2366
            || wcscmp(dirbuf->d_name, L"..") == 0)
 
2367
            {
 
2368
              continue;
 
2369
            }
 
2370
          /* Name of file to return  */
 
2371
          returnFileName = _openStepPathFromLocalImp(defaultManager, ospfl,
 
2372
            [NSString stringWithCharacters: dirbuf->d_name
 
2373
                                    length: wcslen(dirbuf->d_name)]);
 
2374
#else
 
2375
          /* Skip "." and ".." directory entries */
 
2376
          if (strcmp(dirbuf->d_name, ".") == 0
 
2377
            || strcmp(dirbuf->d_name, "..") == 0)
 
2378
            {
 
2379
              continue;
 
2380
            }
 
2381
          /* Name of file to return  */
 
2382
          returnFileName = _openStepPathFromLocalImp(defaultManager, ospfl,
 
2383
            [NSString stringWithCString: dirbuf->d_name]);
 
2384
#endif
 
2385
          returnFileName = [dir.path stringByAppendingPathComponent:
 
2386
            returnFileName];
 
2387
          RETAIN(returnFileName);
 
2388
 
1606
2389
          /* TODO - can this one can be removed ? */
1607
2390
          if (!_flags.justContents)
1608
 
            {
1609
 
              _current_file_path = append_file_to_path(_top_path, 
1610
 
                                                       return_file_name);
1611
 
            }
1612
 
          if (_flags.isRecursive == YES)
 
2391
            _currentFilePath = RETAIN([_topPath stringByAppendingPathComponent:
 
2392
              returnFileName]);
 
2393
 
 
2394
          if (_flags.isRecursive == YES)
1613
2395
            {
1614
2396
              // Do not follow links
1615
2397
#ifdef S_IFLNK
 
2398
#ifdef __MINGW__
 
2399
#warning "lstat does not support unichars"
 
2400
#else
1616
2401
              if (!_flags.isFollowing)
1617
2402
                {
1618
 
                  if (lstat(_current_file_path, &statbuf) != 0)
1619
 
                    break;
 
2403
                  if (lstat([_currentFilePath fileSystemRepresentation],
 
2404
                    &statbuf) != 0)
 
2405
                    {
 
2406
                      break;
 
2407
                    }
1620
2408
                  // If link then return it as link
1621
 
                  if (S_IFLNK == (S_IFMT & statbuf.st_mode)) 
1622
 
                    break;
 
2409
                  if (S_IFLNK == (S_IFMT & statbuf.st_mode))
 
2410
                    {
 
2411
                      break;
 
2412
                    }
1623
2413
                }
1624
2414
              else
1625
2415
#endif
 
2416
#endif
1626
2417
                {
1627
 
                  if (stat(_current_file_path, &statbuf) != 0)
1628
 
                    break;
 
2418
                  if (_STAT(OS2LOCAL(defaultManager, _currentFilePath),
 
2419
                    &statbuf) != 0)
 
2420
                    {
 
2421
                      break;
 
2422
                    }
1629
2423
                }
1630
2424
              if (S_IFDIR == (S_IFMT & statbuf.st_mode))
1631
2425
                {
1632
 
                  DIR*  dir_pointer;
1633
 
                  
1634
 
                  dir_pointer = opendir(_current_file_path);
1635
 
                  
 
2426
                  _DIR*  dir_pointer;
 
2427
 
 
2428
                  dir_pointer
 
2429
                    = _OPENDIR(OS2LOCAL(defaultManager, _currentFilePath));
1636
2430
                  if (dir_pointer)
1637
2431
                    {
1638
2432
                      GSIArrayItem item;
1639
 
                      
1640
 
                      item.ext.path = custom_strdup(return_file_name);
 
2433
 
 
2434
                      item.ext.path = RETAIN(returnFileName);
1641
2435
                      item.ext.pointer = dir_pointer;
1642
 
      
 
2436
 
1643
2437
                      GSIArrayAddItem(_stack, item);
1644
2438
                    }
1645
2439
                  else
1646
2440
                    {
1647
 
                      NSLog(@"Failed to recurse into directory '%s' - %s",
1648
 
                        _current_file_path, GSLastErrorStr(errno));
 
2441
                      NSLog(@"Failed to recurse into directory '%@' - %s",
 
2442
                        _currentFilePath, GSLastErrorStr(errno));
1649
2443
                    }
1650
2444
                }
1651
2445
            }
1654
2448
      else
1655
2449
        {
1656
2450
          GSIArrayRemoveLastItem(_stack);
1657
 
          if (_current_file_path != NULL)
 
2451
          if (_currentFilePath != 0)
1658
2452
            {
1659
 
              NSZoneFree(NSDefaultMallocZone(), _current_file_path);
1660
 
              _current_file_path = NULL;
 
2453
              DESTROY(_currentFilePath);
1661
2454
            }
1662
2455
        }
1663
2456
    }
1664
 
  if (return_file_name == NULL)
1665
 
    {
1666
 
      return nil;
1667
 
    }
1668
 
  else
1669
 
    {
1670
 
      NSString *result = _stringWithFileSysImp(defaultManager, swfsSel, 
1671
 
                                               return_file_name, 
1672
 
                                               strlen(return_file_name));
1673
 
      NSZoneFree(NSDefaultMallocZone(), return_file_name);
1674
 
      return result;
1675
 
    }
 
2457
  return AUTORELEASE(returnFileName);
1676
2458
}
1677
2459
 
1678
2460
@end /* NSDirectoryEnumerator */
1679
2461
 
1680
 
@implementation NSDirectoryEnumerator (PrivateMethods)
1681
 
- (NSDictionary*) _attributesForCopy
1682
 
{
1683
 
  NSString *currentFilePath;
1684
 
  
1685
 
  currentFilePath = _stringWithFileSysImp(defaultManager, swfsSel, 
1686
 
                                          _current_file_path, 
1687
 
                                          strlen(_current_file_path));
1688
 
 
1689
 
  return [defaultManager _attributesAtPath: currentFilePath
1690
 
                         traverseLink: _flags.isFollowing
1691
 
                         forCopy: YES];
1692
 
}
1693
 
@end
1694
 
 
1695
 
/*
1696
 
 * Attributes dictionary access
 
2462
/**
 
2463
 * Convenience methods for accessing named file attributes in a dictionary.
1697
2464
 */
1698
 
 
1699
2465
@implementation NSDictionary(NSFileAttributes)
 
2466
 
 
2467
/**
 
2468
 * Return the file creation date attribute (or nil if not found).
 
2469
 */
 
2470
- (NSDate*) fileCreationDate
 
2471
{
 
2472
  return [self objectForKey: NSFileCreationDate];
 
2473
}
 
2474
 
 
2475
/**
 
2476
 * Return the file extension hidden attribute (or NO if not found).
 
2477
 */
 
2478
- (BOOL) fileExtensionHidden
 
2479
{
 
2480
  return [[self objectForKey: NSFileExtensionHidden] boolValue];
 
2481
}
 
2482
 
 
2483
/**
 
2484
 *  Returns HFS creator attribute (OS X).
 
2485
 */
 
2486
- (int) fileHFSCreatorCode
 
2487
{
 
2488
  return [[self objectForKey: NSFileHFSCreatorCode] intValue];
 
2489
}
 
2490
 
 
2491
/**
 
2492
 *  Returns HFS type code attribute (OS X).
 
2493
 */
 
2494
- (int) fileHFSTypeCode
 
2495
{
 
2496
  return [[self objectForKey: NSFileHFSTypeCode] intValue];
 
2497
}
 
2498
 
 
2499
/**
 
2500
 * Return the file append only attribute (or NO if not found).
 
2501
 */
 
2502
- (BOOL) fileIsAppendOnly
 
2503
{
 
2504
  return [[self objectForKey: NSFileAppendOnly] boolValue];
 
2505
}
 
2506
 
 
2507
/**
 
2508
 * Return the file immutable attribute (or NO if not found).
 
2509
 */
 
2510
- (BOOL) fileIsImmutable
 
2511
{
 
2512
  return [[self objectForKey: NSFileImmutable] boolValue];
 
2513
}
 
2514
 
 
2515
/**
 
2516
 * Return the size of the file, or NSNotFound if the file size attribute
 
2517
 * is not found in the dictionary.
 
2518
 */
1700
2519
- (unsigned long long) fileSize
1701
2520
{
1702
 
  return [[self objectForKey: NSFileSize] unsignedLongLongValue];
 
2521
  NSNumber      *n = [self objectForKey: NSFileSize];
 
2522
 
 
2523
  if (n == nil)
 
2524
    {
 
2525
      return NSNotFound;
 
2526
    }
 
2527
  return [n unsignedLongLongValue];
1703
2528
}
1704
2529
 
 
2530
/**
 
2531
 * Return the file type attribute or nil if not present.
 
2532
 */
1705
2533
- (NSString*) fileType
1706
2534
{
1707
2535
  return [self objectForKey: NSFileType];
1708
2536
}
1709
2537
 
 
2538
/**
 
2539
 * Return the file owner account name attribute or nil if not present.
 
2540
 */
1710
2541
- (NSString*) fileOwnerAccountName
1711
2542
{
1712
2543
  return [self objectForKey: NSFileOwnerAccountName];
1713
2544
}
1714
2545
 
1715
 
- (unsigned long) fileOwnerAccountNumber
 
2546
/**
 
2547
 * Return the numeric value of the NSFileOwnerAccountID attribute
 
2548
 * in the dictionary, or NSNotFound if the attribute is not present.
 
2549
 */
 
2550
- (unsigned long) fileOwnerAccountID
1716
2551
{
1717
 
  return [[self objectForKey: NSFileOwnerAccountNumber] unsignedIntValue];
 
2552
  NSNumber      *n = [self objectForKey: NSFileOwnerAccountID];
 
2553
 
 
2554
  if (n == nil)
 
2555
    {
 
2556
      return NSNotFound;
 
2557
    }
 
2558
  return [n unsignedIntValue];
1718
2559
}
1719
2560
 
 
2561
/**
 
2562
 * Return the file group owner account name attribute or nil if not present.
 
2563
 */
1720
2564
- (NSString*) fileGroupOwnerAccountName
1721
2565
{
1722
2566
  return [self objectForKey: NSFileGroupOwnerAccountName];
1723
2567
}
1724
2568
 
1725
 
- (unsigned long) fileGroupOwnerAccountNumber
 
2569
/**
 
2570
 * Return the numeric value of the NSFileGroupOwnerAccountID attribute
 
2571
 * in the dictionary, or NSNotFound if the attribute is not present.
 
2572
 */
 
2573
- (unsigned long) fileGroupOwnerAccountID
1726
2574
{
1727
 
  return [[self objectForKey: NSFileGroupOwnerAccountNumber] unsignedIntValue];
 
2575
  NSNumber      *n = [self objectForKey: NSFileGroupOwnerAccountID];
 
2576
 
 
2577
  if (n == nil)
 
2578
    {
 
2579
      return NSNotFound;
 
2580
    }
 
2581
  return [n unsignedIntValue];
1728
2582
}
1729
2583
 
 
2584
/**
 
2585
 * Return the file modification date attribute (or nil if not found)
 
2586
 */
1730
2587
- (NSDate*) fileModificationDate
1731
2588
{
1732
2589
  return [self objectForKey: NSFileModificationDate];
1733
2590
}
1734
2591
 
 
2592
/**
 
2593
 * Return the file posix permissions attribute (or NSNotFound if
 
2594
 * the attribute is not present in the dictionary).
 
2595
 */
1735
2596
- (unsigned long) filePosixPermissions
1736
2597
{
1737
 
  return [[self objectForKey: NSFilePosixPermissions] unsignedLongValue];
 
2598
  NSNumber      *n = [self objectForKey: NSFilePosixPermissions];
 
2599
 
 
2600
  if (n == nil)
 
2601
    {
 
2602
      return NSNotFound;
 
2603
    }
 
2604
  return [n unsignedLongValue];
1738
2605
}
1739
2606
 
 
2607
/**
 
2608
 * Return the file system number attribute (or NSNotFound if
 
2609
 * the attribute is not present in the dictionary).
 
2610
 */
1740
2611
- (unsigned long) fileSystemNumber
1741
2612
{
1742
 
  return [[self objectForKey: NSFileSystemNumber] unsignedLongValue];
 
2613
  NSNumber      *n = [self objectForKey: NSFileSystemNumber];
 
2614
 
 
2615
  if (n == nil)
 
2616
    {
 
2617
      return NSNotFound;
 
2618
    }
 
2619
  return [n unsignedLongValue];
1743
2620
}
1744
2621
 
 
2622
/**
 
2623
 * Return the file system file identification number attribute
 
2624
 * or NSNotFound if the attribute is not present in the dictionary).
 
2625
 */
1745
2626
- (unsigned long) fileSystemFileNumber
1746
2627
{
1747
 
  return [[self objectForKey: NSFileSystemFileNumber] unsignedLongValue];
 
2628
  NSNumber      *n = [self objectForKey: NSFileSystemFileNumber];
 
2629
 
 
2630
  if (n == nil)
 
2631
    {
 
2632
      return NSNotFound;
 
2633
    }
 
2634
  return [n unsignedLongValue];
1748
2635
}
1749
2636
@end
1750
2637
 
1755
2642
           handler: (id)handler
1756
2643
{
1757
2644
#if defined(__MINGW__)
1758
 
  if (CopyFile([self fileSystemRepresentationWithPath: source],
1759
 
    [self fileSystemRepresentationWithPath: destination], NO))
 
2645
  if (CopyFile(OS2LOCAL(self, source), OS2LOCAL(self, destination), NO))
1760
2646
    {
1761
2647
      return YES;
1762
2648
    }
1763
 
  if (handler != nil)
1764
 
    {
1765
 
      NSDictionary      *errorInfo
1766
 
        = [NSDictionary dictionaryWithObjectsAndKeys:
1767
 
                       source, @"Path",
1768
 
                       @"cannot copy file", @"Error",
1769
 
                       destination, @"ToPath",
1770
 
                       nil];
1771
 
      return [handler fileManager: self
1772
 
          shouldProceedAfterError: errorInfo];
1773
 
    }
1774
 
  else
1775
 
    {
1776
 
      return NO;
1777
 
    }
 
2649
 
 
2650
  return [self _proceedAccordingToHandler: handler
 
2651
                                 forError: @"cannot copy file"
 
2652
                                   inPath: source
 
2653
                                 fromPath: source
 
2654
                                   toPath: destination];
 
2655
 
1778
2656
#else
1779
2657
  NSDictionary  *attributes;
1780
2658
  int           i;
1791
2669
  NSAssert1 ([self fileExistsAtPath: source],
1792
2670
    @"source file '%@' does not exist!", source);
1793
2671
 
1794
 
  attributes = [self _attributesAtPath: source traverseLink: NO forCopy: YES];
 
2672
  attributes = [self fileAttributesAtPath: source traverseLink: NO];
1795
2673
  NSAssert1 (attributes, @"could not get the attributes for file '%@'",
1796
2674
    source);
1797
2675
 
1798
 
  fileSize = [[attributes objectForKey: NSFileSize] intValue];
1799
 
  fileMode = [[attributes objectForKey: NSFilePosixPermissions] intValue];
 
2676
  fileSize = [attributes fileSize];
 
2677
  fileMode = [attributes filePosixPermissions];
1800
2678
 
1801
2679
  /* Open the source file. In case of error call the handler. */
1802
2680
  sourceFd = open([self fileSystemRepresentationWithPath: source],
1803
2681
    GSBINIO|O_RDONLY);
1804
2682
  if (sourceFd < 0)
1805
2683
    {
1806
 
      if (handler != nil)
1807
 
        {
1808
 
          NSDictionary  *errorInfo
1809
 
            = [NSDictionary dictionaryWithObjectsAndKeys: 
1810
 
                      source, @"Path",
1811
 
                      @"cannot open file for reading", @"Error",
1812
 
                      nil];
1813
 
          return [handler fileManager: self
1814
 
              shouldProceedAfterError: errorInfo];
1815
 
        }
1816
 
      else
1817
 
        {
1818
 
          return NO;
1819
 
        }
 
2684
      return [self _proceedAccordingToHandler: handler
 
2685
                                     forError: @"cannot open file for reading"
 
2686
                                       inPath: source
 
2687
                                     fromPath: source
 
2688
                                       toPath: destination];
1820
2689
    }
1821
2690
 
1822
2691
  /* Open the destination file. In case of error call the handler. */
1824
2693
    GSBINIO|O_WRONLY|O_CREAT|O_TRUNC, fileMode);
1825
2694
  if (destFd < 0)
1826
2695
    {
1827
 
      if (handler != nil)
1828
 
        {
1829
 
          NSDictionary  *errorInfo
1830
 
            = [NSDictionary dictionaryWithObjectsAndKeys: 
1831
 
                      destination, @"ToPath",
1832
 
                      @"cannot open file for writing", @"Error",
1833
 
                      nil];
1834
 
          close (sourceFd);
1835
 
          return [handler fileManager: self
1836
 
              shouldProceedAfterError: errorInfo];
1837
 
        }
1838
 
      else
1839
 
        {
1840
 
          return NO;
1841
 
        }
 
2696
      close (sourceFd);
 
2697
 
 
2698
      return [self _proceedAccordingToHandler: handler
 
2699
                                     forError:  @"cannot open file for writing"
 
2700
                                       inPath: destination
 
2701
                                     fromPath: source
 
2702
                                       toPath: destination];
1842
2703
    }
1843
2704
 
1844
2705
  /* Read bufsize bytes from source file and write them into the destination
1848
2709
      rbytes = read (sourceFd, buffer, bufsize);
1849
2710
      if (rbytes < 0)
1850
2711
        {
1851
 
          if (handler != nil)
1852
 
            {
1853
 
              NSDictionary      *errorInfo
1854
 
                = [NSDictionary dictionaryWithObjectsAndKeys: 
1855
 
                          source, @"Path",
1856
 
                          @"cannot read from file", @"Error",
1857
 
                          nil];
1858
 
              close (sourceFd);
1859
 
              close (destFd);
1860
 
              return [handler fileManager: self
1861
 
                  shouldProceedAfterError: errorInfo];
1862
 
            }
1863
 
          else
1864
 
            {
1865
 
              return NO;
1866
 
            }
 
2712
          close (sourceFd);
 
2713
          close (destFd);
 
2714
 
 
2715
          return [self _proceedAccordingToHandler: handler
 
2716
                                         forError: @"cannot read from file"
 
2717
                                           inPath: source
 
2718
                                         fromPath: source
 
2719
                                           toPath: destination];
1867
2720
        }
1868
2721
 
1869
2722
      wbytes = write (destFd, buffer, rbytes);
1870
2723
      if (wbytes != rbytes)
1871
2724
        {
1872
 
          if (handler != nil)
1873
 
            {
1874
 
              NSDictionary      *errorInfo
1875
 
                = [NSDictionary dictionaryWithObjectsAndKeys: 
1876
 
                          source, @"Path",
1877
 
                          destination, @"ToPath",
1878
 
                          @"cannot write to file", @"Error",
1879
 
                          nil];
1880
 
              close (sourceFd);
1881
 
              close (destFd);
1882
 
              return [handler fileManager: self
1883
 
                  shouldProceedAfterError: errorInfo];
1884
 
            }
1885
 
          else
1886
 
            {
1887
 
              return NO;
1888
 
            }
1889
 
        }
 
2725
          close (sourceFd);
 
2726
          close (destFd);
 
2727
 
 
2728
          return [self _proceedAccordingToHandler: handler
 
2729
                                         forError: @"cannot write to file"
 
2730
                                           inPath: destination
 
2731
                                         fromPath: source
 
2732
                                           toPath: destination];
 
2733
        }
1890
2734
    }
1891
2735
  close (sourceFd);
1892
2736
  close (destFd);
1911
2755
      NSString          *destinationFile;
1912
2756
      NSDictionary      *attributes;
1913
2757
 
1914
 
      attributes = [enumerator _attributesForCopy];
1915
 
      fileType = [attributes objectForKey: NSFileType];
 
2758
      attributes = [enumerator fileAttributes];
 
2759
      fileType = [attributes fileType];
1916
2760
      sourceFile = [source stringByAppendingPathComponent: dirEntry];
1917
2761
      destinationFile
1918
2762
        = [destination stringByAppendingPathComponent: dirEntry];
1919
2763
 
1920
 
      [handler fileManager: self willProcessPath: sourceFile];
 
2764
      [self _sendToHandler: handler willProcessPath: sourceFile];
 
2765
 
1921
2766
      if ([fileType isEqual: NSFileTypeDirectory])
1922
2767
        {
1923
2768
          if (![self createDirectoryAtPath: destinationFile
1924
2769
                                attributes: attributes])
1925
2770
            {
1926
 
              if (handler)
1927
 
                {
1928
 
                  NSDictionary  *errorInfo;
1929
 
 
1930
 
                  errorInfo = [NSDictionary dictionaryWithObjectsAndKeys: 
1931
 
                    destinationFile, @"Path",
1932
 
                    _lastError, @"Error", nil];
1933
 
                  if (![handler fileManager: self
1934
 
                    shouldProceedAfterError: errorInfo])
1935
 
                    return NO;
1936
 
                }
1937
 
              else
1938
 
                return NO;
 
2771
              if (![self _proceedAccordingToHandler: handler
 
2772
                                           forError: _lastError
 
2773
                                             inPath: destinationFile
 
2774
                                           fromPath: sourceFile
 
2775
                                             toPath: destinationFile])
 
2776
                {
 
2777
                  return NO;
 
2778
                }
1939
2779
            }
1940
2780
          else
1941
2781
            {
1942
2782
              [enumerator skipDescendents];
1943
2783
              if (![self _copyPath: sourceFile
1944
 
                            toPath: destinationFile
1945
 
                           handler: handler])
 
2784
                         toPath: destinationFile
 
2785
                         handler: handler])
1946
2786
                return NO;
1947
2787
            }
1948
2788
        }
1961
2801
          if (![self createSymbolicLinkAtPath: destinationFile
1962
2802
                                  pathContent: path])
1963
2803
            {
1964
 
              if (handler)
1965
 
                {
1966
 
                  NSDictionary  *errorInfo
1967
 
                    = [NSDictionary dictionaryWithObjectsAndKeys: 
1968
 
                              sourceFile, @"Path",
1969
 
                              destinationFile, @"ToPath",
1970
 
                              @"cannot create symbolic link", @"Error",
1971
 
                              nil];
1972
 
                  if (![handler fileManager: self
1973
 
                    shouldProceedAfterError: errorInfo])
1974
 
                    {
1975
 
                      return NO;
1976
 
                    }
1977
 
                }
1978
 
              else
1979
 
                {
1980
 
                  return NO;
1981
 
                }
 
2804
              if (![self _proceedAccordingToHandler: handler
 
2805
                forError: @"cannot create symbolic link"
 
2806
                inPath: sourceFile
 
2807
                fromPath: sourceFile
 
2808
                toPath: destinationFile])
 
2809
                {
 
2810
                  return NO;
 
2811
                }
1982
2812
            }
1983
2813
        }
1984
2814
      else
1998
2828
  return YES;
1999
2829
}
2000
2830
 
2001
 
#if (defined(sparc) && defined(DEBUG))
2002
 
static int sparc_warn = 0;
 
2831
- (BOOL) _linkPath: (NSString*)source
 
2832
            toPath: (NSString*)destination
 
2833
           handler: handler
 
2834
{
 
2835
#ifdef HAVE_LINK
 
2836
  NSDirectoryEnumerator *enumerator;
 
2837
  NSString              *dirEntry;
 
2838
  CREATE_AUTORELEASE_POOL(pool);
 
2839
 
 
2840
  enumerator = [self enumeratorAtPath: source];
 
2841
  while ((dirEntry = [enumerator nextObject]))
 
2842
    {
 
2843
      NSString          *sourceFile;
 
2844
      NSString          *fileType;
 
2845
      NSString          *destinationFile;
 
2846
      NSDictionary      *attributes;
 
2847
 
 
2848
      attributes = [enumerator fileAttributes];
 
2849
      fileType = [attributes fileType];
 
2850
      sourceFile = [source stringByAppendingPathComponent: dirEntry];
 
2851
      destinationFile
 
2852
        = [destination stringByAppendingPathComponent: dirEntry];
 
2853
 
 
2854
      [self _sendToHandler: handler willProcessPath: sourceFile];
 
2855
 
 
2856
      if ([fileType isEqual: NSFileTypeDirectory] == YES)
 
2857
        {
 
2858
          if ([self createDirectoryAtPath: destinationFile
 
2859
                               attributes: attributes] == NO)
 
2860
            {
 
2861
              if ([self _proceedAccordingToHandler: handler
 
2862
                                          forError: _lastError
 
2863
                                            inPath: destinationFile
 
2864
                                          fromPath: sourceFile
 
2865
                                            toPath: destinationFile] == NO)
 
2866
                {
 
2867
                  return NO;
 
2868
                }
 
2869
            }
 
2870
          else
 
2871
            {
 
2872
              [enumerator skipDescendents];
 
2873
              if ([self _linkPath: sourceFile
 
2874
                           toPath: destinationFile
 
2875
                          handler: handler] == NO)
 
2876
                {
 
2877
                  return NO;
 
2878
                }
 
2879
            }
 
2880
        }
 
2881
      else if ([fileType isEqual: NSFileTypeSymbolicLink])
 
2882
        {
 
2883
          NSString      *path;
 
2884
 
 
2885
          path = [self pathContentOfSymbolicLinkAtPath: sourceFile];
 
2886
          if ([self createSymbolicLinkAtPath: destinationFile
 
2887
                                 pathContent: path] == NO)
 
2888
            {
 
2889
              if ([self _proceedAccordingToHandler: handler
 
2890
                forError: @"cannot create symbolic link"
 
2891
                inPath: sourceFile
 
2892
                fromPath: sourceFile
 
2893
                toPath: destinationFile] == NO)
 
2894
                {
 
2895
                  return NO;
 
2896
                }
 
2897
            }
 
2898
        }
 
2899
      else
 
2900
        {
 
2901
          if (link([sourceFile fileSystemRepresentation],
 
2902
            [destinationFile fileSystemRepresentation]) < 0)
 
2903
            {
 
2904
              if ([self _proceedAccordingToHandler: handler
 
2905
                forError: @"cannot create hard link"
 
2906
                inPath: sourceFile
 
2907
                fromPath: sourceFile
 
2908
                toPath: destinationFile] == NO)
 
2909
                {
 
2910
                  return NO;
 
2911
                }
 
2912
            }
 
2913
        }
 
2914
      [self changeFileAttributes: attributes atPath: destinationFile];
 
2915
    }
 
2916
  RELEASE(pool);
 
2917
  return YES;
 
2918
#else
 
2919
  return NO;
2003
2920
#endif
2004
 
 
2005
 
- (NSDictionary*) _attributesAtPath: (NSString*)path
2006
 
                       traverseLink: (BOOL)traverse
2007
 
                            forCopy: (BOOL)copy
2008
 
{
2009
 
  struct stat statbuf;
2010
 
  const char* cpath = [self fileSystemRepresentationWithPath: path];
2011
 
  int mode;
2012
 
  int count;
2013
 
  id values[12];
2014
 
  id keys[12] = {
2015
 
    NSFileSize,
2016
 
    NSFileModificationDate,
2017
 
    NSFileReferenceCount,
2018
 
    NSFileSystemNumber,
2019
 
    NSFileSystemFileNumber,
2020
 
    NSFileDeviceIdentifier,
2021
 
    NSFilePosixPermissions,
2022
 
    NSFileType,
2023
 
    NSFileOwnerAccountName,
2024
 
    NSFileGroupOwnerAccountName,
2025
 
    NSFileOwnerAccountNumber,
2026
 
    NSFileGroupOwnerAccountNumber
2027
 
  };
2028
 
 
2029
 
#if defined(__MINGW__)
2030
 
  if (stat(cpath, &statbuf) != 0)
 
2921
}
 
2922
 
 
2923
- (void) _sendToHandler: (id) handler
 
2924
        willProcessPath: (NSString*) path
 
2925
{
 
2926
  if ([handler respondsToSelector: @selector (fileManager:willProcessPath:)])
 
2927
    {
 
2928
      [handler fileManager: self willProcessPath: path];
 
2929
    }
 
2930
}
 
2931
 
 
2932
- (BOOL) _proceedAccordingToHandler: (id) handler
 
2933
                           forError: (NSString*) error
 
2934
                             inPath: (NSString*) path
 
2935
{
 
2936
  if ([handler respondsToSelector:
 
2937
    @selector (fileManager:shouldProceedAfterError:)])
 
2938
    {
 
2939
      NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
 
2940
                                                path, @"Path",
 
2941
                                              error, @"Error", nil];
 
2942
      return [handler fileManager: self
 
2943
          shouldProceedAfterError: errorInfo];
 
2944
    }
 
2945
  return NO;
 
2946
}
 
2947
 
 
2948
- (BOOL) _proceedAccordingToHandler: (id) handler
 
2949
                           forError: (NSString*) error
 
2950
                             inPath: (NSString*) path
 
2951
                           fromPath: (NSString*) fromPath
 
2952
                             toPath: (NSString*) toPath
 
2953
{
 
2954
  if ([handler respondsToSelector:
 
2955
    @selector (fileManager:shouldProceedAfterError:)])
 
2956
    {
 
2957
      NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
 
2958
                                                path, @"Path",
 
2959
                                              fromPath, @"FromPath",
 
2960
                                              toPath, @"ToPath",
 
2961
                                              error, @"Error", nil];
 
2962
      return [handler fileManager: self
 
2963
          shouldProceedAfterError: errorInfo];
 
2964
    }
 
2965
  return NO;
 
2966
}
 
2967
 
 
2968
@end /* NSFileManager (PrivateMethods) */
 
2969
 
 
2970
 
 
2971
 
 
2972
@implementation GSAttrDictionary
 
2973
 
 
2974
static NSSet    *fileKeys = nil;
 
2975
 
 
2976
+ (NSDictionary*) attributesAt: (const _CHAR*)lpath
 
2977
                  traverseLink: (BOOL)traverse
 
2978
{
 
2979
  GSAttrDictionary      *d;
 
2980
 
 
2981
  if (lpath == 0 || *lpath == 0)
2031
2982
    {
2032
2983
      return nil;
2033
2984
    }
2034
 
#else /* !(__MINGW__) */
2035
 
  if (traverse)
2036
 
    {
2037
 
      if (stat(cpath, &statbuf) != 0)
2038
 
        {
2039
 
          return nil;
2040
 
        }
2041
 
    }
2042
 
#ifdef S_IFLNK
2043
 
  else
2044
 
    {
2045
 
      if (lstat(cpath, &statbuf) != 0)
2046
 
        {
2047
 
          return nil;
2048
 
        }
2049
 
    }
2050
 
#endif /* (S_IFLNK) */
2051
 
#endif /* (__MINGW__) */
2052
 
    
2053
 
  values[0] = [NSNumber numberWithUnsignedLongLong: statbuf.st_size];
2054
 
  values[1] = [NSDate dateWithTimeIntervalSince1970: statbuf.st_mtime];
2055
 
  values[2] = [NSNumber numberWithUnsignedInt: statbuf.st_nlink];
2056
 
  values[3] = [NSNumber numberWithUnsignedLong: statbuf.st_dev];
2057
 
  values[4] = [NSNumber numberWithUnsignedLong: statbuf.st_ino];
2058
 
  values[5] = [NSNumber numberWithUnsignedInt: statbuf.st_dev];
2059
 
  values[6] = [NSNumber numberWithUnsignedInt: statbuf.st_mode];
2060
 
  
2061
 
  mode = statbuf.st_mode & S_IFMT;
2062
 
 
2063
 
  if (mode == S_IFREG)
2064
 
    values[7] = NSFileTypeRegular;
2065
 
  else if (mode == S_IFDIR)
2066
 
    values[7] = NSFileTypeDirectory;
2067
 
  else if (mode == S_IFCHR)
2068
 
    values[7] = NSFileTypeCharacterSpecial;
2069
 
  else if (mode == S_IFBLK)
2070
 
    values[7] = NSFileTypeBlockSpecial;
2071
 
#ifdef S_IFLNK
2072
 
  else if (mode == S_IFLNK)
2073
 
    values[7] = NSFileTypeSymbolicLink;
2074
 
#endif
2075
 
  else if (mode == S_IFIFO)
2076
 
    values[7] = NSFileTypeFifo;
 
2985
  d = (GSAttrDictionary*)NSAllocateObject(self, 0, NSDefaultMallocZone());
 
2986
 
 
2987
#if defined(S_IFLNK) && !defined(__MINGW__)
 
2988
  if (traverse == NO)
 
2989
    {
 
2990
      if (lstat(lpath, &d->statbuf) != 0)
 
2991
        {
 
2992
          DESTROY(d);
 
2993
        }
 
2994
    }
 
2995
  else
 
2996
#endif
 
2997
  if (_STAT(lpath, &d->statbuf) != 0)
 
2998
    {
 
2999
      DESTROY(d);
 
3000
    }
 
3001
  return AUTORELEASE(d);
 
3002
}
 
3003
 
 
3004
+ (void) initialize
 
3005
{
 
3006
  if (fileKeys == nil)
 
3007
    {
 
3008
      fileKeys = [NSSet setWithObjects:
 
3009
        NSFileAppendOnly,
 
3010
        NSFileCreationDate,
 
3011
        NSFileDeviceIdentifier,
 
3012
        NSFileExtensionHidden,
 
3013
        NSFileGroupOwnerAccountName,
 
3014
        NSFileGroupOwnerAccountID,
 
3015
        NSFileHFSCreatorCode,
 
3016
        NSFileHFSTypeCode,
 
3017
        NSFileImmutable,
 
3018
        NSFileModificationDate,
 
3019
        NSFileOwnerAccountName,
 
3020
        NSFileOwnerAccountID,
 
3021
        NSFilePosixPermissions,
 
3022
        NSFileReferenceCount,
 
3023
        NSFileSize,
 
3024
        NSFileSystemFileNumber,
 
3025
        NSFileSystemNumber,
 
3026
        NSFileType,
 
3027
        nil];
 
3028
      RETAIN(fileKeys);
 
3029
    }
 
3030
}
 
3031
 
 
3032
- (unsigned int) count
 
3033
{
 
3034
  return [fileKeys count];
 
3035
}
 
3036
 
 
3037
- (NSDate*) fileCreationDate
 
3038
{
 
3039
  /*
 
3040
   * FIXME ... not sure there is any way to get a creation date :-(
 
3041
   * Use the earlier of ctime or mtime
 
3042
   */
 
3043
  if (statbuf.st_ctime < statbuf.st_mtime)
 
3044
    return [NSDate dateWithTimeIntervalSince1970: statbuf.st_ctime];
 
3045
  else
 
3046
    return [NSDate dateWithTimeIntervalSince1970: statbuf.st_mtime];
 
3047
}
 
3048
 
 
3049
- (BOOL) fileExtensionHidden
 
3050
{
 
3051
  return NO;
 
3052
}
 
3053
 
 
3054
- (unsigned long) fileGroupOwnerAccountID
 
3055
{
 
3056
  return statbuf.st_gid;
 
3057
}
 
3058
 
 
3059
- (NSString*) fileGroupOwnerAccountName
 
3060
{
 
3061
  NSString      *result = @"UnknownGroup";
 
3062
#if defined(HAVE_GRP_H)
 
3063
  struct group  *gp;
 
3064
 
 
3065
  gp = getgrgid(statbuf.st_gid);
 
3066
  if (gp != 0)
 
3067
    {
 
3068
      result = [NSString stringWithCString: gp->gr_name];
 
3069
    }
 
3070
#endif
 
3071
  return result;
 
3072
}
 
3073
 
 
3074
- (int) fileHFSCreatorCode
 
3075
{
 
3076
  return 0;
 
3077
}
 
3078
 
 
3079
- (int) fileHFSTypeCode
 
3080
{
 
3081
  return 0;
 
3082
}
 
3083
 
 
3084
- (BOOL) fileIsAppendOnly
 
3085
{
 
3086
  return 0;
 
3087
}
 
3088
 
 
3089
- (BOOL) fileIsImmutable
 
3090
{
 
3091
  return 0;
 
3092
}
 
3093
 
 
3094
- (NSDate*) fileModificationDate
 
3095
{
 
3096
  return [NSDate dateWithTimeIntervalSince1970: statbuf.st_mtime];
 
3097
}
 
3098
 
 
3099
- (unsigned long) filePosixPermissions
 
3100
{
 
3101
  return (statbuf.st_mode & ~S_IFMT);
 
3102
}
 
3103
 
 
3104
- (unsigned long) fileOwnerAccountID
 
3105
{
 
3106
  return statbuf.st_uid;
 
3107
}
 
3108
 
 
3109
- (NSString*) fileOwnerAccountName
 
3110
{
 
3111
  NSString      *result = @"UnknownUser";
 
3112
#ifdef __MINGW_NOT_AVAILABLE_YET
 
3113
{
 
3114
  DWORD         dwRtnCode = 0;
 
3115
  PSID          pSidOwner;
 
3116
  BOOL          bRtnBool = TRUE;
 
3117
  LPTSTR        AcctName;
 
3118
  LPTSTR        DomainName;
 
3119
  DWORD         dwAcctName = 1;
 
3120
  DWORD         dwDomainName = 1;
 
3121
  SID_NAME_USE  eUse = SidTypeUnknown;
 
3122
  HANDLE        hFile;
 
3123
  PSECURITY_DESCRIPTOR pSD;
 
3124
 
 
3125
  // Get the handle of the file object.
 
3126
  hFile = CreateFile(
 
3127
    "myfile.txt",
 
3128
    GENERIC_READ,
 
3129
    FILE_SHARE_READ,
 
3130
    0,
 
3131
    OPEN_EXISTING,
 
3132
    FILE_ATTRIBUTE_NORMAL,
 
3133
    0);
 
3134
 
 
3135
  // Check GetLastError for CreateFile error code.
 
3136
  if (hFile == INVALID_HANDLE_VALUE)
 
3137
    {
 
3138
      DWORD dwErrorCode = 0;
 
3139
 
 
3140
      dwErrorCode = GetLastError();
 
3141
      _tprintf(TEXT("CreateFile error = %d\n"), dwErrorCode);
 
3142
      return -1;
 
3143
    }
 
3144
 
 
3145
  // Allocate memory for the SID structure.
 
3146
  pSidOwner = (PSID)GlobalAlloc(
 
3147
    GMEM_FIXED,
 
3148
    sizeof(PSID));
 
3149
 
 
3150
  // Allocate memory for the security descriptor structure.
 
3151
  pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(
 
3152
    GMEM_FIXED,
 
3153
    sizeof(PSECURITY_DESCRIPTOR));
 
3154
 
 
3155
  // Get the owner SID of the file.
 
3156
  dwRtnCode = GetSecurityInfo(
 
3157
    hFile,
 
3158
    SE_FILE_OBJECT,
 
3159
    OWNER_SECURITY_INFORMATION,
 
3160
    &pSidOwner,
 
3161
    0,
 
3162
    0,
 
3163
    0,
 
3164
    &pSD);
 
3165
 
 
3166
  // Check GetLastError for GetSecurityInfo error condition.
 
3167
  if (dwRtnCode != ERROR_SUCCESS)
 
3168
    {
 
3169
      DWORD dwErrorCode = 0;
 
3170
 
 
3171
      dwErrorCode = GetLastError();
 
3172
      _tprintf(TEXT("GetSecurityInfo error = %d\n"), dwErrorCode);
 
3173
      return -1;
 
3174
    }
 
3175
 
 
3176
  // First call to LookupAccountSid to get the buffer sizes.
 
3177
  bRtnBool = LookupAccountSid(
 
3178
    0,           // local computer
 
3179
    pSidOwner,
 
3180
    AcctName,
 
3181
    (LPDWORD)&dwAcctName,
 
3182
    DomainName,
 
3183
    (LPDWORD)&dwDomainName,
 
3184
    &eUse);
 
3185
 
 
3186
  // Reallocate memory for the buffers.
 
3187
  AcctName = (char *)GlobalAlloc(
 
3188
    GMEM_FIXED,
 
3189
    dwAcctName);
 
3190
 
 
3191
  // Check GetLastError for GlobalAlloc error condition.
 
3192
  if (AcctName == 0)
 
3193
    {
 
3194
      DWORD dwErrorCode = 0;
 
3195
 
 
3196
      dwErrorCode = GetLastError();
 
3197
      _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
 
3198
      return -1;
 
3199
    }
 
3200
 
 
3201
  DomainName = (char *)GlobalAlloc(
 
3202
    GMEM_FIXED,
 
3203
    dwDomainName);
 
3204
 
 
3205
  // Check GetLastError for GlobalAlloc error condition.
 
3206
  if (DomainName == 0)
 
3207
    {
 
3208
      DWORD dwErrorCode = 0;
 
3209
 
 
3210
      dwErrorCode = GetLastError();
 
3211
      _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
 
3212
      return -1;
 
3213
    }
 
3214
 
 
3215
  // Second call to LookupAccountSid to get the account name.
 
3216
  bRtnBool = LookupAccountSid(
 
3217
    0,                          // name of local or remote computer
 
3218
    pSidOwner,                     // security identifier
 
3219
    AcctName,                      // account name buffer
 
3220
    (LPDWORD)&dwAcctName,          // size of account name buffer
 
3221
    DomainName,                    // domain name
 
3222
    (LPDWORD)&dwDomainName,        // size of domain name buffer
 
3223
    &eUse);                        // SID type
 
3224
 
 
3225
  // Check GetLastError for LookupAccountSid error condition.
 
3226
  if (bRtnBool == FALSE)
 
3227
    {
 
3228
      DWORD dwErrorCode = 0;
 
3229
 
 
3230
      dwErrorCode = GetLastError();
 
3231
 
 
3232
      if (dwErrorCode == ERROR_NONE_MAPPED)
 
3233
        _tprintf(TEXT("Account owner not found for specified SID.\n"));
 
3234
      else
 
3235
        _tprintf(TEXT("Error in LookupAccountSid.\n"));
 
3236
      return -1;
 
3237
    }
 
3238
  else if (bRtnBool == TRUE)
 
3239
    {
 
3240
      // Print the account name.
 
3241
      _tprintf(TEXT("Account owner = %s\n"), AcctName);
 
3242
    }
 
3243
  return 0;
 
3244
}
 
3245
 
 
3246
#endif
 
3247
#ifdef HAVE_PWD_H
 
3248
  struct passwd *pw;
 
3249
 
 
3250
  pw = getpwuid(statbuf.st_uid);
 
3251
 
 
3252
  if (pw != 0)
 
3253
    {
 
3254
      result = [NSString stringWithCString: pw->pw_name];
 
3255
    }
 
3256
#endif /* HAVE_PWD_H */
 
3257
  return result;
 
3258
}
 
3259
 
 
3260
- (unsigned long long) fileSize
 
3261
{
 
3262
  return statbuf.st_size;
 
3263
}
 
3264
 
 
3265
- (unsigned long) fileSystemFileNumber
 
3266
{
 
3267
  return statbuf.st_ino;
 
3268
}
 
3269
 
 
3270
- (unsigned long) fileSystemNumber
 
3271
{
 
3272
  return statbuf.st_dev;
 
3273
}
 
3274
 
 
3275
- (NSString*) fileType
 
3276
{
 
3277
  switch (statbuf.st_mode & S_IFMT)
 
3278
    {
 
3279
      case S_IFREG: return NSFileTypeRegular;
 
3280
      case S_IFDIR: return NSFileTypeDirectory;
 
3281
      case S_IFCHR: return NSFileTypeCharacterSpecial;
 
3282
      case S_IFBLK: return NSFileTypeBlockSpecial;
 
3283
#ifdef S_IFLNK
 
3284
      case S_IFLNK: return NSFileTypeSymbolicLink;
 
3285
#endif
 
3286
      case S_IFIFO: return NSFileTypeFifo;
2077
3287
#ifdef S_IFSOCK
2078
 
  else if (mode == S_IFSOCK)
2079
 
    values[7] = NSFileTypeSocket;
2080
 
#endif
2081
 
  else
2082
 
    values[7] = NSFileTypeUnknown;
2083
 
 
2084
 
  if (copy == NO)
2085
 
    {
2086
 
#if HAVE_PWD_H  
2087
 
      {
2088
 
        struct passwd *pw;
2089
 
 
2090
 
        pw = getpwuid(statbuf.st_uid);
2091
 
 
2092
 
        if (pw)
2093
 
          {
2094
 
            values[8] = [NSString stringWithCString: pw->pw_name];
2095
 
          }
2096
 
        else
2097
 
          {
2098
 
            values[8] = @"UnknownUser";
2099
 
          }
2100
 
      }
2101
 
#else
2102
 
      values[8] = @"UnknownUser";
2103
 
#endif /* HAVE_PWD_H */
2104
 
 
2105
 
#if defined(HAVE_GRP_H) && !(defined(sparc) && defined(DEBUG))
2106
 
      {
2107
 
        struct group *gp;
2108
 
 
2109
 
        setgrent();
2110
 
        while ((gp = getgrent()) != 0)
2111
 
          {
2112
 
            if (gp->gr_gid == statbuf.st_gid)
2113
 
              {
2114
 
                break;
2115
 
              }
2116
 
          }
2117
 
        if (gp)
2118
 
          {
2119
 
            values[9] = [NSString stringWithCString: gp->gr_name];
2120
 
          }
2121
 
        else
2122
 
          {
2123
 
            values[9] = @"UnknownGroup";
2124
 
          }
2125
 
        endgrent();
2126
 
      }
2127
 
#else
2128
 
#if (defined(sparc) && defined(DEBUG))
2129
 
      if (sparc_warn == 0)
2130
 
        {
2131
 
          sparc_warn = 1;
2132
 
          /* Can't be NSLog - causes recursion in [NSUser -synchronize] */
2133
 
          fprintf(stderr, "WARNING (NSFileManager): Disabling group enums (setgrent, etc) since this crashes gdb on sparc machines\n");
2134
 
        }
2135
 
#endif
2136
 
      values[9] = @"UnknownGroup";
2137
 
#endif
2138
 
      values[10] = [NSNumber numberWithUnsignedInt: statbuf.st_uid];
2139
 
      values[11] = [NSNumber numberWithUnsignedInt: statbuf.st_gid];
2140
 
      count = 12;
 
3288
      case S_IFSOCK: return NSFileTypeSocket;
 
3289
#endif
 
3290
      default: return NSFileTypeUnknown;
2141
3291
    }
2142
 
  else
 
3292
}
 
3293
 
 
3294
- (NSEnumerator*) keyEnumerator
 
3295
{
 
3296
  return [fileKeys objectEnumerator];
 
3297
}
 
3298
 
 
3299
- (NSEnumerator*) objectEnumerator
 
3300
{
 
3301
  return [GSAttrDictionaryEnumerator enumeratorFor: self];
 
3302
}
 
3303
 
 
3304
- (id) objectForKey: (NSString*)key
 
3305
{
 
3306
  int   count = 0;
 
3307
 
 
3308
  while (key != 0 && count < 2)
2143
3309
    {
2144
 
      NSString  *u = NSUserName();
 
3310
      if (key == NSFileAppendOnly)
 
3311
        return [NSNumber numberWithBool: [self fileIsAppendOnly]];
 
3312
      if (key == NSFileCreationDate)
 
3313
        return [self fileCreationDate];
 
3314
      if (key == NSFileDeviceIdentifier)
 
3315
        return [NSNumber numberWithUnsignedInt: statbuf.st_dev];
 
3316
      if (key == NSFileExtensionHidden)
 
3317
        return [NSNumber numberWithBool: [self fileExtensionHidden]];
 
3318
      if (key == NSFileGroupOwnerAccountName)
 
3319
        return [self fileGroupOwnerAccountName];
 
3320
      if (key == NSFileGroupOwnerAccountID)
 
3321
        return [NSNumber numberWithInt: [self fileGroupOwnerAccountID]];
 
3322
      if (key == NSFileHFSCreatorCode)
 
3323
        return [NSNumber numberWithInt: [self fileHFSCreatorCode]];
 
3324
      if (key == NSFileHFSTypeCode)
 
3325
        return [NSNumber numberWithInt: [self fileHFSTypeCode]];
 
3326
      if (key == NSFileImmutable)
 
3327
        return [NSNumber numberWithBool: [self fileIsImmutable]];
 
3328
      if (key == NSFileModificationDate)
 
3329
        return [self fileModificationDate];
 
3330
      if (key == NSFileOwnerAccountName)
 
3331
        return [self fileOwnerAccountName];
 
3332
      if (key == NSFileOwnerAccountID)
 
3333
        return [NSNumber numberWithInt: [self fileOwnerAccountID]];
 
3334
      if (key == NSFilePosixPermissions)
 
3335
        return [NSNumber numberWithUnsignedInt: [self filePosixPermissions]];
 
3336
      if (key == NSFileReferenceCount)
 
3337
        return [NSNumber numberWithUnsignedInt: statbuf.st_nlink];
 
3338
      if (key == NSFileSize)
 
3339
        return [NSNumber numberWithUnsignedLongLong: [self fileSize]];
 
3340
      if (key == NSFileSystemFileNumber)
 
3341
        return [NSNumber numberWithUnsignedInt: [self fileSystemFileNumber]];
 
3342
      if (key == NSFileSystemNumber)
 
3343
        return [NSNumber numberWithUnsignedInt: [self fileSystemNumber]];
 
3344
      if (key == NSFileType)
 
3345
        return [self fileType];
2145
3346
 
2146
 
      count = 8;        /* No ownership details needed. */
2147
3347
      /*
2148
 
       * If we are running setuid to root - we need to specify the user
2149
 
       * to be the owner of copied files.
 
3348
       * Now, if we didn't get an exact pointer match, check for
 
3349
       * string equalities and ensure we get an exact match next
 
3350
       * time round the loop.
2150
3351
       */
2151
 
#if HAVE_GETEUID
2152
 
      if (geteuid() == 0 && [@"root" isEqualToString: u] == NO)
2153
 
        {
2154
 
          values[count++] = u;
2155
 
        }
2156
 
#endif
2157
 
    }
2158
 
 
2159
 
  return [NSDictionary dictionaryWithObjects: values
2160
 
                                     forKeys: keys
2161
 
                                       count: count];
2162
 
}
2163
 
 
2164
 
@end /* NSFileManager (PrivateMethods) */
 
3352
      count++;
 
3353
      key = [fileKeys member: key];
 
3354
    }
 
3355
  if (count >= 2)
 
3356
    {
 
3357
      NSLog(@"Warning ... key '%@' not handled", key);
 
3358
    }
 
3359
  return nil;
 
3360
}
 
3361
 
 
3362
@end    /* GSAttrDictionary */
 
3363
 
 
3364
@implementation GSAttrDictionaryEnumerator
 
3365
+ (NSEnumerator*) enumeratorFor: (NSDictionary*)d
 
3366
{
 
3367
  GSAttrDictionaryEnumerator    *e;
 
3368
 
 
3369
  e = (GSAttrDictionaryEnumerator*)
 
3370
    NSAllocateObject(self, 0, NSDefaultMallocZone());
 
3371
  e->dictionary = RETAIN(d);
 
3372
  e->enumerator = RETAIN([fileKeys objectEnumerator]);
 
3373
  return AUTORELEASE(e);
 
3374
}
 
3375
 
 
3376
- (void) dealloc
 
3377
{
 
3378
  RELEASE(enumerator);
 
3379
  RELEASE(dictionary);
 
3380
  [super dealloc];
 
3381
}
 
3382
 
 
3383
- (id) nextObject
 
3384
{
 
3385
  NSString      *key = [enumerator nextObject];
 
3386
  id            val = nil;
 
3387
 
 
3388
  if (key != nil)
 
3389
    {
 
3390
      val = [dictionary objectForKey: key];
 
3391
    }
 
3392
  return val;
 
3393
}
 
3394
@end
 
3395
 
 
3396
NSString * const NSFileAppendOnly = @"NSFileAppendOnly";
 
3397
NSString * const NSFileCreationDate = @"NSFileCreationDate";
 
3398
NSString * const NSFileDeviceIdentifier = @"NSFileDeviceIdentifier";
 
3399
NSString * const NSFileExtensionHidden = @"NSFileExtensionHidden";
 
3400
NSString * const NSFileGroupOwnerAccountID = @"NSFileGroupOwnerAccountID";
 
3401
NSString * const NSFileGroupOwnerAccountName = @"NSFileGroupOwnerAccountName";
 
3402
NSString * const NSFileHFSCreatorCode = @"NSFileHFSCreatorCode";
 
3403
NSString * const NSFileHFSTypeCode = @"NSFileHFSTypeCode";
 
3404
NSString * const NSFileImmutable = @"NSFileImmutable";
 
3405
NSString * const NSFileModificationDate = @"NSFileModificationDate";
 
3406
NSString * const NSFileOwnerAccountID = @"NSFileOwnerAccountID";
 
3407
NSString * const NSFileOwnerAccountName = @"NSFileOwnerAccountName";
 
3408
NSString * const NSFilePosixPermissions = @"NSFilePosixPermissions";
 
3409
NSString * const NSFileReferenceCount = @"NSFileReferenceCount";
 
3410
NSString * const NSFileSize = @"NSFileSize";
 
3411
NSString * const NSFileSystemFileNumber = @"NSFileSystemFileNumber";
 
3412
NSString * const NSFileSystemFreeNodes = @"NSFileSystemFreeNodes";
 
3413
NSString * const NSFileSystemFreeSize = @"NSFileSystemFreeSize";
 
3414
NSString * const NSFileSystemNodes = @"NSFileSystemNodes";
 
3415
NSString * const NSFileSystemNumber = @"NSFileSystemNumber";
 
3416
NSString * const NSFileSystemSize = @"NSFileSystemSize";
 
3417
NSString * const NSFileType = @"NSFileType";
 
3418
NSString * const NSFileTypeBlockSpecial = @"NSFileTypeBlockSpecial";
 
3419
NSString * const NSFileTypeCharacterSpecial = @"NSFileTypeCharacterSpecial";
 
3420
NSString * const NSFileTypeDirectory = @"NSFileTypeDirectory";
 
3421
NSString * const NSFileTypeFifo = @"NSFileTypeFifo";
 
3422
NSString * const NSFileTypeRegular = @"NSFileTypeRegular";
 
3423
NSString * const NSFileTypeSocket = @"NSFileTypeSocket";
 
3424
NSString * const NSFileTypeSymbolicLink = @"NSFileTypeSymbolicLink";
 
3425
NSString * const NSFileTypeUnknown = @"NSFileTypeUnknown";
 
3426
 
 
3427