~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2001, 2002
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *  Conrad Carlen <ccarlen@netscape.com>
 
24
 *  Jungshik Shin <jshin@mailaps.org>
 
25
 *  Asaf Romano <mozilla.mano@sent.com>
 
26
 *  Mark Mentovai <mark@moxienet.com>
 
27
 *
 
28
 * Alternatively, the contents of this file may be used under the terms of
 
29
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
30
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
31
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
32
 * of those above. If you wish to allow use of your version of this file only
 
33
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
34
 * use your version of this file under the terms of the MPL, indicate your
 
35
 * decision by deleting the provisions above and replace them with the notice
 
36
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
37
 * the provisions above, a recipient may use your version of this file under
 
38
 * the terms of any one of the MPL, the GPL or the LGPL.
 
39
 *
 
40
 * ***** END LICENSE BLOCK ***** */
 
41
 
 
42
#include "nsLocalFile.h"
 
43
#include "nsDirectoryServiceDefs.h"
 
44
 
 
45
#include "nsString.h"
 
46
#include "nsReadableUtils.h"
 
47
#include "nsIDirectoryEnumerator.h"
 
48
#include "nsISimpleEnumerator.h"
 
49
#include "nsITimelineService.h"
 
50
#include "nsVoidArray.h"
 
51
 
 
52
#include "plbase64.h"
 
53
#include "prmem.h"
 
54
#include "nsCRT.h"
 
55
#include "nsHashKeys.h"
 
56
 
 
57
#include "MoreFilesX.h"
 
58
#include "FSCopyObject.h"
 
59
#include "nsAutoBuffer.h"
 
60
#include "nsTraceRefcntImpl.h"
 
61
 
 
62
// Mac Includes
 
63
#include <Carbon/Carbon.h>
 
64
 
 
65
// Unix Includes
 
66
#include <unistd.h>
 
67
#include <sys/stat.h>
 
68
#include <stdlib.h>
 
69
 
 
70
#if !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
 
71
#define GetAliasSizeFromRecord(aliasRecord) aliasRecord.aliasSize
 
72
#else
 
73
#define GetAliasSizeFromRecord(aliasRecord) GetAliasSizeFromPtr(&aliasRecord)
 
74
#endif
 
75
 
 
76
#define CHECK_mBaseRef()                        \
 
77
    PR_BEGIN_MACRO                              \
 
78
        if (!mBaseRef)                          \
 
79
            return NS_ERROR_NOT_INITIALIZED;    \
 
80
    PR_END_MACRO
 
81
 
 
82
//*****************************************************************************
 
83
//  Static Function Prototypes
 
84
//*****************************************************************************
 
85
 
 
86
static nsresult MacErrorMapper(OSErr inErr);
 
87
static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn);
 
88
static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult);
 
89
 
 
90
//*****************************************************************************
 
91
//  Local Helper Classes
 
92
//*****************************************************************************
 
93
 
 
94
#pragma mark -
 
95
#pragma mark [FSRef operator==]
 
96
 
 
97
bool operator==(const FSRef& lhs, const FSRef& rhs)
 
98
{
 
99
  return (::FSCompareFSRefs(&lhs, &rhs) == noErr);
 
100
}
 
101
 
 
102
#pragma mark -
 
103
#pragma mark [StFollowLinksState]
 
104
 
 
105
class StFollowLinksState
 
106
{
 
107
  public:
 
108
    StFollowLinksState(nsLocalFile& aFile) :
 
109
        mFile(aFile)
 
110
    {
 
111
        mFile.GetFollowLinks(&mSavedState);
 
112
    }
 
113
 
 
114
    StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) :
 
115
        mFile(aFile)
 
116
    {
 
117
        mFile.GetFollowLinks(&mSavedState);
 
118
        mFile.SetFollowLinks(followLinksState);
 
119
    }
 
120
 
 
121
    ~StFollowLinksState()
 
122
    {
 
123
        mFile.SetFollowLinks(mSavedState);
 
124
    }
 
125
 
 
126
  private:
 
127
    nsLocalFile& mFile;
 
128
    PRBool mSavedState;
 
129
};
 
130
 
 
131
#pragma mark -
 
132
#pragma mark [nsDirEnumerator]
 
133
 
 
134
class nsDirEnumerator : public nsISimpleEnumerator,
 
135
                        public nsIDirectoryEnumerator
 
136
{
 
137
    public:
 
138
 
 
139
        NS_DECL_ISUPPORTS
 
140
 
 
141
        nsDirEnumerator() :
 
142
          mIterator(nsnull),
 
143
          mFSRefsArray(nsnull),
 
144
          mArrayCnt(0), mArrayIndex(0)
 
145
        {
 
146
        }
 
147
 
 
148
        nsresult Init(nsILocalFileMac* parent)
 
149
        {
 
150
          NS_ENSURE_ARG(parent);
 
151
 
 
152
          OSErr err;
 
153
          nsresult rv;
 
154
          FSRef parentRef;
 
155
 
 
156
          rv = parent->GetFSRef(&parentRef);
 
157
          if (NS_FAILED(rv))
 
158
            return rv;
 
159
 
 
160
          mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef)
 
161
                                                  * kRequestCountPerIteration);
 
162
          if (!mFSRefsArray)
 
163
            return NS_ERROR_OUT_OF_MEMORY;
 
164
 
 
165
          err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator);
 
166
          if (err != noErr)
 
167
            return MacErrorMapper(err);
 
168
 
 
169
          return NS_OK;
 
170
        }
 
171
 
 
172
        NS_IMETHOD HasMoreElements(PRBool *result)
 
173
        {
 
174
          if (mNext == nsnull) {
 
175
            if (mArrayIndex >= mArrayCnt) {
 
176
              ItemCount actualCnt;
 
177
              OSErr err = ::FSGetCatalogInfoBulk(mIterator,
 
178
                                           kRequestCountPerIteration,
 
179
                                           &actualCnt,
 
180
                                           nsnull,
 
181
                                           kFSCatInfoNone,
 
182
                                           nsnull,
 
183
                                           mFSRefsArray,
 
184
                                           nsnull,
 
185
                                           nsnull);
 
186
 
 
187
              if (err == noErr || err == errFSNoMoreItems) {
 
188
                mArrayCnt = actualCnt;
 
189
                mArrayIndex = 0;
 
190
              }
 
191
            }
 
192
            if (mArrayIndex < mArrayCnt) {
 
193
              nsLocalFile *newFile = new nsLocalFile;
 
194
              if (!newFile)
 
195
                return NS_ERROR_OUT_OF_MEMORY;
 
196
              FSRef fsRef = mFSRefsArray[mArrayIndex];
 
197
              if (NS_FAILED(newFile->InitWithFSRef(&fsRef)))
 
198
                return NS_ERROR_FAILURE;
 
199
              mArrayIndex++;
 
200
              mNext = newFile;
 
201
            }
 
202
          }
 
203
          *result = mNext != nsnull;
 
204
          if (!*result)
 
205
            Close();
 
206
          return NS_OK;
 
207
        }
 
208
 
 
209
        NS_IMETHOD GetNext(nsISupports **result)
 
210
        {
 
211
            NS_ENSURE_ARG_POINTER(result);
 
212
            *result = nsnull;
 
213
 
 
214
            nsresult rv;
 
215
            PRBool hasMore;
 
216
            rv = HasMoreElements(&hasMore);
 
217
            if (NS_FAILED(rv)) return rv;
 
218
 
 
219
            *result = mNext;        // might return nsnull
 
220
            NS_IF_ADDREF(*result);
 
221
 
 
222
            mNext = nsnull;
 
223
            return NS_OK;
 
224
        }
 
225
 
 
226
        NS_IMETHOD GetNextFile(nsIFile **result)
 
227
        {
 
228
            *result = nsnull;
 
229
            PRBool hasMore = PR_FALSE;
 
230
            nsresult rv = HasMoreElements(&hasMore);
 
231
            if (NS_FAILED(rv) || !hasMore)
 
232
                return rv;
 
233
            *result = mNext;
 
234
            NS_IF_ADDREF(*result);
 
235
            mNext = nsnull;
 
236
            return NS_OK;
 
237
        }
 
238
 
 
239
        NS_IMETHOD Close()
 
240
        {
 
241
          if (mIterator) {
 
242
            ::FSCloseIterator(mIterator);
 
243
            mIterator = nsnull;
 
244
          }
 
245
          if (mFSRefsArray) {
 
246
            nsMemory::Free(mFSRefsArray);
 
247
            mFSRefsArray = nsnull;
 
248
          }
 
249
          return NS_OK;
 
250
        }
 
251
 
 
252
    private:
 
253
        ~nsDirEnumerator()
 
254
        {
 
255
          Close();
 
256
        }
 
257
 
 
258
    protected:
 
259
        // According to Apple doc, request the number of objects
 
260
        // per call that will fit in 4 VM pages.
 
261
        enum {
 
262
          kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef))
 
263
        };
 
264
 
 
265
        nsCOMPtr<nsILocalFileMac>   mNext;
 
266
 
 
267
        FSIterator              mIterator;
 
268
        FSRef                   *mFSRefsArray;
 
269
        PRInt32                 mArrayCnt, mArrayIndex;
 
270
};
 
271
 
 
272
NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator)
 
273
 
 
274
#pragma mark -
 
275
#pragma mark [StAEDesc]
 
276
 
 
277
class StAEDesc: public AEDesc
 
278
{
 
279
public:
 
280
    StAEDesc()
 
281
    {
 
282
      descriptorType = typeNull;
 
283
      dataHandle = nil;
 
284
    }
 
285
 
 
286
    ~StAEDesc()
 
287
    {
 
288
      ::AEDisposeDesc(this);
 
289
    }
 
290
};
 
291
 
 
292
#define FILENAME_BUFFER_SIZE 512
 
293
 
 
294
//*****************************************************************************
 
295
//  nsLocalFile
 
296
//*****************************************************************************
 
297
 
 
298
const char      nsLocalFile::kPathSepChar = '/';
 
299
const PRUnichar nsLocalFile::kPathSepUnichar = '/';
 
300
 
 
301
// The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local
 
302
// The NSPR epoch is Jan. 1, 1970 GMT
 
303
// 2082844800 is the difference in seconds between those dates
 
304
const PRInt64   nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL;
 
305
 
 
306
#pragma mark -
 
307
#pragma mark [CTORs/DTOR]
 
308
 
 
309
nsLocalFile::nsLocalFile() :
 
310
  mBaseRef(nsnull),
 
311
  mTargetRef(nsnull),
 
312
  mCachedFSRefValid(PR_FALSE),
 
313
  mFollowLinks(PR_TRUE),
 
314
  mFollowLinksDirty(PR_TRUE)
 
315
{
 
316
}
 
317
 
 
318
nsLocalFile::nsLocalFile(const nsLocalFile& src) :
 
319
  mBaseRef(src.mBaseRef),
 
320
  mTargetRef(src.mTargetRef),
 
321
  mCachedFSRef(src.mCachedFSRef),
 
322
  mCachedFSRefValid(src.mCachedFSRefValid),
 
323
  mFollowLinks(src.mFollowLinks),
 
324
  mFollowLinksDirty(src.mFollowLinksDirty)
 
325
{
 
326
  // A CFURLRef is immutable so no need to copy, just retain.
 
327
  if (mBaseRef)
 
328
    ::CFRetain(mBaseRef);
 
329
  if (mTargetRef)
 
330
    ::CFRetain(mTargetRef);
 
331
}
 
332
 
 
333
nsLocalFile::~nsLocalFile()
 
334
{
 
335
  if (mBaseRef)
 
336
    ::CFRelease(mBaseRef);
 
337
  if (mTargetRef)
 
338
    ::CFRelease(mTargetRef);
 
339
}
 
340
 
 
341
 
 
342
//*****************************************************************************
 
343
//  nsLocalFile::nsISupports
 
344
//*****************************************************************************
 
345
#pragma mark -
 
346
#pragma mark [nsISupports]
 
347
 
 
348
NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
 
349
                              nsILocalFileMac,
 
350
                              nsILocalFile,
 
351
                              nsIFile,
 
352
                              nsIHashable)
 
353
 
 
354
NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
 
355
{
 
356
  NS_ENSURE_ARG_POINTER(aInstancePtr);
 
357
  NS_ENSURE_NO_AGGREGATION(outer);
 
358
 
 
359
  nsLocalFile* inst = new nsLocalFile();
 
360
  if (inst == NULL)
 
361
    return NS_ERROR_OUT_OF_MEMORY;
 
362
 
 
363
  nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
 
364
  if (NS_FAILED(rv))
 
365
  {
 
366
    delete inst;
 
367
    return rv;
 
368
  }
 
369
  return NS_OK;
 
370
}
 
371
 
 
372
 
 
373
//*****************************************************************************
 
374
//  nsLocalFile::nsIFile
 
375
//*****************************************************************************
 
376
#pragma mark -
 
377
#pragma mark [nsIFile]
 
378
 
 
379
/* void append (in AString node); */
 
380
NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode)
 
381
{
 
382
  return AppendNative(NS_ConvertUTF16toUTF8(aNode));
 
383
}
 
384
 
 
385
/* [noscript] void appendNative (in ACString node); */
 
386
NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode)
 
387
{
 
388
  // Check we are correctly initialized.
 
389
  CHECK_mBaseRef();
 
390
 
 
391
  nsACString::const_iterator start, end;
 
392
  aNode.BeginReading(start);
 
393
  aNode.EndReading(end);
 
394
  if (FindCharInReadable(kPathSepChar, start, end))
 
395
    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
396
 
 
397
  CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
 
398
                                  PromiseFlatCString(aNode).get(),
 
399
                                  kCFStringEncodingUTF8);
 
400
  if (nodeStrRef) {
 
401
    CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
 
402
                                  mBaseRef, nodeStrRef, PR_FALSE);
 
403
    ::CFRelease(nodeStrRef);
 
404
    if (newRef) {
 
405
      SetBaseRef(newRef);
 
406
      ::CFRelease(newRef);
 
407
      return NS_OK;
 
408
    }
 
409
  }
 
410
  return NS_ERROR_FAILURE;
 
411
}
 
412
 
 
413
/* void normalize (); */
 
414
NS_IMETHODIMP nsLocalFile::Normalize()
 
415
{
 
416
  // Check we are correctly initialized.
 
417
  CHECK_mBaseRef();
 
418
 
 
419
  // CFURL doesn't doesn't seem to resolve paths containing relative
 
420
  // components, so we'll nick the stdlib code from nsLocalFileUnix
 
421
  UInt8 path[PATH_MAX] = "";
 
422
  Boolean success;
 
423
  success = ::CFURLGetFileSystemRepresentation(mBaseRef, true, path, PATH_MAX);
 
424
  if (!success)
 
425
    return NS_ERROR_FAILURE;
 
426
 
 
427
  char resolved_path[PATH_MAX] = "";
 
428
  char *resolved_path_ptr = nsnull;
 
429
  resolved_path_ptr = realpath((char*)path, resolved_path);
 
430
 
 
431
  // if there is an error, the return is null.
 
432
  if (!resolved_path_ptr)
 
433
      return NSRESULT_FOR_ERRNO();
 
434
 
 
435
  // Need to know whether we're a directory to create a new CFURLRef
 
436
  PRBool isDirectory;
 
437
  nsresult rv = IsDirectory(&isDirectory);
 
438
  NS_ENSURE_SUCCESS(rv, rv);
 
439
 
 
440
  rv = NS_ERROR_FAILURE;
 
441
  CFStringRef pathStrRef =
 
442
    ::CFStringCreateWithCString(kCFAllocatorDefault,
 
443
                                resolved_path,
 
444
                                kCFStringEncodingUTF8);
 
445
  if (pathStrRef) {
 
446
    CFURLRef newURLRef =
 
447
      ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef,
 
448
                                      kCFURLPOSIXPathStyle, isDirectory);
 
449
    if (newURLRef) {
 
450
      SetBaseRef(newURLRef);
 
451
      ::CFRelease(newURLRef);
 
452
      rv = NS_OK;
 
453
    }
 
454
    ::CFRelease(pathStrRef);
 
455
  }
 
456
 
 
457
  return rv;
 
458
}
 
459
 
 
460
/* void create (in unsigned long type, in unsigned long permissions); */
 
461
NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
 
462
{
 
463
  if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
 
464
    return NS_ERROR_FILE_UNKNOWN_TYPE;
 
465
 
 
466
  // Check we are correctly initialized.
 
467
  CHECK_mBaseRef();
 
468
 
 
469
  nsStringArray nonExtantNodes;
 
470
  CFURLRef pathURLRef = mBaseRef;
 
471
  FSRef pathFSRef;
 
472
  CFStringRef leafStrRef = nsnull;
 
473
  nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
 
474
  Boolean success;
 
475
 
 
476
  // Work backwards through the path to find the last node which
 
477
  // exists. Place the nodes which don't exist in an array and we'll
 
478
  // create those below.
 
479
  while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) {
 
480
    leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef);
 
481
    if (!leafStrRef)
 
482
      break;
 
483
    CFIndex leafLen = ::CFStringGetLength(leafStrRef);
 
484
    if (!buffer.EnsureElemCapacity(leafLen + 1))
 
485
      break;
 
486
    ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get());
 
487
    buffer.get()[leafLen] = '\0';
 
488
    nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get())));
 
489
    ::CFRelease(leafStrRef);
 
490
    leafStrRef = nsnull;
 
491
 
 
492
    // Get the parent of the leaf for the next go round
 
493
    CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef);
 
494
    if (!parent)
 
495
      break;
 
496
    if (pathURLRef != mBaseRef)
 
497
      ::CFRelease(pathURLRef);
 
498
    pathURLRef = parent;
 
499
  }
 
500
  if (pathURLRef != mBaseRef)
 
501
    ::CFRelease(pathURLRef);
 
502
  if (leafStrRef != nsnull)
 
503
    ::CFRelease(leafStrRef);
 
504
  if (!success)
 
505
    return NS_ERROR_FAILURE;
 
506
  PRInt32 nodesToCreate = nonExtantNodes.Count();
 
507
  if (nodesToCreate == 0)
 
508
    return NS_ERROR_FILE_ALREADY_EXISTS;
 
509
 
 
510
  OSErr err;
 
511
  nsAutoString nextNodeName;
 
512
  for (PRInt32 i = nodesToCreate - 1; i > 0; i--) {
 
513
    nonExtantNodes.StringAt(i, nextNodeName);
 
514
    err = ::FSCreateDirectoryUnicode(&pathFSRef,
 
515
                                      nextNodeName.Length(),
 
516
                                      (const UniChar *)nextNodeName.get(),
 
517
                                      kFSCatInfoNone,
 
518
                                      nsnull, &pathFSRef, nsnull, nsnull);
 
519
    if (err != noErr)
 
520
      return MacErrorMapper(err);
 
521
  }
 
522
  nonExtantNodes.StringAt(0, nextNodeName);
 
523
  if (type == NORMAL_FILE_TYPE) {
 
524
    err = ::FSCreateFileUnicode(&pathFSRef,
 
525
                                nextNodeName.Length(),
 
526
                                (const UniChar *)nextNodeName.get(),
 
527
                                kFSCatInfoNone,
 
528
                                nsnull, nsnull, nsnull);
 
529
  }
 
530
  else {
 
531
    err = ::FSCreateDirectoryUnicode(&pathFSRef,
 
532
                                    nextNodeName.Length(),
 
533
                                    (const UniChar *)nextNodeName.get(),
 
534
                                    kFSCatInfoNone,
 
535
                                    nsnull, nsnull, nsnull, nsnull);
 
536
  }
 
537
 
 
538
  return MacErrorMapper(err);
 
539
}
 
540
 
 
541
/* attribute AString leafName; */
 
542
NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName)
 
543
{
 
544
  nsCAutoString nativeString;
 
545
  nsresult rv = GetNativeLeafName(nativeString);
 
546
  if (NS_FAILED(rv))
 
547
    return rv;
 
548
  CopyUTF8toUTF16NFC(nativeString, aLeafName);
 
549
  return NS_OK;
 
550
}
 
551
 
 
552
NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName)
 
553
{
 
554
  return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName));
 
555
}
 
556
 
 
557
/* [noscript] attribute ACString nativeLeafName; */
 
558
NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName)
 
559
{
 
560
  // Check we are correctly initialized.
 
561
  CHECK_mBaseRef();
 
562
 
 
563
  nsresult rv = NS_ERROR_FAILURE;
 
564
  CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef);
 
565
  if (leafStrRef) {
 
566
    rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName);
 
567
    ::CFRelease(leafStrRef);
 
568
  }
 
569
  return rv;
 
570
}
 
571
 
 
572
NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName)
 
573
{
 
574
  // Check we are correctly initialized.
 
575
  CHECK_mBaseRef();
 
576
 
 
577
  nsresult rv = NS_ERROR_FAILURE;
 
578
  CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
 
579
  if (parentURLRef) {
 
580
    CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
 
581
                                    PromiseFlatCString(aNativeLeafName).get(),
 
582
                                    kCFStringEncodingUTF8);
 
583
 
 
584
    if (nodeStrRef) {
 
585
      CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
 
586
                                    parentURLRef, nodeStrRef, PR_FALSE);
 
587
      if (newURLRef) {
 
588
        SetBaseRef(newURLRef);
 
589
        ::CFRelease(newURLRef);
 
590
        rv = NS_OK;
 
591
      }
 
592
      ::CFRelease(nodeStrRef);
 
593
    }
 
594
    ::CFRelease(parentURLRef);
 
595
  }
 
596
  return rv;
 
597
}
 
598
 
 
599
/* void copyTo (in nsIFile newParentDir, in AString newName); */
 
600
NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName)
 
601
{
 
602
  return CopyInternal(newParentDir, newName, PR_FALSE);
 
603
}
 
604
 
 
605
/* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */
 
606
NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName)
 
607
{
 
608
  return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE);
 
609
}
 
610
 
 
611
/* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */
 
612
NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName)
 
613
{
 
614
  return CopyInternal(newParentDir, newName, PR_TRUE);
 
615
}
 
616
 
 
617
/* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */
 
618
NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName)
 
619
{
 
620
  return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE);
 
621
}
 
622
 
 
623
/* void moveTo (in nsIFile newParentDir, in AString newName); */
 
624
NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName)
 
625
{
 
626
  return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName));
 
627
}
 
628
 
 
629
/* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */
 
630
NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName)
 
631
{
 
632
  // Check we are correctly initialized.
 
633
  CHECK_mBaseRef();
 
634
 
 
635
  StFollowLinksState followLinks(*this, PR_FALSE);
 
636
 
 
637
  PRBool isDirectory;
 
638
  nsresult rv = IsDirectory(&isDirectory);
 
639
  if (NS_FAILED(rv))
 
640
    return rv;
 
641
 
 
642
  // Get the source path.
 
643
  nsCAutoString srcPath;
 
644
  rv = GetNativePath(srcPath);
 
645
  if (NS_FAILED(rv))
 
646
    return rv;
 
647
 
 
648
  // Build the destination path.
 
649
  nsCOMPtr<nsIFile> parentDir = newParentDir;
 
650
  if (!parentDir) {
 
651
    if (newName.IsEmpty())
 
652
      return NS_ERROR_INVALID_ARG;
 
653
    rv = GetParent(getter_AddRefs(parentDir));
 
654
    if (NS_FAILED(rv))
 
655
      return rv;
 
656
  }
 
657
  else {
 
658
    PRBool exists;
 
659
    rv = parentDir->Exists(&exists);
 
660
    if (NS_FAILED(rv))
 
661
      return rv;
 
662
    if (!exists) {
 
663
      rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
 
664
      if (NS_FAILED(rv))
 
665
        return rv;
 
666
    }
 
667
  }
 
668
 
 
669
  nsCAutoString destPath;
 
670
  rv = parentDir->GetNativePath(destPath);
 
671
  if (NS_FAILED(rv))
 
672
    return rv;
 
673
 
 
674
  if (!newName.IsEmpty())
 
675
    destPath.Append(NS_LITERAL_CSTRING("/") + newName);
 
676
  else {
 
677
    nsCAutoString leafName;
 
678
    rv = GetNativeLeafName(leafName);
 
679
    if (NS_FAILED(rv))
 
680
      return rv;
 
681
    destPath.Append(NS_LITERAL_CSTRING("/") + leafName);
 
682
  }
 
683
 
 
684
  // Perform the move.
 
685
  if (rename(srcPath.get(), destPath.get()) != 0) {
 
686
    if (errno == EXDEV) {
 
687
      // Can't move across volume (device) boundaries.  Copy and remove.
 
688
      rv = CopyToNative(parentDir, newName);
 
689
      if (NS_SUCCEEDED(rv)) {
 
690
        // Permit removal failure.
 
691
        Remove(PR_TRUE);
 
692
      }
 
693
    }
 
694
    else
 
695
      rv = NSRESULT_FOR_ERRNO();
 
696
 
 
697
    if (NS_FAILED(rv))
 
698
      return rv;
 
699
  }
 
700
 
 
701
  // Update |this| to refer to the moved file.
 
702
  CFURLRef newBaseRef =
 
703
   ::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(),
 
704
                                             destPath.Length(), isDirectory);
 
705
  if (!newBaseRef)
 
706
    return NS_ERROR_FAILURE;
 
707
  SetBaseRef(newBaseRef);
 
708
  ::CFRelease(newBaseRef);
 
709
 
 
710
  return rv;
 
711
}
 
712
 
 
713
/* void remove (in boolean recursive); */
 
714
NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive)
 
715
{
 
716
  // Check we are correctly initialized.
 
717
  CHECK_mBaseRef();
 
718
 
 
719
  // XXX If we're an alias, never remove target
 
720
  StFollowLinksState followLinks(*this, PR_FALSE);
 
721
 
 
722
  PRBool isDirectory;
 
723
  nsresult rv = IsDirectory(&isDirectory);
 
724
  if (NS_FAILED(rv))
 
725
    return rv;
 
726
 
 
727
  if (recursive && isDirectory) {
 
728
    FSRef fsRef;
 
729
    rv = GetFSRefInternal(fsRef);
 
730
    if (NS_FAILED(rv))
 
731
      return rv;
 
732
 
 
733
    // Call MoreFilesX to do a recursive removal.
 
734
    OSStatus err = ::FSDeleteContainer(&fsRef);
 
735
    rv = MacErrorMapper(err);
 
736
  }
 
737
  else {
 
738
    nsCAutoString path;
 
739
    rv = GetNativePath(path);
 
740
    if (NS_FAILED(rv))
 
741
      return rv;
 
742
 
 
743
    const char* pathPtr = path.get();
 
744
    int status;
 
745
    if (isDirectory)
 
746
      status = rmdir(pathPtr);
 
747
    else
 
748
      status = unlink(pathPtr);
 
749
 
 
750
    if (status != 0)
 
751
      rv = NSRESULT_FOR_ERRNO();
 
752
  }
 
753
 
 
754
  mCachedFSRefValid = PR_FALSE;
 
755
  return rv;
 
756
}
 
757
 
 
758
/* attribute unsigned long permissions; */
 
759
NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions)
 
760
{
 
761
  NS_ENSURE_ARG_POINTER(aPermissions);
 
762
 
 
763
  FSRef fsRef;
 
764
  nsresult rv = GetFSRefInternal(fsRef);
 
765
  if (NS_FAILED(rv))
 
766
    return rv;
 
767
 
 
768
  FSCatalogInfo catalogInfo;
 
769
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
 
770
                  nsnull, nsnull, nsnull);
 
771
  if (err != noErr)
 
772
    return MacErrorMapper(err);
 
773
  FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
 
774
  *aPermissions = permPtr->mode;
 
775
  return NS_OK;
 
776
}
 
777
 
 
778
NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions)
 
779
{
 
780
  FSRef fsRef;
 
781
  nsresult rv = GetFSRefInternal(fsRef);
 
782
  if (NS_FAILED(rv))
 
783
    return rv;
 
784
 
 
785
  FSCatalogInfo catalogInfo;
 
786
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
 
787
                  nsnull, nsnull, nsnull);
 
788
  if (err != noErr)
 
789
    return MacErrorMapper(err);
 
790
  FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
 
791
  permPtr->mode = (UInt16)aPermissions;
 
792
  err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo);
 
793
  return MacErrorMapper(err);
 
794
}
 
795
 
 
796
/* attribute unsigned long permissionsOfLink; */
 
797
NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
 
798
{
 
799
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
800
    return NS_ERROR_NOT_IMPLEMENTED;
 
801
}
 
802
 
 
803
NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink)
 
804
{
 
805
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
806
    return NS_ERROR_NOT_IMPLEMENTED;
 
807
}
 
808
 
 
809
/* attribute PRInt64 lastModifiedTime; */
 
810
NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
 
811
{
 
812
  // Check we are correctly initialized.
 
813
  CHECK_mBaseRef();
 
814
 
 
815
  NS_ENSURE_ARG_POINTER(aLastModifiedTime);
 
816
 
 
817
  FSRef fsRef;
 
818
  nsresult rv = GetFSRefInternal(fsRef);
 
819
  if (NS_FAILED(rv))
 
820
    return rv;
 
821
 
 
822
  FSCatalogInfo catalogInfo;
 
823
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo,
 
824
                                nsnull, nsnull, nsnull);
 
825
  if (err != noErr)
 
826
    return MacErrorMapper(err);
 
827
  *aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate);
 
828
  return NS_OK;
 
829
}
 
830
 
 
831
NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
 
832
{
 
833
  // Check we are correctly initialized.
 
834
  CHECK_mBaseRef();
 
835
 
 
836
  OSErr err;
 
837
  nsresult rv;
 
838
  FSRef fsRef;
 
839
  FSCatalogInfo catalogInfo;
 
840
 
 
841
  rv = GetFSRefInternal(fsRef);
 
842
  if (NS_FAILED(rv))
 
843
    return rv;
 
844
 
 
845
  FSRef parentRef;
 
846
  PRBool notifyParent;
 
847
 
 
848
  /* Get the node flags, the content modification date and time, and the parent ref */
 
849
  err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod,
 
850
                           &catalogInfo, NULL, NULL, &parentRef);
 
851
  if (err != noErr)
 
852
    return MacErrorMapper(err);
 
853
 
 
854
  /* Notify the parent if this is a file */
 
855
  notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
 
856
 
 
857
  NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate);
 
858
  err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo);
 
859
  if (err != noErr)
 
860
    return MacErrorMapper(err);
 
861
 
 
862
  /* Send a notification for the parent of the file, or for the directory */
 
863
  err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions);
 
864
  if (err != noErr)
 
865
    return MacErrorMapper(err);
 
866
 
 
867
  return NS_OK;
 
868
}
 
869
 
 
870
/* attribute PRInt64 lastModifiedTimeOfLink; */
 
871
NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink)
 
872
{
 
873
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
874
    return NS_ERROR_NOT_IMPLEMENTED;
 
875
}
 
876
NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink)
 
877
{
 
878
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
879
    return NS_ERROR_NOT_IMPLEMENTED;
 
880
}
 
881
 
 
882
/* attribute PRInt64 fileSize; */
 
883
NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize)
 
884
{
 
885
  NS_ENSURE_ARG_POINTER(aFileSize);
 
886
  *aFileSize = 0;
 
887
 
 
888
  FSRef fsRef;
 
889
  nsresult rv = GetFSRefInternal(fsRef);
 
890
  if (NS_FAILED(rv))
 
891
    return rv;
 
892
 
 
893
  FSCatalogInfo catalogInfo;
 
894
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo,
 
895
                                  nsnull, nsnull, nsnull);
 
896
  if (err != noErr)
 
897
    return MacErrorMapper(err);
 
898
 
 
899
  // FSGetCatalogInfo can return a bogus size for directories sometimes, so only
 
900
  // rely on the answer for files
 
901
  if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0)
 
902
      *aFileSize = catalogInfo.dataLogicalSize;
 
903
  return NS_OK;
 
904
}
 
905
 
 
906
NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize)
 
907
{
 
908
  // Check we are correctly initialized.
 
909
  CHECK_mBaseRef();
 
910
 
 
911
  FSRef fsRef;
 
912
  nsresult rv = GetFSRefInternal(fsRef);
 
913
  if (NS_FAILED(rv))
 
914
    return rv;
 
915
 
 
916
  SInt16 refNum;
 
917
  OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum);
 
918
  if (err != noErr)
 
919
    return MacErrorMapper(err);
 
920
  err = ::FSSetForkSize(refNum, fsFromStart, aFileSize);
 
921
  ::FSCloseFork(refNum);
 
922
 
 
923
  return MacErrorMapper(err);
 
924
}
 
925
 
 
926
/* readonly attribute PRInt64 fileSizeOfLink; */
 
927
NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink)
 
928
{
 
929
  // Check we are correctly initialized.
 
930
  CHECK_mBaseRef();
 
931
 
 
932
  NS_ENSURE_ARG_POINTER(aFileSizeOfLink);
 
933
 
 
934
  StFollowLinksState followLinks(*this, PR_FALSE);
 
935
  return GetFileSize(aFileSizeOfLink);
 
936
}
 
937
 
 
938
/* readonly attribute AString target; */
 
939
NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget)
 
940
{
 
941
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
942
    return NS_ERROR_NOT_IMPLEMENTED;
 
943
}
 
944
 
 
945
/* [noscript] readonly attribute ACString nativeTarget; */
 
946
NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget)
 
947
{
 
948
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
949
    return NS_ERROR_NOT_IMPLEMENTED;
 
950
}
 
951
 
 
952
/* readonly attribute AString path; */
 
953
NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath)
 
954
{
 
955
  nsCAutoString nativeString;
 
956
  nsresult rv = GetNativePath(nativeString);
 
957
  if (NS_FAILED(rv))
 
958
    return rv;
 
959
  CopyUTF8toUTF16NFC(nativeString, aPath);
 
960
  return NS_OK;
 
961
}
 
962
 
 
963
/* [noscript] readonly attribute ACString nativePath; */
 
964
NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath)
 
965
{
 
966
  // Check we are correctly initialized.
 
967
  CHECK_mBaseRef();
 
968
 
 
969
  nsresult rv = NS_ERROR_FAILURE;
 
970
  CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
 
971
  if (pathStrRef) {
 
972
    rv = CFStringReftoUTF8(pathStrRef, aNativePath);
 
973
    ::CFRelease(pathStrRef);
 
974
  }
 
975
  return rv;
 
976
}
 
977
 
 
978
/* boolean exists (); */
 
979
NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval)
 
980
{
 
981
  // Check we are correctly initialized.
 
982
  CHECK_mBaseRef();
 
983
 
 
984
  NS_ENSURE_ARG_POINTER(_retval);
 
985
  *_retval = PR_FALSE;
 
986
 
 
987
  FSRef fsRef;
 
988
  if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) {
 
989
    *_retval = PR_TRUE;
 
990
  }
 
991
 
 
992
  return NS_OK;
 
993
}
 
994
 
 
995
/* boolean isWritable (); */
 
996
NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval)
 
997
{
 
998
    // Check we are correctly initialized.
 
999
    CHECK_mBaseRef();
 
1000
 
 
1001
    NS_ENSURE_ARG_POINTER(_retval);
 
1002
    *_retval = PR_FALSE;
 
1003
 
 
1004
    FSRef fsRef;
 
1005
    nsresult rv = GetFSRefInternal(fsRef);
 
1006
    if (NS_FAILED(rv))
 
1007
      return rv;
 
1008
    if (::FSCheckLock(&fsRef) == noErr) {
 
1009
      PRUint32 permissions;
 
1010
      rv = GetPermissions(&permissions);
 
1011
      if (NS_FAILED(rv))
 
1012
        return rv;
 
1013
      *_retval = ((permissions & S_IWUSR) != 0);
 
1014
    }
 
1015
    return NS_OK;
 
1016
}
 
1017
 
 
1018
/* boolean isReadable (); */
 
1019
NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval)
 
1020
{
 
1021
    // Check we are correctly initialized.
 
1022
    CHECK_mBaseRef();
 
1023
 
 
1024
    NS_ENSURE_ARG_POINTER(_retval);
 
1025
    *_retval = PR_FALSE;
 
1026
 
 
1027
    PRUint32 permissions;
 
1028
    nsresult rv = GetPermissions(&permissions);
 
1029
    if (NS_FAILED(rv))
 
1030
      return rv;
 
1031
    *_retval = ((permissions & S_IRUSR) != 0);
 
1032
    return NS_OK;
 
1033
}
 
1034
 
 
1035
/* boolean isExecutable (); */
 
1036
NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval)
 
1037
{
 
1038
  // Check we are correctly initialized.
 
1039
  CHECK_mBaseRef();
 
1040
 
 
1041
  NS_ENSURE_ARG_POINTER(_retval);
 
1042
  *_retval = PR_FALSE;
 
1043
 
 
1044
  FSRef fsRef;
 
1045
  nsresult rv = GetFSRefInternal(fsRef);
 
1046
  if (NS_FAILED(rv))
 
1047
    return rv;
 
1048
 
 
1049
  LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
 
1050
  LSItemInfoRecord theInfo;
 
1051
  if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) {
 
1052
    if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
 
1053
    *_retval = PR_TRUE;
 
1054
  }
 
1055
  return NS_OK;
 
1056
}
 
1057
 
 
1058
/* boolean isHidden (); */
 
1059
NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval)
 
1060
{
 
1061
  NS_ENSURE_ARG_POINTER(_retval);
 
1062
  *_retval = PR_FALSE;
 
1063
 
 
1064
  FSRef fsRef;
 
1065
  nsresult rv = GetFSRefInternal(fsRef);
 
1066
  if (NS_FAILED(rv))
 
1067
    return rv;
 
1068
 
 
1069
  FSCatalogInfo catalogInfo;
 
1070
  HFSUniStr255 leafName;
 
1071
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo,
 
1072
                                &leafName, nsnull, nsnull);
 
1073
  if (err != noErr)
 
1074
    return MacErrorMapper(err);
 
1075
 
 
1076
  FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo
 
1077
  if ((fInfoPtr->finderFlags & kIsInvisible) != 0) {
 
1078
    *_retval = PR_TRUE;
 
1079
  }
 
1080
  else {
 
1081
    // If the leaf name begins with a '.', consider it invisible
 
1082
    if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.'))
 
1083
      *_retval = PR_TRUE;
 
1084
  }
 
1085
  return NS_OK;
 
1086
}
 
1087
 
 
1088
/* boolean isDirectory (); */
 
1089
NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval)
 
1090
{
 
1091
  NS_ENSURE_ARG_POINTER(_retval);
 
1092
  *_retval = PR_FALSE;
 
1093
 
 
1094
  FSRef fsRef;
 
1095
  nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
 
1096
  if (NS_FAILED(rv))
 
1097
    return rv;
 
1098
 
 
1099
  FSCatalogInfo catalogInfo;
 
1100
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
 
1101
                                nsnull, nsnull, nsnull);
 
1102
  if (err != noErr)
 
1103
    return MacErrorMapper(err);
 
1104
  *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0);
 
1105
  return NS_OK;
 
1106
}
 
1107
 
 
1108
/* boolean isFile (); */
 
1109
NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval)
 
1110
{
 
1111
  NS_ENSURE_ARG_POINTER(_retval);
 
1112
  *_retval = PR_FALSE;
 
1113
 
 
1114
  FSRef fsRef;
 
1115
  nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
 
1116
  if (NS_FAILED(rv))
 
1117
    return rv;
 
1118
 
 
1119
  FSCatalogInfo catalogInfo;
 
1120
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
 
1121
                                nsnull, nsnull, nsnull);
 
1122
  if (err != noErr)
 
1123
    return MacErrorMapper(err);
 
1124
  *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0);
 
1125
  return NS_OK;
 
1126
}
 
1127
 
 
1128
/* boolean isSymlink (); */
 
1129
NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval)
 
1130
{
 
1131
  // Check we are correctly initialized.
 
1132
  CHECK_mBaseRef();
 
1133
 
 
1134
  NS_ENSURE_ARG(_retval);
 
1135
  *_retval = PR_FALSE;
 
1136
 
 
1137
  // Check we are correctly initialized.
 
1138
  CHECK_mBaseRef();
 
1139
 
 
1140
  FSRef fsRef;
 
1141
  if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
 
1142
    Boolean isAlias, isFolder;
 
1143
    if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr)
 
1144
        *_retval = isAlias;
 
1145
  }
 
1146
  return NS_OK;
 
1147
}
 
1148
 
 
1149
/* boolean isSpecial (); */
 
1150
NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval)
 
1151
{
 
1152
    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
1153
    return NS_ERROR_NOT_IMPLEMENTED;
 
1154
}
 
1155
 
 
1156
/* nsIFile clone (); */
 
1157
NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval)
 
1158
{
 
1159
    // Just copy-construct ourselves
 
1160
    *_retval = new nsLocalFile(*this);
 
1161
    if (!*_retval)
 
1162
      return NS_ERROR_OUT_OF_MEMORY;
 
1163
 
 
1164
    NS_ADDREF(*_retval);
 
1165
 
 
1166
    return NS_OK;
 
1167
}
 
1168
 
 
1169
/* boolean equals (in nsIFile inFile); */
 
1170
NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
 
1171
{
 
1172
    return EqualsInternal(inFile, PR_TRUE, _retval);
 
1173
}
 
1174
 
 
1175
nsresult
 
1176
nsLocalFile::EqualsInternal(nsISupports* inFile, PRBool aUpdateCache,
 
1177
                            PRBool *_retval)
 
1178
{
 
1179
  NS_ENSURE_ARG_POINTER(_retval);
 
1180
  *_retval = PR_FALSE;
 
1181
 
 
1182
  nsCOMPtr<nsILocalFileMac> inMacFile(do_QueryInterface(inFile));
 
1183
  if (!inFile)
 
1184
    return NS_OK;
 
1185
 
 
1186
  nsLocalFile* inLF =
 
1187
      NS_STATIC_CAST(nsLocalFile*, (nsILocalFileMac*) inMacFile);
 
1188
 
 
1189
  // If both exist, compare FSRefs
 
1190
  FSRef thisFSRef, inFSRef;
 
1191
  nsresult rv1 = GetFSRefInternal(thisFSRef, aUpdateCache);
 
1192
  nsresult rv2 = inLF->GetFSRefInternal(inFSRef, aUpdateCache);
 
1193
  if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
 
1194
    *_retval = (thisFSRef == inFSRef);
 
1195
    return NS_OK;
 
1196
  }
 
1197
  // If one exists and the other doesn't, not equal
 
1198
  if (rv1 != rv2)
 
1199
    return NS_OK;
 
1200
 
 
1201
  // Arg, we have to get their paths and compare
 
1202
  nsCAutoString thisPath, inPath;
 
1203
  if (NS_FAILED(GetNativePath(thisPath)))
 
1204
    return NS_ERROR_FAILURE;
 
1205
  if (NS_FAILED(inMacFile->GetNativePath(inPath)))
 
1206
    return NS_ERROR_FAILURE;
 
1207
  *_retval = thisPath.Equals(inPath);
 
1208
 
 
1209
  return NS_OK;
 
1210
}
 
1211
 
 
1212
/* boolean contains (in nsIFile inFile, in boolean recur); */
 
1213
NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
 
1214
{
 
1215
  // Check we are correctly initialized.
 
1216
  CHECK_mBaseRef();
 
1217
 
 
1218
  NS_ENSURE_ARG_POINTER(_retval);
 
1219
  *_retval = PR_FALSE;
 
1220
 
 
1221
  PRBool isDir;
 
1222
  nsresult rv = IsDirectory(&isDir);
 
1223
  if (NS_FAILED(rv))
 
1224
    return rv;
 
1225
  if (!isDir)
 
1226
    return NS_OK;     // must be a dir to contain someone
 
1227
 
 
1228
  nsCAutoString thisPath, inPath;
 
1229
  if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath)))
 
1230
    return NS_ERROR_FAILURE;
 
1231
  size_t thisPathLen = thisPath.Length();
 
1232
  if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) {
 
1233
    // Now make sure that the |inFile|'s path has a separator at thisPathLen,
 
1234
    // and there's at least one more character after that.
 
1235
    if (inPath[thisPathLen] == kPathSepChar)
 
1236
      *_retval = PR_TRUE;
 
1237
  }
 
1238
  return NS_OK;
 
1239
}
 
1240
 
 
1241
/* readonly attribute nsIFile parent; */
 
1242
NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent)
 
1243
{
 
1244
  NS_ENSURE_ARG_POINTER(aParent);
 
1245
  *aParent = nsnull;
 
1246
 
 
1247
  // Check we are correctly initialized.
 
1248
  CHECK_mBaseRef();
 
1249
 
 
1250
  nsLocalFile *newFile = nsnull;
 
1251
 
 
1252
  // If it can be determined without error that a file does not
 
1253
  // have a parent, return nsnull for the parent and NS_OK as the result.
 
1254
  // See bug 133617.
 
1255
  nsresult rv = NS_OK;
 
1256
  CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
 
1257
  if (parentURLRef) {
 
1258
    rv = NS_ERROR_FAILURE;
 
1259
    newFile = new nsLocalFile;
 
1260
    if (newFile) {
 
1261
      rv = newFile->InitWithCFURL(parentURLRef);
 
1262
      if (NS_SUCCEEDED(rv)) {
 
1263
        NS_ADDREF(*aParent = newFile);
 
1264
        rv = NS_OK;
 
1265
      }
 
1266
    }
 
1267
    ::CFRelease(parentURLRef);
 
1268
  }
 
1269
  return rv;
 
1270
}
 
1271
 
 
1272
/* readonly attribute nsISimpleEnumerator directoryEntries; */
 
1273
NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries)
 
1274
{
 
1275
  NS_ENSURE_ARG_POINTER(aDirectoryEntries);
 
1276
  *aDirectoryEntries = nsnull;
 
1277
 
 
1278
  nsresult rv;
 
1279
  PRBool isDir;
 
1280
  rv = IsDirectory(&isDir);
 
1281
  if (NS_FAILED(rv))
 
1282
    return rv;
 
1283
  if (!isDir)
 
1284
    return NS_ERROR_FILE_NOT_DIRECTORY;
 
1285
 
 
1286
  nsDirEnumerator* dirEnum = new nsDirEnumerator;
 
1287
  if (dirEnum == nsnull)
 
1288
    return NS_ERROR_OUT_OF_MEMORY;
 
1289
  NS_ADDREF(dirEnum);
 
1290
  rv = dirEnum->Init(this);
 
1291
  if (NS_FAILED(rv)) {
 
1292
    NS_RELEASE(dirEnum);
 
1293
    return rv;
 
1294
  }
 
1295
  *aDirectoryEntries = dirEnum;
 
1296
 
 
1297
  return NS_OK;
 
1298
}
 
1299
 
 
1300
 
 
1301
//*****************************************************************************
 
1302
//  nsLocalFile::nsILocalFile
 
1303
//*****************************************************************************
 
1304
#pragma mark -
 
1305
#pragma mark [nsILocalFile]
 
1306
 
 
1307
/* void initWithPath (in AString filePath); */
 
1308
NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath)
 
1309
{
 
1310
  return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath));
 
1311
}
 
1312
 
 
1313
/* [noscript] void initWithNativePath (in ACString filePath); */
 
1314
NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath)
 
1315
{
 
1316
  nsCAutoString fixedPath;
 
1317
  if (Substring(filePath, 0, 2).EqualsLiteral("~/")) {
 
1318
    nsCOMPtr<nsIFile> homeDir;
 
1319
    nsCAutoString homePath;
 
1320
    nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR,
 
1321
                                        getter_AddRefs(homeDir));
 
1322
    NS_ENSURE_SUCCESS(rv, rv);
 
1323
    rv = homeDir->GetNativePath(homePath);
 
1324
    NS_ENSURE_SUCCESS(rv, rv);
 
1325
 
 
1326
    fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1);
 
1327
  }
 
1328
  else if (filePath.IsEmpty() || filePath.First() != '/')
 
1329
    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
1330
  else
 
1331
    fixedPath.Assign(filePath);
 
1332
 
 
1333
  // A path with consecutive '/'s which are not between
 
1334
  // nodes crashes CFURLGetFSRef(). Consecutive '/'s which
 
1335
  // are between actual nodes are OK. So, convert consecutive
 
1336
  // '/'s to a single one.
 
1337
  fixedPath.ReplaceSubstring("//", "/");
 
1338
 
 
1339
#if 1 // bird: hack to fix RegistryLocationForSpec issues with /path/to/./components
 
1340
  fixedPath.ReplaceSubstring("/./", "/");
 
1341
  size_t len = fixedPath.Length();
 
1342
  while (len > 2)
 
1343
  {
 
1344
    size_t choplen = 0;
 
1345
    if (!strcmp(fixedPath.get() + len - 2, "/."))
 
1346
      choplen = 2;
 
1347
    else if (!strcmp(fixedPath.get() + len - 1, "/"))
 
1348
      choplen = 1;
 
1349
    else
 
1350
      break;
 
1351
    fixedPath = StringHead(fixedPath, len - choplen);
 
1352
  }
 
1353
  // bird: another hack for the issue with VirtualBoxVM and symlinks...
 
1354
  char tmpBuf[PATH_MAX];
 
1355
  if (realpath(fixedPath.get(), tmpBuf))
 
1356
    fixedPath = tmpBuf;
 
1357
#endif
 
1358
 
 
1359
  // On 10.2, huge paths also crash CFURLGetFSRef()
 
1360
  if (fixedPath.Length() > PATH_MAX)
 
1361
    return NS_ERROR_FILE_NAME_TOO_LONG;
 
1362
 
 
1363
  CFStringRef pathAsCFString;
 
1364
  CFURLRef pathAsCFURL;
 
1365
 
 
1366
  pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8);
 
1367
  if (!pathAsCFString)
 
1368
    return NS_ERROR_FAILURE;
 
1369
  pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE);
 
1370
  if (!pathAsCFURL) {
 
1371
    ::CFRelease(pathAsCFString);
 
1372
    return NS_ERROR_FAILURE;
 
1373
  }
 
1374
  SetBaseRef(pathAsCFURL);
 
1375
  ::CFRelease(pathAsCFURL);
 
1376
  ::CFRelease(pathAsCFString);
 
1377
  return NS_OK;
 
1378
}
 
1379
 
 
1380
/* void initWithFile (in nsILocalFile aFile); */
 
1381
NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
 
1382
{
 
1383
  NS_ENSURE_ARG(aFile);
 
1384
 
 
1385
  nsCOMPtr<nsILocalFileMac> aFileMac(do_QueryInterface(aFile));
 
1386
  if (!aFileMac)
 
1387
    return NS_ERROR_UNEXPECTED;
 
1388
  CFURLRef urlRef;
 
1389
  nsresult rv = aFileMac->GetCFURL(&urlRef);
 
1390
  if (NS_FAILED(rv))
 
1391
    return rv;
 
1392
  rv = InitWithCFURL(urlRef);
 
1393
  ::CFRelease(urlRef);
 
1394
  return rv;
 
1395
}
 
1396
 
 
1397
/* attribute PRBool followLinks; */
 
1398
NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
 
1399
{
 
1400
  NS_ENSURE_ARG_POINTER(aFollowLinks);
 
1401
 
 
1402
  *aFollowLinks = mFollowLinks;
 
1403
  return NS_OK;
 
1404
}
 
1405
 
 
1406
NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
 
1407
{
 
1408
  if (aFollowLinks != mFollowLinks) {
 
1409
    mFollowLinks = aFollowLinks;
 
1410
    UpdateTargetRef();
 
1411
  }
 
1412
  return NS_OK;
 
1413
}
 
1414
 
 
1415
/* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */
 
1416
NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
 
1417
{
 
1418
  NS_ENSURE_ARG_POINTER(_retval);
 
1419
 
 
1420
  nsCAutoString path;
 
1421
  nsresult rv = GetPathInternal(path);
 
1422
  if (NS_FAILED(rv))
 
1423
    return rv;
 
1424
 
 
1425
  *_retval = PR_Open(path.get(), flags, mode);
 
1426
  if (! *_retval)
 
1427
    return NS_ErrorAccordingToNSPR();
 
1428
 
 
1429
  return NS_OK;
 
1430
}
 
1431
 
 
1432
/* [noscript] FILE openANSIFileDesc (in string mode); */
 
1433
NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
 
1434
{
 
1435
  NS_ENSURE_ARG_POINTER(_retval);
 
1436
 
 
1437
  nsCAutoString path;
 
1438
  nsresult rv = GetPathInternal(path);
 
1439
  if (NS_FAILED(rv))
 
1440
    return rv;
 
1441
 
 
1442
  *_retval = fopen(path.get(), mode);
 
1443
  if (! *_retval)
 
1444
    return NS_ERROR_FAILURE;
 
1445
 
 
1446
  return NS_OK;
 
1447
}
 
1448
 
 
1449
/* [noscript] PRLibraryStar load (); */
 
1450
NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval)
 
1451
{
 
1452
  // Check we are correctly initialized.
 
1453
  CHECK_mBaseRef();
 
1454
 
 
1455
  NS_ENSURE_ARG_POINTER(_retval);
 
1456
 
 
1457
  NS_TIMELINE_START_TIMER("PR_LoadLibrary");
 
1458
 
 
1459
  nsCAutoString path;
 
1460
  nsresult rv = GetPathInternal(path);
 
1461
  if (NS_FAILED(rv))
 
1462
    return rv;
 
1463
 
 
1464
#ifdef NS_BUILD_REFCNT_LOGGING
 
1465
  nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
 
1466
#endif
 
1467
 
 
1468
  *_retval = PR_LoadLibrary(path.get());
 
1469
 
 
1470
#ifdef NS_BUILD_REFCNT_LOGGING
 
1471
  nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
 
1472
#endif
 
1473
 
 
1474
  NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
 
1475
  NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get());
 
1476
 
 
1477
  if (!*_retval)
 
1478
    return NS_ERROR_FAILURE;
 
1479
 
 
1480
  return NS_OK;
 
1481
}
 
1482
 
 
1483
/* readonly attribute PRInt64 diskSpaceAvailable; */
 
1484
NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
 
1485
{
 
1486
  // Check we are correctly initialized.
 
1487
  CHECK_mBaseRef();
 
1488
 
 
1489
  NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
 
1490
 
 
1491
  FSRef fsRef;
 
1492
  nsresult rv = GetFSRefInternal(fsRef);
 
1493
  if (NS_FAILED(rv))
 
1494
    return rv;
 
1495
 
 
1496
  OSErr err;
 
1497
  FSCatalogInfo catalogInfo;
 
1498
  err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo,
 
1499
                           nsnull, nsnull, nsnull);
 
1500
  if (err != noErr)
 
1501
    return MacErrorMapper(err);
 
1502
 
 
1503
  FSVolumeInfo volumeInfo;
 
1504
  err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes,
 
1505
                          &volumeInfo, nsnull, nsnull);
 
1506
  if (err != noErr)
 
1507
    return MacErrorMapper(err);
 
1508
 
 
1509
  *aDiskSpaceAvailable = volumeInfo.freeBytes;
 
1510
  return NS_OK;
 
1511
}
 
1512
 
 
1513
/* void appendRelativePath (in AString relativeFilePath); */
 
1514
NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath)
 
1515
{
 
1516
  return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath));
 
1517
}
 
1518
 
 
1519
/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */
 
1520
NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath)
 
1521
{
 
1522
  if (relativeFilePath.IsEmpty())
 
1523
    return NS_OK;
 
1524
  // No leading '/'
 
1525
  if (relativeFilePath.First() == '/')
 
1526
    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
1527
 
 
1528
  // Parse the nodes and call Append() for each
 
1529
  nsACString::const_iterator nodeBegin, pathEnd;
 
1530
  relativeFilePath.BeginReading(nodeBegin);
 
1531
  relativeFilePath.EndReading(pathEnd);
 
1532
  nsACString::const_iterator nodeEnd(nodeBegin);
 
1533
 
 
1534
  while (nodeEnd != pathEnd) {
 
1535
    FindCharInReadable(kPathSepChar, nodeEnd, pathEnd);
 
1536
    nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd));
 
1537
    if (NS_FAILED(rv))
 
1538
      return rv;
 
1539
    if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
 
1540
      ++nodeEnd;
 
1541
    nodeBegin = nodeEnd;
 
1542
  }
 
1543
  return NS_OK;
 
1544
}
 
1545
 
 
1546
/* attribute ACString persistentDescriptor; */
 
1547
NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor)
 
1548
{
 
1549
  FSRef fsRef;
 
1550
  nsresult rv = GetFSRefInternal(fsRef);
 
1551
  if (NS_FAILED(rv))
 
1552
    return rv;
 
1553
 
 
1554
  AliasHandle aliasH;
 
1555
  OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH);
 
1556
  if (err != noErr)
 
1557
    return MacErrorMapper(err);
 
1558
 
 
1559
   PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
 
1560
   ::HLock((Handle) aliasH);
 
1561
   // Passing nsnull for dest makes NULL-term string
 
1562
   char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
 
1563
   ::DisposeHandle((Handle) aliasH);
 
1564
   NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
 
1565
 
 
1566
   aPersistentDescriptor = buf;
 
1567
   PR_Free(buf);
 
1568
 
 
1569
  return NS_OK;
 
1570
}
 
1571
 
 
1572
NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor)
 
1573
{
 
1574
  if (aPersistentDescriptor.IsEmpty())
 
1575
    return NS_ERROR_INVALID_ARG;
 
1576
 
 
1577
  // Support pathnames as user-supplied descriptors if they begin with '/'
 
1578
  // or '~'.  These characters do not collide with the base64 set used for
 
1579
  // encoding alias records.
 
1580
  char first = aPersistentDescriptor.First();
 
1581
  if (first == '/' || first == '~')
 
1582
    return InitWithNativePath(aPersistentDescriptor);
 
1583
 
 
1584
  nsresult rv = NS_OK;
 
1585
 
 
1586
  PRUint32 dataSize = aPersistentDescriptor.Length();
 
1587
  char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
 
1588
  if (!decodedData) {
 
1589
    NS_ERROR("SetPersistentDescriptor was given bad data");
 
1590
    return NS_ERROR_FAILURE;
 
1591
  }
 
1592
 
 
1593
  // Cast to an alias record and resolve.
 
1594
  AliasRecord aliasHeader = *(AliasPtr)decodedData;
 
1595
  PRInt32 aliasSize = GetAliasSizeFromRecord(aliasHeader);
 
1596
  if (aliasSize > (dataSize * 3) / 4) { // be paranoid about having too few data
 
1597
    PR_Free(decodedData);
 
1598
    return NS_ERROR_FAILURE;
 
1599
  }
 
1600
 
 
1601
  // Move the now-decoded data into the Handle.
 
1602
  // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
 
1603
  Handle        newHandle = nsnull;
 
1604
  if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
 
1605
    rv = NS_ERROR_OUT_OF_MEMORY;
 
1606
  PR_Free(decodedData);
 
1607
  if (NS_FAILED(rv))
 
1608
    return rv;
 
1609
 
 
1610
  Boolean changed;
 
1611
  FSRef resolvedFSRef;
 
1612
  OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
 
1613
 
 
1614
  rv = MacErrorMapper(err);
 
1615
  DisposeHandle(newHandle);
 
1616
  if (NS_FAILED(rv))
 
1617
    return rv;
 
1618
 
 
1619
  return InitWithFSRef(&resolvedFSRef);
 
1620
}
 
1621
 
 
1622
/* void reveal (); */
 
1623
NS_IMETHODIMP nsLocalFile::Reveal()
 
1624
{
 
1625
  FSRef             fsRefToReveal;
 
1626
  AppleEvent        aeEvent = {0, nil};
 
1627
  AppleEvent        aeReply = {0, nil};
 
1628
  StAEDesc          aeDirDesc, listElem, myAddressDesc, fileList;
 
1629
  OSErr             err;
 
1630
  ProcessSerialNumber   process;
 
1631
 
 
1632
  nsresult rv = GetFSRefInternal(fsRefToReveal);
 
1633
  if (NS_FAILED(rv))
 
1634
    return rv;
 
1635
 
 
1636
  err = ::FindRunningAppBySignature ('MACS', process);
 
1637
  if (err == noErr) {
 
1638
    err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
 
1639
    if (err == noErr) {
 
1640
      // Create the FinderEvent
 
1641
      err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc,
 
1642
                        kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
 
1643
      if (err == noErr) {
 
1644
        // Create the file list
 
1645
        err = ::AECreateList(nil, 0, false, &fileList);
 
1646
        if (err == noErr) {
 
1647
          FSSpec fsSpecToReveal;
 
1648
          err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal);
 
1649
          if (err == noErr) {
 
1650
            err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec));
 
1651
            if (err == noErr) {
 
1652
              err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList);
 
1653
              if (err == noErr) {
 
1654
                err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
 
1655
                if (err == noErr)
 
1656
                  ::SetFrontProcess(&process);
 
1657
              }
 
1658
            }
 
1659
          }
 
1660
        }
 
1661
      }
 
1662
    }
 
1663
  }
 
1664
 
 
1665
  return NS_OK;
 
1666
}
 
1667
 
 
1668
/* void launch (); */
 
1669
NS_IMETHODIMP nsLocalFile::Launch()
 
1670
{
 
1671
  FSRef fsRef;
 
1672
  nsresult rv = GetFSRefInternal(fsRef);
 
1673
  if (NS_FAILED(rv))
 
1674
    return rv;
 
1675
 
 
1676
  OSErr err = ::LSOpenFSRef(&fsRef, NULL);
 
1677
  return MacErrorMapper(err);
 
1678
}
 
1679
 
 
1680
 
 
1681
//*****************************************************************************
 
1682
//  nsLocalFile::nsILocalFileMac
 
1683
//*****************************************************************************
 
1684
#pragma mark -
 
1685
#pragma mark [nsILocalFileMac]
 
1686
 
 
1687
/* void initWithCFURL (in CFURLRef aCFURL); */
 
1688
NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
 
1689
{
 
1690
  NS_ENSURE_ARG(aCFURL);
 
1691
 
 
1692
  SetBaseRef(aCFURL);
 
1693
  return NS_OK;
 
1694
}
 
1695
 
 
1696
/* void initWithFSRef ([const] in FSRefPtr aFSRef); */
 
1697
NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
 
1698
{
 
1699
  NS_ENSURE_ARG(aFSRef);
 
1700
  nsresult rv = NS_ERROR_FAILURE;
 
1701
 
 
1702
  CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
 
1703
  if (newURLRef) {
 
1704
    SetBaseRef(newURLRef);
 
1705
    ::CFRelease(newURLRef);
 
1706
    rv = NS_OK;
 
1707
  }
 
1708
  return rv;
 
1709
}
 
1710
 
 
1711
/* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */
 
1712
NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec)
 
1713
{
 
1714
  NS_ENSURE_ARG(aFileSpec);
 
1715
 
 
1716
  FSRef fsRef;
 
1717
  OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef);
 
1718
  if (err == noErr)
 
1719
    return InitWithFSRef(&fsRef);
 
1720
  else if (err == fnfErr) {
 
1721
    CInfoPBRec  pBlock;
 
1722
    FSSpec parentDirSpec;
 
1723
 
 
1724
    memset(&pBlock, 0, sizeof(CInfoPBRec));
 
1725
    parentDirSpec.name[0] = 0;
 
1726
    pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum;
 
1727
    pBlock.dirInfo.ioDrDirID = aFileSpec->parID;
 
1728
    pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name;
 
1729
    pBlock.dirInfo.ioFDirIndex = -1;        //get info on parID
 
1730
    err = ::PBGetCatInfoSync(&pBlock);
 
1731
    if (err != noErr)
 
1732
      return MacErrorMapper(err);
 
1733
 
 
1734
    parentDirSpec.vRefNum = aFileSpec->vRefNum;
 
1735
    parentDirSpec.parID = pBlock.dirInfo.ioDrParID;
 
1736
    err = ::FSpMakeFSRef(&parentDirSpec, &fsRef);
 
1737
    if (err != noErr)
 
1738
      return MacErrorMapper(err);
 
1739
    HFSUniStr255 unicodeName;
 
1740
    err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName);
 
1741
    if (err != noErr)
 
1742
      return MacErrorMapper(err);
 
1743
    nsresult rv = InitWithFSRef(&fsRef);
 
1744
    if (NS_FAILED(rv))
 
1745
      return rv;
 
1746
    return Append(nsDependentString(unicodeName.unicode, unicodeName.length));
 
1747
  }
 
1748
  return MacErrorMapper(err);
 
1749
}
 
1750
 
 
1751
/* void initToAppWithCreatorCode (in OSType aAppCreator); */
 
1752
NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
 
1753
{
 
1754
  FSRef fsRef;
 
1755
  OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull);
 
1756
  if (err != noErr)
 
1757
    return MacErrorMapper(err);
 
1758
  return InitWithFSRef(&fsRef);
 
1759
}
 
1760
 
 
1761
/* CFURLRef getCFURL (); */
 
1762
NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
 
1763
{
 
1764
  NS_ENSURE_ARG_POINTER(_retval);
 
1765
  CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
 
1766
  if (whichURLRef)
 
1767
    ::CFRetain(whichURLRef);
 
1768
  *_retval = whichURLRef;
 
1769
  return whichURLRef ? NS_OK : NS_ERROR_FAILURE;
 
1770
}
 
1771
 
 
1772
/* FSRef getFSRef (); */
 
1773
NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
 
1774
{
 
1775
  NS_ENSURE_ARG_POINTER(_retval);
 
1776
  return GetFSRefInternal(*_retval);
 
1777
}
 
1778
 
 
1779
/* FSSpec getFSSpec (); */
 
1780
NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval)
 
1781
{
 
1782
  NS_ENSURE_ARG_POINTER(_retval);
 
1783
 
 
1784
  // Check we are correctly initialized.
 
1785
  CHECK_mBaseRef();
 
1786
 
 
1787
  OSErr err;
 
1788
  FSRef fsRef;
 
1789
  nsresult rv = GetFSRefInternal(fsRef);
 
1790
  if (NS_SUCCEEDED(rv)) {
 
1791
    // If the leaf node exists, things are simple.
 
1792
    err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone,
 
1793
              nsnull, nsnull, _retval, nsnull);
 
1794
    return MacErrorMapper(err);
 
1795
  }
 
1796
  else if (rv == NS_ERROR_FILE_NOT_FOUND) {
 
1797
    // If the parent of the leaf exists, make an FSSpec from that.
 
1798
    CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
 
1799
    if (!parentURLRef)
 
1800
      return NS_ERROR_FAILURE;
 
1801
 
 
1802
    err = fnfErr;
 
1803
    if (::CFURLGetFSRef(parentURLRef, &fsRef)) {
 
1804
      FSCatalogInfo catalogInfo;
 
1805
      if ((err = ::FSGetCatalogInfo(&fsRef,
 
1806
                        kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding,
 
1807
                        &catalogInfo, nsnull, nsnull, nsnull)) == noErr) {
 
1808
        nsAutoString leafName;
 
1809
        if (NS_SUCCEEDED(GetLeafName(leafName))) {
 
1810
          Str31 hfsName;
 
1811
          if ((err = ::UnicodeNameGetHFSName(leafName.Length(),
 
1812
                          leafName.get(),
 
1813
                          catalogInfo.textEncodingHint,
 
1814
                          catalogInfo.nodeID == fsRtDirID,
 
1815
                          hfsName)) == noErr)
 
1816
            err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval);
 
1817
        }
 
1818
      }
 
1819
    }
 
1820
    ::CFRelease(parentURLRef);
 
1821
    rv = MacErrorMapper(err);
 
1822
  }
 
1823
  return rv;
 
1824
}
 
1825
 
 
1826
/* readonly attribute PRInt64 fileSizeWithResFork; */
 
1827
NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
 
1828
{
 
1829
  NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
 
1830
 
 
1831
  FSRef fsRef;
 
1832
  nsresult rv = GetFSRefInternal(fsRef);
 
1833
  if (NS_FAILED(rv))
 
1834
    return rv;
 
1835
 
 
1836
  FSCatalogInfo catalogInfo;
 
1837
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
 
1838
                                 &catalogInfo, nsnull, nsnull, nsnull);
 
1839
  if (err != noErr)
 
1840
    return MacErrorMapper(err);
 
1841
 
 
1842
  *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
 
1843
  return NS_OK;
 
1844
}
 
1845
 
 
1846
/* attribute OSType fileType; */
 
1847
NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
 
1848
{
 
1849
  NS_ENSURE_ARG_POINTER(aFileType);
 
1850
 
 
1851
  FSRef fsRef;
 
1852
  nsresult rv = GetFSRefInternal(fsRef);
 
1853
  if (NS_FAILED(rv))
 
1854
    return rv;
 
1855
 
 
1856
  FinderInfo fInfo;
 
1857
  OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
 
1858
  if (err != noErr)
 
1859
    return MacErrorMapper(err);
 
1860
  *aFileType = fInfo.file.fileType;
 
1861
  return NS_OK;
 
1862
}
 
1863
 
 
1864
NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
 
1865
{
 
1866
  FSRef fsRef;
 
1867
  nsresult rv = GetFSRefInternal(fsRef);
 
1868
  if (NS_FAILED(rv))
 
1869
    return rv;
 
1870
 
 
1871
  OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType);
 
1872
  return MacErrorMapper(err);
 
1873
}
 
1874
 
 
1875
/* attribute OSType fileCreator; */
 
1876
NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator)
 
1877
{
 
1878
  NS_ENSURE_ARG_POINTER(aFileCreator);
 
1879
 
 
1880
  FSRef fsRef;
 
1881
  nsresult rv = GetFSRefInternal(fsRef);
 
1882
  if (NS_FAILED(rv))
 
1883
    return rv;
 
1884
 
 
1885
  FinderInfo fInfo;
 
1886
  OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
 
1887
  if (err != noErr)
 
1888
    return MacErrorMapper(err);
 
1889
  *aFileCreator = fInfo.file.fileCreator;
 
1890
  return NS_OK;
 
1891
}
 
1892
 
 
1893
NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator)
 
1894
{
 
1895
  FSRef fsRef;
 
1896
  nsresult rv = GetFSRefInternal(fsRef);
 
1897
  if (NS_FAILED(rv))
 
1898
    return rv;
 
1899
 
 
1900
  OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0);
 
1901
  return MacErrorMapper(err);
 
1902
}
 
1903
 
 
1904
/* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */
 
1905
NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType)
 
1906
{
 
1907
  // XXX - This should be cut from the API. Would create an evil dependency.
 
1908
  NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
1909
  return NS_ERROR_NOT_IMPLEMENTED;
 
1910
}
 
1911
 
 
1912
/* void setFileTypeAndCreatorFromExtension (in string aExtension); */
 
1913
NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension)
 
1914
{
 
1915
  // XXX - This should be cut from the API. Would create an evil dependency.
 
1916
  NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
 
1917
  return NS_ERROR_NOT_IMPLEMENTED;
 
1918
}
 
1919
 
 
1920
/* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */
 
1921
NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
 
1922
{
 
1923
  PRBool isExecutable;
 
1924
  nsresult rv = IsExecutable(&isExecutable);
 
1925
  if (NS_FAILED(rv))
 
1926
    return rv;
 
1927
  if (!isExecutable)
 
1928
    return NS_ERROR_FILE_EXECUTION_FAILED;
 
1929
 
 
1930
  FSRef appFSRef, docFSRef;
 
1931
  rv = GetFSRefInternal(appFSRef);
 
1932
  if (NS_FAILED(rv))
 
1933
    return rv;
 
1934
 
 
1935
  if (aDocToLoad) {
 
1936
    nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
 
1937
    rv = macDoc->GetFSRef(&docFSRef);
 
1938
    if (NS_FAILED(rv))
 
1939
      return rv;
 
1940
  }
 
1941
 
 
1942
  LSLaunchFlags       theLaunchFlags = kLSLaunchDefaults;
 
1943
  LSLaunchFSRefSpec   thelaunchSpec;
 
1944
 
 
1945
  if (aLaunchInBackground)
 
1946
    theLaunchFlags |= kLSLaunchDontSwitch;
 
1947
  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
 
1948
 
 
1949
  thelaunchSpec.appRef = &appFSRef;
 
1950
  if (aDocToLoad) {
 
1951
    thelaunchSpec.numDocs = 1;
 
1952
    thelaunchSpec.itemRefs = &docFSRef;
 
1953
  }
 
1954
  thelaunchSpec.launchFlags = theLaunchFlags;
 
1955
 
 
1956
  OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
 
1957
  if (err != noErr)
 
1958
    return MacErrorMapper(err);
 
1959
 
 
1960
  return NS_OK;
 
1961
}
 
1962
 
 
1963
/* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */
 
1964
NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
 
1965
{
 
1966
  nsresult rv;
 
1967
  OSErr err;
 
1968
 
 
1969
  FSRef docFSRef, appFSRef;
 
1970
  rv = GetFSRefInternal(docFSRef);
 
1971
  if (NS_FAILED(rv))
 
1972
    return rv;
 
1973
 
 
1974
  if (aAppToOpenWith) {
 
1975
    nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
 
1976
    if (!appFileMac)
 
1977
      return rv;
 
1978
 
 
1979
    PRBool isExecutable;
 
1980
    rv = appFileMac->IsExecutable(&isExecutable);
 
1981
    if (NS_FAILED(rv))
 
1982
      return rv;
 
1983
    if (!isExecutable)
 
1984
      return NS_ERROR_FILE_EXECUTION_FAILED;
 
1985
 
 
1986
    rv = appFileMac->GetFSRef(&appFSRef);
 
1987
    if (NS_FAILED(rv))
 
1988
      return rv;
 
1989
  }
 
1990
  else {
 
1991
    OSType  fileCreator;
 
1992
    rv = GetFileCreator(&fileCreator);
 
1993
    if (NS_FAILED(rv))
 
1994
      return rv;
 
1995
 
 
1996
    err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull);
 
1997
    if (err != noErr)
 
1998
      return MacErrorMapper(err);
 
1999
  }
 
2000
 
 
2001
  LSLaunchFlags       theLaunchFlags = kLSLaunchDefaults;
 
2002
  LSLaunchFSRefSpec   thelaunchSpec;
 
2003
 
 
2004
  if (aLaunchInBackground)
 
2005
  theLaunchFlags |= kLSLaunchDontSwitch;
 
2006
  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
 
2007
 
 
2008
  thelaunchSpec.appRef = &appFSRef;
 
2009
  thelaunchSpec.numDocs = 1;
 
2010
  thelaunchSpec.itemRefs = &docFSRef;
 
2011
  thelaunchSpec.launchFlags = theLaunchFlags;
 
2012
 
 
2013
  err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
 
2014
  if (err != noErr)
 
2015
    return MacErrorMapper(err);
 
2016
 
 
2017
  return NS_OK;
 
2018
}
 
2019
 
 
2020
/* boolean isPackage (); */
 
2021
NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval)
 
2022
{
 
2023
  NS_ENSURE_ARG(_retval);
 
2024
  *_retval = PR_FALSE;
 
2025
 
 
2026
  FSRef fsRef;
 
2027
  nsresult rv = GetFSRefInternal(fsRef);
 
2028
  if (NS_FAILED(rv))
 
2029
    return rv;
 
2030
 
 
2031
  FSCatalogInfo catalogInfo;
 
2032
  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo,
 
2033
                                 &catalogInfo, nsnull, nsnull, nsnull);
 
2034
  if (err != noErr)
 
2035
    return MacErrorMapper(err);
 
2036
  if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
 
2037
    FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo);
 
2038
    if ((fInfoPtr->finderFlags & kHasBundle) != 0) {
 
2039
      *_retval = PR_TRUE;
 
2040
    }
 
2041
    else {
 
2042
     // Folders ending with ".app" are also considered to
 
2043
     // be packages, even if the top-level folder doesn't have bundle set
 
2044
      nsCAutoString name;
 
2045
      if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) {
 
2046
        const char *extPtr = strrchr(name.get(), '.');
 
2047
        if (extPtr) {
 
2048
          if ((nsCRT::strcasecmp(extPtr, ".app") == 0))
 
2049
            *_retval = PR_TRUE;
 
2050
        }
 
2051
      }
 
2052
    }
 
2053
  }
 
2054
  return NS_OK;
 
2055
}
 
2056
 
 
2057
NS_IMETHODIMP
 
2058
nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
 
2059
{
 
2060
  PRBool isPackage = PR_FALSE;
 
2061
  nsresult rv = IsPackage(&isPackage);
 
2062
  if (NS_FAILED(rv) || !isPackage)
 
2063
    return NS_ERROR_FAILURE;
 
2064
 
 
2065
  nsAutoString name;
 
2066
  rv = GetLeafName(name);
 
2067
  if (NS_FAILED(rv))
 
2068
    return rv;
 
2069
 
 
2070
  PRInt32 length = name.Length();
 
2071
  if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
 
2072
    // 4 characters in ".app"
 
2073
    outBundleName = Substring(name, 0, length - 4);
 
2074
  }
 
2075
  else
 
2076
    outBundleName = name;
 
2077
 
 
2078
  return NS_OK;
 
2079
}
 
2080
 
 
2081
NS_IMETHODIMP
 
2082
nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
 
2083
{
 
2084
  nsresult rv = NS_ERROR_FAILURE;
 
2085
 
 
2086
  CFURLRef urlRef;
 
2087
  if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
 
2088
    CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
 
2089
    if (bundle) {
 
2090
      CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
 
2091
      if (bundleIdentifier)
 
2092
        rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
 
2093
 
 
2094
      ::CFRelease(bundle);
 
2095
    }
 
2096
    ::CFRelease(urlRef);
 
2097
  }
 
2098
 
 
2099
  return rv;
 
2100
}
 
2101
 
 
2102
 
 
2103
//*****************************************************************************
 
2104
//  nsLocalFile Methods
 
2105
//*****************************************************************************
 
2106
#pragma mark -
 
2107
#pragma mark [Protected Methods]
 
2108
 
 
2109
nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef)
 
2110
{
 
2111
  NS_ENSURE_ARG(aCFURLRef);
 
2112
 
 
2113
  ::CFRetain(aCFURLRef);
 
2114
  if (mBaseRef)
 
2115
    ::CFRelease(mBaseRef);
 
2116
  mBaseRef = aCFURLRef;
 
2117
 
 
2118
  mFollowLinksDirty = PR_TRUE;
 
2119
  UpdateTargetRef();
 
2120
  mCachedFSRefValid = PR_FALSE;
 
2121
  return NS_OK;
 
2122
}
 
2123
 
 
2124
nsresult nsLocalFile::UpdateTargetRef()
 
2125
{
 
2126
  // Check we are correctly initialized.
 
2127
  CHECK_mBaseRef();
 
2128
 
 
2129
  if (mFollowLinksDirty) {
 
2130
    if (mTargetRef) {
 
2131
      ::CFRelease(mTargetRef);
 
2132
      mTargetRef = nsnull;
 
2133
    }
 
2134
    if (mFollowLinks) {
 
2135
      mTargetRef = mBaseRef;
 
2136
      ::CFRetain(mTargetRef);
 
2137
 
 
2138
      FSRef fsRef;
 
2139
      if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
 
2140
        Boolean targetIsFolder, wasAliased;
 
2141
        if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/,
 
2142
            &targetIsFolder, &wasAliased) == noErr && wasAliased) {
 
2143
          ::CFRelease(mTargetRef);
 
2144
          mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef);
 
2145
          if (!mTargetRef)
 
2146
            return NS_ERROR_FAILURE;
 
2147
        }
 
2148
      }
 
2149
      mFollowLinksDirty = PR_FALSE;
 
2150
    }
 
2151
  }
 
2152
  return NS_OK;
 
2153
}
 
2154
 
 
2155
nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache)
 
2156
{
 
2157
  if (bForceUpdateCache || !mCachedFSRefValid) {
 
2158
    mCachedFSRefValid = PR_FALSE;
 
2159
    CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
 
2160
    NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
 
2161
    if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef))
 
2162
      mCachedFSRefValid = PR_TRUE;
 
2163
  }
 
2164
  if (mCachedFSRefValid) {
 
2165
    aFSRef = mCachedFSRef;
 
2166
    return NS_OK;
 
2167
  }
 
2168
  // CFURLGetFSRef only returns a Boolean for success,
 
2169
  // so we have to assume what the error was. This is
 
2170
  // the only probable cause.
 
2171
  return NS_ERROR_FILE_NOT_FOUND;
 
2172
}
 
2173
 
 
2174
nsresult nsLocalFile::GetPathInternal(nsACString& path)
 
2175
{
 
2176
  nsresult rv = NS_ERROR_FAILURE;
 
2177
 
 
2178
  CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
 
2179
  NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
 
2180
 
 
2181
  CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle);
 
2182
  if (pathStrRef) {
 
2183
    rv = CFStringReftoUTF8(pathStrRef, path);
 
2184
    ::CFRelease(pathStrRef);
 
2185
  }
 
2186
  return rv;
 
2187
}
 
2188
 
 
2189
nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir,
 
2190
                                   const nsAString& newName,
 
2191
                                   PRBool followLinks)
 
2192
{
 
2193
  // Check we are correctly initialized.
 
2194
  CHECK_mBaseRef();
 
2195
 
 
2196
  StFollowLinksState srcFollowState(*this, followLinks);
 
2197
 
 
2198
  nsresult rv;
 
2199
  OSErr err;
 
2200
  FSRef srcFSRef, newFSRef;
 
2201
 
 
2202
  rv = GetFSRefInternal(srcFSRef);
 
2203
  if (NS_FAILED(rv))
 
2204
    return rv;
 
2205
 
 
2206
  nsCOMPtr<nsIFile> newParentDir = aParentDir;
 
2207
 
 
2208
  if (!newParentDir) {
 
2209
    if (newName.IsEmpty())
 
2210
      return NS_ERROR_INVALID_ARG;
 
2211
    rv = GetParent(getter_AddRefs(newParentDir));
 
2212
    if (NS_FAILED(rv))
 
2213
      return rv;
 
2214
  }
 
2215
 
 
2216
  // If newParentDir does not exist, create it
 
2217
  PRBool exists;
 
2218
  rv = newParentDir->Exists(&exists);
 
2219
  if (NS_FAILED(rv))
 
2220
    return rv;
 
2221
  if (!exists) {
 
2222
    rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
 
2223
    if (NS_FAILED(rv))
 
2224
      return rv;
 
2225
  }
 
2226
 
 
2227
  FSRef destFSRef;
 
2228
  nsCOMPtr<nsILocalFileMac> newParentDirMac(do_QueryInterface(newParentDir));
 
2229
  if (!newParentDirMac)
 
2230
    return NS_ERROR_NO_INTERFACE;
 
2231
  rv = newParentDirMac->GetFSRef(&destFSRef);
 
2232
  if (NS_FAILED(rv))
 
2233
    return rv;
 
2234
 
 
2235
  err =
 
2236
   ::FSCopyObject(&srcFSRef, &destFSRef, newName.Length(),
 
2237
                  newName.Length() ? PromiseFlatString(newName).get() : NULL,
 
2238
                  0, kFSCatInfoNone, false, false, NULL, NULL, &newFSRef);
 
2239
 
 
2240
  return MacErrorMapper(err);
 
2241
}
 
2242
 
 
2243
const PRInt64 kMillisecsPerSec = 1000LL;
 
2244
const PRInt64 kUTCDateTimeFractionDivisor = 65535LL;
 
2245
 
 
2246
PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime)
 
2247
{
 
2248
  // Start with seconds since Jan. 1, 1904 GMT
 
2249
  PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds;
 
2250
  // Subtract to convert to NSPR epoch of 1970
 
2251
  result -= kJanuaryFirst1970Seconds;
 
2252
  // Convert to millisecs
 
2253
  result *= kMillisecsPerSec;
 
2254
  // Convert the fraction to millisecs and add it
 
2255
  result += ((PRInt64)utcTime.fraction * kMillisecsPerSec) / kUTCDateTimeFractionDivisor;
 
2256
 
 
2257
  return result;
 
2258
}
 
2259
 
 
2260
void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime)
 
2261
{
 
2262
  PRInt64 fraction = nsprTime % kMillisecsPerSec;
 
2263
  PRInt64 seconds = (nsprTime / kMillisecsPerSec) + kJanuaryFirst1970Seconds;
 
2264
  utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32);
 
2265
  utcTime.lowSeconds = (UInt32)seconds;
 
2266
  utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMillisecsPerSec);
 
2267
}
 
2268
 
 
2269
nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
 
2270
{
 
2271
  nsresult rv = NS_ERROR_FAILURE;
 
2272
  CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
 
2273
  CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
 
2274
                              kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen);
 
2275
  if (charsConverted == inStrLen) {
 
2276
#if 0 /* bird: too new? */
 
2277
    aOutStr.SetLength(usedBufLen);
 
2278
    if (aOutStr.Length() != usedBufLen)
 
2279
      return NS_ERROR_OUT_OF_MEMORY;
 
2280
    UInt8 *buffer = (UInt8*) aOutStr.BeginWriting();
 
2281
 
 
2282
    ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
 
2283
                       kCFStringEncodingUTF8, 0, false, buffer, usedBufLen, &usedBufLen);
 
2284
    rv = NS_OK;
 
2285
#else
 
2286
    nsAutoBuffer<UInt8, FILENAME_BUFFER_SIZE> buffer;
 
2287
    if (buffer.EnsureElemCapacity(usedBufLen + 1)) {
 
2288
      ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
 
2289
          kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen);
 
2290
      buffer.get()[usedBufLen] = '\0';
 
2291
      aOutStr.Assign(nsDependentCString((char*)buffer.get()));
 
2292
      rv = NS_OK;
 
2293
    }
 
2294
#endif
 
2295
  }
 
2296
  return rv;
 
2297
}
 
2298
 
 
2299
// nsIHashable
 
2300
 
 
2301
NS_IMETHODIMP
 
2302
nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult)
 
2303
{
 
2304
    return EqualsInternal(aOther, PR_FALSE, aResult);
 
2305
}
 
2306
 
 
2307
NS_IMETHODIMP
 
2308
nsLocalFile::GetHashCode(PRUint32 *aResult)
 
2309
{
 
2310
    CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
 
2311
    nsCAutoString path;
 
2312
    CFStringReftoUTF8(pathStrRef, path);
 
2313
    *aResult = HashString(path);
 
2314
    return NS_OK;
 
2315
}
 
2316
 
 
2317
//*****************************************************************************
 
2318
//  Global Functions
 
2319
//*****************************************************************************
 
2320
#pragma mark -
 
2321
#pragma mark [Global Functions]
 
2322
 
 
2323
void nsLocalFile::GlobalInit()
 
2324
{
 
2325
}
 
2326
 
 
2327
void nsLocalFile::GlobalShutdown()
 
2328
{
 
2329
}
 
2330
 
 
2331
nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result)
 
2332
{
 
2333
    nsLocalFile* file = new nsLocalFile;
 
2334
    if (file == nsnull)
 
2335
        return NS_ERROR_OUT_OF_MEMORY;
 
2336
    NS_ADDREF(file);
 
2337
 
 
2338
    file->SetFollowLinks(followLinks);
 
2339
 
 
2340
    if (!path.IsEmpty()) {
 
2341
        nsresult rv = file->InitWithPath(path);
 
2342
        if (NS_FAILED(rv)) {
 
2343
            NS_RELEASE(file);
 
2344
            return rv;
 
2345
        }
 
2346
    }
 
2347
    *result = file;
 
2348
    return NS_OK;
 
2349
}
 
2350
 
 
2351
nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result)
 
2352
{
 
2353
    return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result);
 
2354
}
 
2355
 
 
2356
nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result)
 
2357
{
 
2358
    nsLocalFile* file = new nsLocalFile();
 
2359
    if (file == nsnull)
 
2360
        return NS_ERROR_OUT_OF_MEMORY;
 
2361
    NS_ADDREF(file);
 
2362
 
 
2363
    file->SetFollowLinks(followLinks);
 
2364
 
 
2365
    nsresult rv = file->InitWithFSSpec(inSpec);
 
2366
    if (NS_FAILED(rv)) {
 
2367
        NS_RELEASE(file);
 
2368
        return rv;
 
2369
    }
 
2370
    *result = file;
 
2371
    return NS_OK;
 
2372
}
 
2373
 
 
2374
nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result)
 
2375
{
 
2376
    nsLocalFile* file = new nsLocalFile();
 
2377
    if (file == nsnull)
 
2378
        return NS_ERROR_OUT_OF_MEMORY;
 
2379
    NS_ADDREF(file);
 
2380
 
 
2381
    file->SetFollowLinks(aFollowLinks);
 
2382
 
 
2383
    nsresult rv = file->InitWithFSRef(aFSRef);
 
2384
    if (NS_FAILED(rv)) {
 
2385
        NS_RELEASE(file);
 
2386
        return rv;
 
2387
    }
 
2388
    *result = file;
 
2389
    return NS_OK;
 
2390
}
 
2391
 
 
2392
//*****************************************************************************
 
2393
//  Static Functions
 
2394
//*****************************************************************************
 
2395
 
 
2396
static nsresult MacErrorMapper(OSErr inErr)
 
2397
{
 
2398
    nsresult outErr;
 
2399
 
 
2400
    switch (inErr)
 
2401
    {
 
2402
        case noErr:
 
2403
            outErr = NS_OK;
 
2404
            break;
 
2405
 
 
2406
        case fnfErr:
 
2407
            outErr = NS_ERROR_FILE_NOT_FOUND;
 
2408
            break;
 
2409
 
 
2410
        case dupFNErr:
 
2411
            outErr = NS_ERROR_FILE_ALREADY_EXISTS;
 
2412
            break;
 
2413
 
 
2414
        case dskFulErr:
 
2415
            outErr = NS_ERROR_FILE_DISK_FULL;
 
2416
            break;
 
2417
 
 
2418
        case fLckdErr:
 
2419
            outErr = NS_ERROR_FILE_IS_LOCKED;
 
2420
            break;
 
2421
 
 
2422
        // Can't find good map for some
 
2423
        case bdNamErr:
 
2424
            outErr = NS_ERROR_FAILURE;
 
2425
            break;
 
2426
 
 
2427
        default:
 
2428
            outErr = NS_ERROR_FAILURE;
 
2429
            break;
 
2430
    }
 
2431
    return outErr;
 
2432
}
 
2433
 
 
2434
static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn)
 
2435
{
 
2436
  ProcessInfoRec info;
 
2437
  OSErr err = noErr;
 
2438
 
 
2439
  outPsn.highLongOfPSN = 0;
 
2440
  outPsn.lowLongOfPSN  = kNoProcess;
 
2441
 
 
2442
  while (PR_TRUE)
 
2443
  {
 
2444
    err = ::GetNextProcess(&outPsn);
 
2445
    if (err == procNotFound)
 
2446
      break;
 
2447
    if (err != noErr)
 
2448
      return err;
 
2449
    info.processInfoLength = sizeof(ProcessInfoRec);
 
2450
    info.processName = nil;
 
2451
    info.processAppSpec = nil;
 
2452
    err = ::GetProcessInformation(&outPsn, &info);
 
2453
    if (err != noErr)
 
2454
      return err;
 
2455
 
 
2456
    if (info.processSignature == aAppSig)
 
2457
      return noErr;
 
2458
  }
 
2459
  return procNotFound;
 
2460
}
 
2461
 
 
2462
// Convert a UTF-8 string to a UTF-16 string while normalizing to
 
2463
// Normalization Form C (composed Unicode). We need this because
 
2464
// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode)
 
2465
// while most other OS', server-side programs usually expect NFC.
 
2466
 
 
2467
typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm);
 
2468
static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult)
 
2469
{
 
2470
    static PRBool sChecked = PR_FALSE;
 
2471
    static UnicodeNormalizer sUnicodeNormalizer = NULL;
 
2472
 
 
2473
    // CFStringNormalize was not introduced until Mac OS 10.2
 
2474
    if (!sChecked) {
 
2475
        CFBundleRef carbonBundle =
 
2476
            CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon"));
 
2477
        if (carbonBundle)
 
2478
            sUnicodeNormalizer = (UnicodeNormalizer)
 
2479
                ::CFBundleGetFunctionPointerForName(carbonBundle,
 
2480
                                                    CFSTR("CFStringNormalize"));
 
2481
        sChecked = PR_TRUE;
 
2482
    }
 
2483
 
 
2484
    if (!sUnicodeNormalizer) {  // OS X 10.2 or earlier
 
2485
        CopyUTF8toUTF16(aSrc, aResult);
 
2486
        return;
 
2487
    }
 
2488
 
 
2489
    const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc);
 
2490
 
 
2491
    // The number of 16bit code units in a UTF-16 string will never be
 
2492
    // larger than the number of bytes in the corresponding UTF-8 string.
 
2493
    CFMutableStringRef inStr =
 
2494
        ::CFStringCreateMutable(NULL, inFlatSrc.Length());
 
2495
 
 
2496
    if (!inStr) {
 
2497
        CopyUTF8toUTF16(aSrc, aResult);
 
2498
        return;
 
2499
    }
 
2500
 
 
2501
    ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8);
 
2502
 
 
2503
    sUnicodeNormalizer(inStr, kCFStringNormalizationFormC);
 
2504
 
 
2505
    CFIndex length = CFStringGetLength(inStr);
 
2506
    const UniChar* chars = CFStringGetCharactersPtr(inStr);
 
2507
 
 
2508
    if (chars)
 
2509
        aResult.Assign(chars, length);
 
2510
    else {
 
2511
        nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
 
2512
        if (!buffer.EnsureElemCapacity(length))
 
2513
            CopyUTF8toUTF16(aSrc, aResult);
 
2514
        else {
 
2515
            CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get());
 
2516
            aResult.Assign(buffer.get(), length);
 
2517
        }
 
2518
    }
 
2519
    CFRelease(inStr);
 
2520
}