~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpcom/io/nsLocalFileWin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/*
 
3
 * The contents of this file are subject to the Netscape Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/NPL/
 
7
 *
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 *
 
13
 * The Original Code is Mozilla Communicator client code,
 
14
 * released March 31, 1998.
 
15
 *
 
16
 * The Initial Developer of the Original Code is Netscape Communications
 
17
 * Corporation.  Portions created by Netscape are
 
18
 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
 
19
 * Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 *     Doug Turner <dougt@netscape.com>
 
23
 */
 
24
 
 
25
 
 
26
#include "nsCOMPtr.h"
 
27
#include "nsMemory.h"
 
28
 
 
29
#include "nsLocalFile.h"
 
30
#include "nsNativeCharsetUtils.h"
 
31
 
 
32
#include "nsISimpleEnumerator.h"
 
33
#include "nsIComponentManager.h"
 
34
#include "prtypes.h"
 
35
#include "prio.h"
 
36
 
 
37
#include "nsXPIDLString.h"
 
38
#include "nsReadableUtils.h"
 
39
 
 
40
#include <direct.h>
 
41
#include <windows.h>
 
42
 
 
43
#include "shellapi.h"
 
44
#include "shlguid.h"
 
45
 
 
46
#include  <io.h>
 
47
#include  <stdio.h>
 
48
#include  <stdlib.h>
 
49
#include  <mbstring.h>
 
50
 
 
51
#include "nsXPIDLString.h"
 
52
#include "prproces.h"
 
53
#include "nsITimelineService.h"
 
54
 
 
55
#include "nsAutoLock.h"
 
56
 
 
57
// _mbsstr isn't declared in w32api headers but it's there in the libs
 
58
#ifdef __MINGW32__
 
59
extern "C" {
 
60
unsigned char *_mbsstr( const unsigned char *str,
 
61
                        const unsigned char *substr );
 
62
}
 
63
#endif
 
64
 
 
65
//----------------------------------------------------------------------------
 
66
// short cut resolver
 
67
//----------------------------------------------------------------------------
 
68
 
 
69
class ShortcutResolver
 
70
{
 
71
public:
 
72
    ShortcutResolver();
 
73
    // nonvirtual since we're not subclassed
 
74
    ~ShortcutResolver();
 
75
 
 
76
    nsresult Init();
 
77
    nsresult Resolve(const WCHAR* in, char* out);
 
78
 
 
79
private:
 
80
    PRLock*       mLock;
 
81
    IPersistFile* mPersistFile;
 
82
    IShellLink*   mShellLink;
 
83
};
 
84
 
 
85
ShortcutResolver::ShortcutResolver()
 
86
{
 
87
    mLock = nsnull;
 
88
    mPersistFile = nsnull;
 
89
    mShellLink   = nsnull;
 
90
}
 
91
 
 
92
ShortcutResolver::~ShortcutResolver()
 
93
{
 
94
    if (mLock)
 
95
        PR_DestroyLock(mLock);
 
96
 
 
97
    // Release the pointer to the IPersistFile interface.
 
98
    if (mPersistFile)
 
99
        mPersistFile->Release();
 
100
 
 
101
    // Release the pointer to the IShellLink interface.
 
102
    if(mShellLink)
 
103
        mShellLink->Release();
 
104
 
 
105
    CoUninitialize();
 
106
}
 
107
 
 
108
nsresult
 
109
ShortcutResolver::Init()
 
110
{
 
111
    CoInitialize(NULL);  // FIX: we should probably move somewhere higher up during startup
 
112
 
 
113
    mLock = PR_NewLock();
 
114
    if (!mLock)
 
115
        return NS_ERROR_FAILURE;
 
116
 
 
117
    HRESULT hres = CoCreateInstance(CLSID_ShellLink,
 
118
                                    NULL,
 
119
                                    CLSCTX_INPROC_SERVER,
 
120
                                    IID_IShellLink,
 
121
                                    (void**)&mShellLink);
 
122
    if (SUCCEEDED(hres))
 
123
    {
 
124
        // Get a pointer to the IPersistFile interface.
 
125
        hres = mShellLink->QueryInterface(IID_IPersistFile, (void**)&mPersistFile);
 
126
    }
 
127
 
 
128
    if (mPersistFile == nsnull || mShellLink == nsnull)
 
129
        return NS_ERROR_FAILURE;
 
130
 
 
131
    return NS_OK;
 
132
}
 
133
 
 
134
// |out| must be an allocated buffer of size MAX_PATH
 
135
nsresult
 
136
ShortcutResolver::Resolve(const WCHAR* in, char* out)
 
137
{
 
138
    nsAutoLock lock(mLock);
 
139
 
 
140
    // see if we can Load the path.
 
141
    HRESULT hres = mPersistFile->Load(in, STGM_READ);
 
142
 
 
143
    if (FAILED(hres))
 
144
        return NS_ERROR_FAILURE;
 
145
 
 
146
    // Resolve the link.
 
147
    hres = mShellLink->Resolve(nsnull, SLR_NO_UI );
 
148
 
 
149
    if (FAILED(hres))
 
150
        return NS_ERROR_FAILURE;
 
151
 
 
152
    WIN32_FIND_DATA wfd;
 
153
    // Get the path to the link target.
 
154
    hres = mShellLink->GetPath( out, MAX_PATH, &wfd, SLGP_UNCPRIORITY );
 
155
    if (FAILED(hres))
 
156
        return NS_ERROR_FAILURE;
 
157
    return NS_OK;
 
158
}
 
159
 
 
160
static ShortcutResolver * gResolver = nsnull;
 
161
 
 
162
static nsresult NS_CreateShortcutResolver()
 
163
{
 
164
    gResolver = new ShortcutResolver();
 
165
    if (!gResolver)
 
166
        return NS_ERROR_OUT_OF_MEMORY;
 
167
 
 
168
    return gResolver->Init();
 
169
}
 
170
 
 
171
static void NS_DestroyShortcutResolver()
 
172
{
 
173
    delete gResolver;
 
174
    gResolver = nsnull;
 
175
}
 
176
 
 
177
 
 
178
//-----------------------------------------------------------------------------
 
179
// static helper functions
 
180
//-----------------------------------------------------------------------------
 
181
 
 
182
// certainly not all the error that can be
 
183
// encountered, but many of them common ones
 
184
static nsresult ConvertWinError(DWORD winErr)
 
185
{
 
186
    nsresult rv;
 
187
 
 
188
    switch (winErr)
 
189
    {
 
190
        case ERROR_FILE_NOT_FOUND:
 
191
        case ERROR_PATH_NOT_FOUND:
 
192
        case ERROR_INVALID_DRIVE:
 
193
            rv = NS_ERROR_FILE_NOT_FOUND;
 
194
            break;
 
195
        case ERROR_ACCESS_DENIED:
 
196
        case ERROR_NOT_SAME_DEVICE:
 
197
            rv = NS_ERROR_FILE_ACCESS_DENIED;
 
198
            break;
 
199
        case ERROR_NOT_ENOUGH_MEMORY:
 
200
        case ERROR_INVALID_BLOCK:
 
201
        case ERROR_INVALID_HANDLE:
 
202
        case ERROR_ARENA_TRASHED:
 
203
            rv = NS_ERROR_OUT_OF_MEMORY;
 
204
            break;
 
205
        case ERROR_CURRENT_DIRECTORY:
 
206
            rv = NS_ERROR_FILE_DIR_NOT_EMPTY;
 
207
            break;
 
208
        case ERROR_WRITE_PROTECT:
 
209
            rv = NS_ERROR_FILE_READ_ONLY;
 
210
            break;
 
211
        case ERROR_HANDLE_DISK_FULL:
 
212
            rv = NS_ERROR_FILE_TOO_BIG;
 
213
            break;
 
214
        case ERROR_FILE_EXISTS:
 
215
        case ERROR_ALREADY_EXISTS:
 
216
        case ERROR_CANNOT_MAKE:
 
217
            rv = NS_ERROR_FILE_ALREADY_EXISTS;
 
218
            break;
 
219
        case 0:
 
220
            rv = NS_OK;
 
221
        default:
 
222
            rv = NS_ERROR_FAILURE;
 
223
    }
 
224
    return rv;
 
225
}
 
226
 
 
227
 
 
228
static void
 
229
myLL_II2L(PRInt32 hi, PRInt32 lo, PRInt64 *result)
 
230
{
 
231
    PRInt64 a64, b64;  // probably could have been done with
 
232
                       // only one PRInt64, but these are macros,
 
233
                       // and I am a wimp.
 
234
 
 
235
    // put hi in the low bits of a64.
 
236
    LL_I2L(a64, hi);
 
237
    // now shift it to the upperbit and place it the result in result
 
238
    LL_SHL(b64, a64, 32);
 
239
    // now put the low bits on by adding them to the result.
 
240
    LL_ADD(*result, b64, lo);
 
241
}
 
242
 
 
243
 
 
244
static void
 
245
myLL_L2II(PRInt64 result, PRInt32 *hi, PRInt32 *lo )
 
246
{
 
247
    PRInt64 a64, b64;  // probably could have been done with
 
248
                       // only one PRInt64, but these are macros,
 
249
                       // and I am a wimp.
 
250
 
 
251
    // shift the hi word to the low word, then push it into a long.
 
252
    LL_SHR(a64, result, 32);
 
253
    LL_L2I(*hi, a64);
 
254
 
 
255
    // shift the low word to the hi word first, then shift it back.
 
256
    LL_SHL(b64, result, 32);
 
257
    LL_SHR(a64, b64, 32);
 
258
    LL_L2I(*lo, a64);
 
259
}
 
260
 
 
261
static PRBool
 
262
IsShortcut(const char* workingPath, int filePathLen)
 
263
{
 
264
    // XXX this is badly broken!!
 
265
    // XXX consider "C:\FOO.LNK"
 
266
    // XXX consider "C:\foo.lnkx\bar.lnk"
 
267
 
 
268
    // check to see if it is shortcut, i.e., it has ".lnk" in it
 
269
    unsigned char* dest = _mbsstr((unsigned char*)workingPath,
 
270
                                  (unsigned char*)".lnk");
 
271
    if (!dest)
 
272
        return PR_FALSE;
 
273
 
 
274
    // find index of ".lnk"
 
275
    int result = (int)(dest - (unsigned char*)workingPath);
 
276
 
 
277
    // if ".lnk" is not at the leaf of this path, we need to make sure the
 
278
    // next char after ".lnk" is a '\\'. e.g. "c:\\foo.lnk\\a.html" is valid,
 
279
    // whereas "c:\\foo.lnkx" is not.
 
280
    if (result + 4 < filePathLen)
 
281
    {
 
282
        if (workingPath[result + 4] != '\\')
 
283
            return PR_FALSE;
 
284
    }
 
285
    return PR_TRUE;
 
286
}
 
287
 
 
288
//-----------------------------------------------------------------------------
 
289
// nsDirEnumerator
 
290
//-----------------------------------------------------------------------------
 
291
 
 
292
class nsDirEnumerator : public nsISimpleEnumerator
 
293
{
 
294
    public:
 
295
 
 
296
        NS_DECL_ISUPPORTS
 
297
 
 
298
        nsDirEnumerator() : mDir(nsnull)
 
299
        {
 
300
        }
 
301
 
 
302
        nsresult Init(nsILocalFile* parent)
 
303
        {
 
304
            nsCAutoString filepath;
 
305
            parent->GetNativeTarget(filepath);
 
306
 
 
307
            if (filepath.IsEmpty())
 
308
            {
 
309
                parent->GetNativePath(filepath);
 
310
            }
 
311
 
 
312
            if (filepath.IsEmpty())
 
313
            {
 
314
                return NS_ERROR_UNEXPECTED;
 
315
            }
 
316
 
 
317
            mDir = PR_OpenDir(filepath.get());
 
318
            if (mDir == nsnull)    // not a directory?
 
319
                return NS_ERROR_FAILURE;
 
320
 
 
321
            mParent = parent;
 
322
            return NS_OK;
 
323
        }
 
324
 
 
325
        NS_IMETHOD HasMoreElements(PRBool *result)
 
326
        {
 
327
            nsresult rv;
 
328
            if (mNext == nsnull && mDir)
 
329
            {
 
330
                PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH);
 
331
                if (entry == nsnull)
 
332
                {
 
333
                    // end of dir entries
 
334
 
 
335
                    PRStatus status = PR_CloseDir(mDir);
 
336
                    if (status != PR_SUCCESS)
 
337
                        return NS_ERROR_FAILURE;
 
338
                    mDir = nsnull;
 
339
 
 
340
                    *result = PR_FALSE;
 
341
                    return NS_OK;
 
342
                }
 
343
 
 
344
                nsCOMPtr<nsIFile> file;
 
345
                rv = mParent->Clone(getter_AddRefs(file));
 
346
                if (NS_FAILED(rv))
 
347
                    return rv;
 
348
 
 
349
                rv = file->AppendNative(nsDependentCString(entry->name));
 
350
                if (NS_FAILED(rv))
 
351
                    return rv;
 
352
 
 
353
                // make sure the thing exists.  If it does, try the next one.
 
354
                PRBool exists;
 
355
                rv = file->Exists(&exists);
 
356
                if (NS_FAILED(rv) || !exists)
 
357
                {
 
358
                    return HasMoreElements(result);
 
359
                }
 
360
 
 
361
                mNext = do_QueryInterface(file);
 
362
            }
 
363
            *result = mNext != nsnull;
 
364
            return NS_OK;
 
365
        }
 
366
 
 
367
        NS_IMETHOD GetNext(nsISupports **result)
 
368
        {
 
369
            nsresult rv;
 
370
            PRBool hasMore;
 
371
            rv = HasMoreElements(&hasMore);
 
372
            if (NS_FAILED(rv)) return rv;
 
373
 
 
374
            *result = mNext;        // might return nsnull
 
375
            NS_IF_ADDREF(*result);
 
376
 
 
377
            mNext = nsnull;
 
378
            return NS_OK;
 
379
        }
 
380
 
 
381
        // dtor can be non-virtual since there are no subclasses, but must be
 
382
        // public to use the class on the stack.
 
383
        ~nsDirEnumerator()
 
384
        {
 
385
            if (mDir)
 
386
            {
 
387
                PRStatus status = PR_CloseDir(mDir);
 
388
                NS_ASSERTION(status == PR_SUCCESS, "close failed");
 
389
            }
 
390
        }
 
391
 
 
392
    protected:
 
393
        PRDir*                  mDir;
 
394
        nsCOMPtr<nsILocalFile>  mParent;
 
395
        nsCOMPtr<nsILocalFile>  mNext;
 
396
};
 
397
 
 
398
NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator)
 
399
 
 
400
 
 
401
//-----------------------------------------------------------------------------
 
402
// nsLocalFile <public>
 
403
//-----------------------------------------------------------------------------
 
404
 
 
405
nsLocalFile::nsLocalFile()
 
406
{
 
407
    mLastResolution = PR_FALSE;
 
408
    mFollowSymlinks = PR_FALSE;
 
409
    MakeDirty();
 
410
}
 
411
 
 
412
NS_METHOD
 
413
nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
 
414
{
 
415
    NS_ENSURE_ARG_POINTER(aInstancePtr);
 
416
    NS_ENSURE_NO_AGGREGATION(outer);
 
417
 
 
418
    nsLocalFile* inst = new nsLocalFile();
 
419
    if (inst == NULL)
 
420
        return NS_ERROR_OUT_OF_MEMORY;
 
421
 
 
422
    nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
 
423
    if (NS_FAILED(rv))
 
424
    {
 
425
        delete inst;
 
426
        return rv;
 
427
    }
 
428
    return NS_OK;
 
429
}
 
430
 
 
431
 
 
432
//-----------------------------------------------------------------------------
 
433
// nsLocalFile::nsISupports
 
434
//-----------------------------------------------------------------------------
 
435
 
 
436
NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile)
 
437
 
 
438
 
 
439
//-----------------------------------------------------------------------------
 
440
// nsLocalFile <private>
 
441
//-----------------------------------------------------------------------------
 
442
 
 
443
nsLocalFile::nsLocalFile(const nsLocalFile& other)
 
444
  : mDirty(other.mDirty)
 
445
  , mLastResolution(other.mLastResolution)
 
446
  , mFollowSymlinks(other.mFollowSymlinks)
 
447
  , mWorkingPath(other.mWorkingPath)
 
448
  , mResolvedPath(other.mResolvedPath)
 
449
  , mFileInfo64(other.mFileInfo64)
 
450
{
 
451
}
 
452
 
 
453
// ResolvePath
 
454
//  this function will walk the native path of |this| resolving any symbolic
 
455
//  links found.  The new resulting path will be placed into mResolvedPath.
 
456
nsresult
 
457
nsLocalFile::ResolvePath(const char* workingPath, PRBool resolveTerminal, char** resolvedPath)
 
458
{
 
459
 
 
460
    nsresult rv = NS_OK;
 
461
    PRBool isDir = PR_FALSE;
 
462
 
 
463
    // check to see if it is shortcut, i.e., it has ".lnk" in it
 
464
    int filePathLen = strlen(workingPath);
 
465
    PRBool isShortcut = IsShortcut(workingPath, filePathLen);
 
466
    if (!isShortcut)
 
467
        return NS_ERROR_FILE_INVALID_PATH;
 
468
 
 
469
#ifdef DEBUG_dougt
 
470
    printf("localfile - resolving symlink\n");
 
471
#endif
 
472
 
 
473
    // Get the native path for |this|
 
474
    // allocate extra bytes incase we need to append '\\' and '\0' to the
 
475
    // workingPath, if it is just a drive letter and a colon
 
476
    char *filePath = (char *) nsMemory::Alloc(filePathLen+2);
 
477
 
 
478
    if (!filePath)
 
479
        return NS_ERROR_NULL_POINTER;
 
480
 
 
481
    memcpy(filePath, workingPath, filePathLen + 1);
 
482
 
 
483
    // We are going to walk the native file path
 
484
    // and stop at each slash.  For each partial
 
485
    // path (the string to the left of the slash)
 
486
    // we will check to see if it is a shortcut.
 
487
    // if it is, we will resolve it and continue
 
488
    // with that resolved path.
 
489
 
 
490
    // Get the first slash.
 
491
    unsigned char* slash = _mbschr((unsigned char*) filePath, '\\');
 
492
 
 
493
    if (slash == nsnull)
 
494
    {
 
495
        if (nsCRT::IsAsciiAlpha(filePath[0]) && filePath[1] == ':' && filePath[2] == '\0')
 
496
        {
 
497
            // we have a drive letter and a colon (eg 'c:'
 
498
            // this is resolve already
 
499
            filePath[filePathLen] = '\\';
 
500
            filePath[filePathLen+1] = '\0';
 
501
 
 
502
            *resolvedPath = filePath;
 
503
            return NS_OK;
 
504
        }
 
505
        else
 
506
        {
 
507
            nsMemory::Free(filePath);
 
508
            return NS_ERROR_FILE_INVALID_PATH;
 
509
        }
 
510
    }
 
511
 
 
512
 
 
513
    // We really cant have just a drive letter as
 
514
    // a shortcut, so we will skip the first '\\'
 
515
    slash = _mbschr(++slash, '\\');
 
516
 
 
517
    while (slash || resolveTerminal)
 
518
    {
 
519
        // Change the slash into a null so that
 
520
        // we can use the partial path. It is is
 
521
        // null, we know it is the terminal node.
 
522
        if (slash)
 
523
        {
 
524
            *slash = '\0';
 
525
        }
 
526
        else if (resolveTerminal)
 
527
        {
 
528
            // this is our last time in this loop.
 
529
            // set loop condition to false
 
530
            resolveTerminal = PR_FALSE;
 
531
        }
 
532
        else
 
533
        {
 
534
            // something is wrong.  we should not have
 
535
            // both slash being null and resolveTerminal
 
536
            // not set!
 
537
            nsMemory::Free(filePath);
 
538
            return NS_ERROR_NULL_POINTER;
 
539
        }
 
540
 
 
541
        // check to see the file is a shortcut by the magic .lnk extension.
 
542
        size_t offset = strlen(filePath) - 4;
 
543
        if ((offset > 0) && (strnicmp( (filePath + offset), ".lnk", 4) == 0))
 
544
        {
 
545
            nsAutoString ucsBuf;
 
546
            NS_CopyNativeToUnicode(nsDependentCString(filePath), ucsBuf);
 
547
            char *temp = (char*) nsMemory::Alloc( MAX_PATH );
 
548
            if (temp == nsnull)
 
549
            {
 
550
                nsMemory::Free(filePath);
 
551
                return NS_ERROR_NULL_POINTER;
 
552
            }
 
553
 
 
554
            if (gResolver)
 
555
                rv = gResolver->Resolve(ucsBuf.get(), temp);
 
556
            else
 
557
                rv = NS_ERROR_FAILURE;
 
558
 
 
559
            if (NS_SUCCEEDED(rv))
 
560
            {
 
561
                // found a new path.
 
562
 
 
563
                // addend a slash on it since it does not come out of GetPath()
 
564
                // with one only if it is a directory.  If it is not a directory
 
565
                // and there is more to append, than we have a problem.
 
566
 
 
567
                struct stat st;
 
568
                int statrv = stat(temp, &st);
 
569
 
 
570
                if (0 == statrv && (_S_IFDIR & st.st_mode))
 
571
                {
 
572
                    // For root directory slash is already appended
 
573
                    // XXX not multibyte safe
 
574
                    if (temp[strlen(temp) - 1] != '\\')
 
575
                       strcat(temp, "\\");
 
576
 
 
577
                    isDir = PR_TRUE;
 
578
                }
 
579
 
 
580
                if (slash)
 
581
                {
 
582
                    // save where we left off.
 
583
                    char *carot= (temp + strlen(temp) -1 );
 
584
 
 
585
                    // append all the stuff that we have not done.
 
586
                    _mbscat((unsigned char*)temp, ++slash);
 
587
 
 
588
                    slash = (unsigned char*)carot;
 
589
                }
 
590
 
 
591
                nsMemory::Free(filePath);
 
592
                filePath = temp;
 
593
 
 
594
            }
 
595
            else
 
596
            {
 
597
                // could not resolve shortcut.  Return error;
 
598
                nsMemory::Free(filePath);
 
599
                return NS_ERROR_FILE_INVALID_PATH;
 
600
            }
 
601
        }
 
602
        if (slash)
 
603
        {
 
604
            *slash = '\\';
 
605
            ++slash;
 
606
            slash = _mbschr(slash, '\\');
 
607
        }
 
608
    }
 
609
 
 
610
    // kill any trailing separator
 
611
    char* temp = filePath;
 
612
    int len = strlen(temp) - 1;
 
613
    if((temp[len] == '\\') && (!isDir))
 
614
        temp[len] = '\0';
 
615
 
 
616
    *resolvedPath = filePath;
 
617
    return rv;
 
618
}
 
619
 
 
620
nsresult
 
621
nsLocalFile::ResolveAndStat(PRBool resolveTerminal)
 
622
{
 
623
    if (!mDirty && mLastResolution == resolveTerminal)
 
624
    {
 
625
        return NS_OK;
 
626
    }
 
627
    mLastResolution = resolveTerminal;
 
628
    mResolvedPath.Assign(mWorkingPath);  //until we know better.
 
629
 
 
630
    // First we will see if the workingPath exists.  If it does, then we
 
631
    // can simply use that as the resolved path.  This simplification can
 
632
    // be done on windows cause its symlinks (shortcuts) use the .lnk
 
633
    // file extension.
 
634
 
 
635
    char temp[4];
 
636
    const char* workingFilePath = mWorkingPath.get();
 
637
    const char* nsprPath = workingFilePath;
 
638
 
 
639
    if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') {
 
640
        temp[0] = workingFilePath[0];
 
641
        temp[1] = workingFilePath[1];
 
642
        temp[2] = '\\';
 
643
        temp[3] = '\0';
 
644
        nsprPath = temp;
 
645
    }
 
646
 
 
647
    PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64);
 
648
    if ( status == PR_SUCCESS )
 
649
    {
 
650
        if (!resolveTerminal)
 
651
        {
 
652
            mDirty = PR_FALSE;
 
653
            return NS_OK;
 
654
        }
 
655
 
 
656
        // check to see that this is shortcut, i.e., the leaf is ".lnk"
 
657
        // if the length < 4, then it's not a link.
 
658
 
 
659
        int pathLen = strlen(workingFilePath);
 
660
        const char* leaf = workingFilePath + pathLen - 4;
 
661
 
 
662
        // if we found the file and we are not following symlinks, then return success.
 
663
 
 
664
        if (!mFollowSymlinks || pathLen < 4 || (stricmp(leaf, ".lnk") != 0))
 
665
        {
 
666
            mDirty = PR_FALSE;
 
667
            return NS_OK;
 
668
        }
 
669
    }
 
670
 
 
671
    if (!mFollowSymlinks)
 
672
        return NS_ERROR_FILE_NOT_FOUND;  // if we are not resolving, we just give up here.
 
673
 
 
674
    nsresult result;
 
675
 
 
676
    // okay, something is wrong with the working path.  We will try to resolve it.
 
677
 
 
678
    char *resolvePath;
 
679
 
 
680
    result = ResolvePath(workingFilePath, resolveTerminal, &resolvePath);
 
681
    if (NS_FAILED(result))
 
682
       return NS_ERROR_FILE_NOT_FOUND;
 
683
 
 
684
    mResolvedPath.Assign(resolvePath);
 
685
    nsMemory::Free(resolvePath);
 
686
 
 
687
    status = PR_GetFileInfo64(mResolvedPath.get(), &mFileInfo64);
 
688
 
 
689
    if ( status == PR_SUCCESS )
 
690
        mDirty = PR_FALSE;
 
691
    else
 
692
        result = NS_ERROR_FILE_NOT_FOUND;
 
693
 
 
694
    return result;
 
695
}
 
696
 
 
697
 
 
698
//-----------------------------------------------------------------------------
 
699
// nsLocalFile::nsIFile,nsILocalFile
 
700
//-----------------------------------------------------------------------------
 
701
 
 
702
NS_IMETHODIMP
 
703
nsLocalFile::Clone(nsIFile **file)
 
704
{
 
705
    // Just copy-construct ourselves
 
706
    *file = new nsLocalFile(*this);
 
707
    if (!*file)
 
708
      return NS_ERROR_OUT_OF_MEMORY;
 
709
 
 
710
    NS_ADDREF(*file);
 
711
    
 
712
    return NS_OK;
 
713
}
 
714
 
 
715
NS_IMETHODIMP
 
716
nsLocalFile::InitWithNativePath(const nsACString &filePath)
 
717
{
 
718
    MakeDirty();
 
719
 
 
720
    nsACString::const_iterator begin, end;
 
721
    filePath.BeginReading(begin);
 
722
    filePath.EndReading(end);
 
723
 
 
724
    // input string must not be empty
 
725
    if (begin == end)
 
726
        return NS_ERROR_FAILURE;
 
727
 
 
728
    char firstChar = *begin;
 
729
    char secondChar = *(++begin);
 
730
 
 
731
    // just do a sanity check.  if it has any forward slashes, it is not a Native path
 
732
    // on windows.  Also, it must have a colon at after the first char.
 
733
 
 
734
    char *path = nsnull;
 
735
    PRInt32 pathLen = 0;
 
736
 
 
737
    if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) ||  // normal path
 
738
         ( (firstChar == '\\') && (secondChar == '\\') ) )  // network path
 
739
    {
 
740
        // This is a native path
 
741
        path = ToNewCString(filePath);
 
742
        pathLen = filePath.Length();
 
743
    }
 
744
 
 
745
    if (path == nsnull)
 
746
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
747
 
 
748
    // kill any trailing '\' provided it isn't the second char of DBCS
 
749
    PRInt32 len = pathLen - 1;
 
750
    if (path[len] == '\\' && (!::IsDBCSLeadByte(path[len-1]) ||
 
751
                _mbsrchr((const unsigned char *)path, '\\') == (const unsigned char *)path+len))
 
752
    {
 
753
        path[len] = '\0';
 
754
        pathLen = len;
 
755
    }
 
756
 
 
757
    mWorkingPath.Adopt(path, pathLen);
 
758
    return NS_OK;
 
759
}
 
760
 
 
761
NS_IMETHODIMP
 
762
nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
 
763
{
 
764
    // check to see if it is shortcut, i.e., it has ".lnk" in it
 
765
    PRBool isShortcut = IsShortcut(mWorkingPath.get(), mWorkingPath.Length());
 
766
 
 
767
    if (!isShortcut && mDirty)
 
768
    {
 
769
        // we will optimize here. If we are not a shortcut and we are opening
 
770
        // a file and we are still dirty, assume that the working path is vaild
 
771
        // and try to open it. The working path will be different from its
 
772
        // resolved path for a shortcut file.
 
773
        // If it does work, get the stat info via the file descriptor
 
774
        mResolvedPath.Assign(mWorkingPath);
 
775
        *_retval = PR_Open(mResolvedPath.get(), flags, mode);
 
776
        if (*_retval)
 
777
        {
 
778
            PRStatus status = PR_GetOpenFileInfo64(*_retval, &mFileInfo64);
 
779
            if (status == PR_SUCCESS)
 
780
            {
 
781
                mDirty = PR_FALSE;
 
782
                mLastResolution = PR_TRUE;
 
783
            }
 
784
            else
 
785
                NS_ERROR("FileInfo64 invalid while PR_Open succeeded.");
 
786
            return NS_OK;
 
787
        }
 
788
    }
 
789
 
 
790
    nsresult rv = ResolveAndStat(PR_TRUE);
 
791
    if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
 
792
        return rv;
 
793
 
 
794
    *_retval = PR_Open(mResolvedPath.get(), flags, mode);
 
795
 
 
796
    if (*_retval)
 
797
        return NS_OK;
 
798
 
 
799
    return NS_ErrorAccordingToNSPR();
 
800
}
 
801
 
 
802
 
 
803
NS_IMETHODIMP
 
804
nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval)
 
805
{
 
806
    nsresult rv = ResolveAndStat(PR_TRUE);
 
807
    if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
 
808
        return rv;
 
809
 
 
810
    *_retval = fopen(mResolvedPath.get(), mode);
 
811
 
 
812
    if (*_retval)
 
813
        return NS_OK;
 
814
 
 
815
    return NS_ERROR_FAILURE;
 
816
}
 
817
 
 
818
 
 
819
 
 
820
NS_IMETHODIMP
 
821
nsLocalFile::Create(PRUint32 type, PRUint32 attributes)
 
822
{
 
823
    if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
 
824
        return NS_ERROR_FILE_UNKNOWN_TYPE;
 
825
 
 
826
    nsresult rv = ResolveAndStat(PR_FALSE);
 
827
    if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
 
828
        return rv;
 
829
 
 
830
    // create directories to target
 
831
    //
 
832
    // A given local file can be either one of these forms:
 
833
    //
 
834
    //   - normal:    X:\some\path\on\this\drive
 
835
    //                       ^--- start here
 
836
    //
 
837
    //   - UNC path:  \\machine\volume\some\path\on\this\drive
 
838
    //                                     ^--- start here
 
839
    //
 
840
    // Skip the first 'X:\' for the first form, and skip the first full
 
841
    // '\\machine\volume\' segment for the second form.
 
842
 
 
843
    const unsigned char* path = (const unsigned char*) mResolvedPath.get();
 
844
    if (path[0] == '\\' && path[1] == '\\')
 
845
    {
 
846
        // dealing with a UNC path here; skip past '\\machine\'
 
847
        path = _mbschr(path + 2, '\\');
 
848
        if (!path)
 
849
            return NS_ERROR_FILE_INVALID_PATH;
 
850
        ++path;
 
851
    }
 
852
 
 
853
    // search for first slash after the drive (or volume) name
 
854
    unsigned char* slash = _mbschr(path, '\\');
 
855
 
 
856
    if (slash)
 
857
    {
 
858
        // skip the first '\\'
 
859
        ++slash;
 
860
        slash = _mbschr(slash, '\\');
 
861
 
 
862
        while (slash)
 
863
        {
 
864
            *slash = '\0';
 
865
 
 
866
            if (!CreateDirectoryA(mResolvedPath.get(), NULL)) {
 
867
                rv = ConvertWinError(GetLastError());
 
868
                // perhaps the base path already exists, or perhaps we don't have
 
869
                // permissions to create the directory.  NOTE: access denied could
 
870
                // occur on a parent directory even though it exists.
 
871
                if (rv != NS_ERROR_FILE_ALREADY_EXISTS &&
 
872
                    rv != NS_ERROR_FILE_ACCESS_DENIED)
 
873
                    return rv;
 
874
            }
 
875
            *slash = '\\';
 
876
            ++slash;
 
877
            slash = _mbschr(slash, '\\');
 
878
        }
 
879
    }
 
880
 
 
881
    if (type == NORMAL_FILE_TYPE)
 
882
    {
 
883
        PRFileDesc* file = PR_Open(mResolvedPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes);
 
884
        if (!file) return NS_ERROR_FILE_ALREADY_EXISTS;
 
885
 
 
886
        PR_Close(file);
 
887
        return NS_OK;
 
888
    }
 
889
 
 
890
    if (type == DIRECTORY_TYPE)
 
891
    {
 
892
        if (!CreateDirectoryA(mResolvedPath.get(), NULL))
 
893
            return ConvertWinError(GetLastError());
 
894
        else
 
895
            return NS_OK;
 
896
    }
 
897
 
 
898
    return NS_ERROR_FILE_UNKNOWN_TYPE;
 
899
}
 
900
 
 
901
NS_IMETHODIMP
 
902
nsLocalFile::AppendNative(const nsACString &node)
 
903
{
 
904
    if (node.IsEmpty())
 
905
        return NS_OK;
 
906
 
 
907
    // Append only one component. Check for subdirs.
 
908
    // XXX can we avoid the PromiseFlatCString call?
 
909
    if (_mbschr((const unsigned char*) PromiseFlatCString(node).get(), '\\') != nsnull)
 
910
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
911
 
 
912
    return AppendRelativeNativePath(node);
 
913
}
 
914
 
 
915
NS_IMETHODIMP
 
916
nsLocalFile::AppendRelativeNativePath(const nsACString &node)
 
917
{
 
918
    // Cannot start with a / or have .. or have / anywhere
 
919
    nsACString::const_iterator begin, end;
 
920
    node.BeginReading(begin);
 
921
    node.EndReading(end);
 
922
    if (node.IsEmpty() || FindCharInReadable('/', begin, end))
 
923
    {
 
924
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
925
    }
 
926
    MakeDirty();
 
927
    mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node);
 
928
    return NS_OK;
 
929
}
 
930
 
 
931
NS_IMETHODIMP
 
932
nsLocalFile::Normalize()
 
933
{
 
934
    return NS_OK;
 
935
}
 
936
 
 
937
NS_IMETHODIMP
 
938
nsLocalFile::GetNativeLeafName(nsACString &aLeafName)
 
939
{
 
940
    aLeafName.Truncate();
 
941
 
 
942
    const char* temp = mWorkingPath.get();
 
943
    if(temp == nsnull)
 
944
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
945
 
 
946
    const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\');
 
947
 
 
948
    // if the working path is just a node without any lashes.
 
949
    if (leaf == nsnull)
 
950
        leaf = temp;
 
951
    else
 
952
        leaf++;
 
953
 
 
954
    aLeafName.Assign(leaf);
 
955
    return NS_OK;
 
956
}
 
957
 
 
958
NS_IMETHODIMP
 
959
nsLocalFile::SetNativeLeafName(const nsACString &aLeafName)
 
960
{
 
961
    MakeDirty();
 
962
 
 
963
    const unsigned char* temp = (const unsigned char*) mWorkingPath.get();
 
964
    if(temp == nsnull)
 
965
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
966
 
 
967
    // cannot use nsCString::RFindChar() due to 0x5c problem
 
968
    PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp);
 
969
    if (offset)
 
970
    {
 
971
        mWorkingPath.Truncate(offset+1);
 
972
    }
 
973
    mWorkingPath.Append(aLeafName);
 
974
 
 
975
    return NS_OK;
 
976
}
 
977
 
 
978
 
 
979
NS_IMETHODIMP
 
980
nsLocalFile::GetNativePath(nsACString &_retval)
 
981
{
 
982
    _retval = mWorkingPath;
 
983
    return NS_OK;
 
984
}
 
985
 
 
986
nsresult
 
987
nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, PRBool followSymlinks, PRBool move)
 
988
{
 
989
    nsresult rv;
 
990
    nsCAutoString filePath;
 
991
 
 
992
    // get the path that we are going to copy to.
 
993
    // Since windows does not know how to auto
 
994
    // resolve shortcust, we must work with the
 
995
    // target.
 
996
    nsCAutoString destPath;
 
997
    destParent->GetNativeTarget(destPath);
 
998
 
 
999
    destPath.Append("\\");
 
1000
 
 
1001
    if (newName.IsEmpty())
 
1002
    {
 
1003
        nsCAutoString aFileName;
 
1004
        sourceFile->GetNativeLeafName(aFileName);
 
1005
        destPath.Append(aFileName);
 
1006
    }
 
1007
    else
 
1008
    {
 
1009
        destPath.Append(newName);
 
1010
    }
 
1011
 
 
1012
 
 
1013
    if (followSymlinks)
 
1014
    {
 
1015
        rv = sourceFile->GetNativeTarget(filePath);
 
1016
        if (filePath.IsEmpty())
 
1017
            rv = sourceFile->GetNativePath(filePath);
 
1018
    }
 
1019
    else
 
1020
    {
 
1021
        rv = sourceFile->GetNativePath(filePath);
 
1022
    }
 
1023
 
 
1024
    if (NS_FAILED(rv))
 
1025
        return rv;
 
1026
 
 
1027
    int copyOK;
 
1028
 
 
1029
    if (!move)
 
1030
        copyOK = CopyFile(filePath.get(), destPath.get(), PR_TRUE);
 
1031
    else
 
1032
    {
 
1033
        // What we have to do is check to see if the destPath exists.  If it
 
1034
        // does, we have to move it out of the say so that MoveFile will
 
1035
        // succeed.  However, we don't want to just remove it since MoveFile
 
1036
        // can fail leaving us without a file.
 
1037
 
 
1038
        nsCAutoString backup;
 
1039
        PRFileInfo64 fileInfo64;
 
1040
        PRStatus status = PR_GetFileInfo64(destPath.get(), &fileInfo64);
 
1041
        if (status == PR_SUCCESS)
 
1042
        {
 
1043
 
 
1044
            // the file exists.  Check to make sure it is not a directory,
 
1045
            // then move it out of the way.
 
1046
            if (fileInfo64.type == PR_FILE_FILE)
 
1047
            {
 
1048
                backup.Append(destPath);
 
1049
                backup.Append(".moztmp");
 
1050
 
 
1051
                // remove any existing backup file that we may already have.
 
1052
                // maybe we should be doing some kind of unique naming here,
 
1053
                // but why bother.
 
1054
                remove(backup.get());
 
1055
 
 
1056
                // move destination file to backup file
 
1057
                copyOK = MoveFile(destPath.get(), backup.get());
 
1058
                if (!copyOK)
 
1059
                {
 
1060
                    // I guess we can't do the backup copy, so return.
 
1061
                    rv = ConvertWinError(GetLastError());
 
1062
                    return rv;
 
1063
                }
 
1064
            }
 
1065
        }
 
1066
        // move source file to destination file
 
1067
        copyOK = MoveFile(filePath.get(), destPath.get());
 
1068
 
 
1069
        if (!backup.IsEmpty())
 
1070
        {
 
1071
            if (copyOK)
 
1072
            {
 
1073
                // remove the backup copy.
 
1074
                remove(backup.get());
 
1075
            }
 
1076
            else
 
1077
            {
 
1078
                // restore backup
 
1079
                int backupOk = MoveFile(backup.get(), destPath.get());
 
1080
                NS_ASSERTION(backupOk, "move backup failed");
 
1081
            }
 
1082
        }
 
1083
    }
 
1084
    if (!copyOK)  // CopyFile and MoveFile returns non-zero if succeeds (backward if you ask me).
 
1085
        rv = ConvertWinError(GetLastError());
 
1086
 
 
1087
    return rv;
 
1088
}
 
1089
 
 
1090
 
 
1091
nsresult
 
1092
nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool followSymlinks, PRBool move)
 
1093
{
 
1094
    nsCOMPtr<nsIFile> newParentDir = aParentDir;
 
1095
    // check to see if this exists, otherwise return an error.
 
1096
    // we will check this by resolving.  If the user wants us
 
1097
    // to follow links, then we are talking about the target,
 
1098
    // hence we can use the |followSymlinks| parameter.
 
1099
    nsresult rv  = ResolveAndStat(followSymlinks);
 
1100
    if (NS_FAILED(rv))
 
1101
        return rv;
 
1102
 
 
1103
    if (!newParentDir)
 
1104
    {
 
1105
        // no parent was specified.  We must rename.
 
1106
 
 
1107
        if (newName.IsEmpty())
 
1108
            return NS_ERROR_INVALID_ARG;
 
1109
 
 
1110
        rv = GetParent(getter_AddRefs(newParentDir));
 
1111
        if (NS_FAILED(rv))
 
1112
            return rv;
 
1113
    }
 
1114
 
 
1115
    if (!newParentDir)
 
1116
        return NS_ERROR_FILE_DESTINATION_NOT_DIR;
 
1117
 
 
1118
    // make sure it exists and is a directory.  Create it if not there.
 
1119
    PRBool exists;
 
1120
    newParentDir->Exists(&exists);
 
1121
    if (!exists)
 
1122
    {
 
1123
        rv = newParentDir->Create(DIRECTORY_TYPE, 0644);  // TODO, what permissions should we use
 
1124
        if (NS_FAILED(rv))
 
1125
            return rv;
 
1126
    }
 
1127
    else
 
1128
    {
 
1129
        PRBool isDir;
 
1130
        newParentDir->IsDirectory(&isDir);
 
1131
        if (isDir == PR_FALSE)
 
1132
        {
 
1133
            if (followSymlinks)
 
1134
            {
 
1135
                PRBool isLink;
 
1136
                newParentDir->IsSymlink(&isLink);
 
1137
                if (isLink)
 
1138
                {
 
1139
                    nsCAutoString target;
 
1140
                    newParentDir->GetNativeTarget(target);
 
1141
 
 
1142
                    nsCOMPtr<nsILocalFile> realDest = new nsLocalFile();
 
1143
                    if (realDest == nsnull)
 
1144
                        return NS_ERROR_OUT_OF_MEMORY;
 
1145
 
 
1146
                    rv = realDest->InitWithNativePath(target);
 
1147
 
 
1148
                    if (NS_FAILED(rv))
 
1149
                        return rv;
 
1150
 
 
1151
                    return CopyMove(realDest, newName, followSymlinks, move);
 
1152
                }
 
1153
            }
 
1154
            else
 
1155
            {
 
1156
                return NS_ERROR_FILE_DESTINATION_NOT_DIR;
 
1157
            }
 
1158
        }
 
1159
    }
 
1160
 
 
1161
    // check to see if we are a directory, if so enumerate it.
 
1162
 
 
1163
    PRBool isDir;
 
1164
    IsDirectory(&isDir);
 
1165
    PRBool isSymlink;
 
1166
    IsSymlink(&isSymlink);
 
1167
 
 
1168
    if (!isDir || (isSymlink && !followSymlinks))
 
1169
    {
 
1170
        rv = CopySingleFile(this, newParentDir, newName, followSymlinks, move);
 
1171
        if (NS_FAILED(rv))
 
1172
            return rv;
 
1173
    }
 
1174
    else
 
1175
    {
 
1176
        // create a new target destination in the new parentDir;
 
1177
        nsCOMPtr<nsIFile> target;
 
1178
        rv = newParentDir->Clone(getter_AddRefs(target));
 
1179
 
 
1180
        if (NS_FAILED(rv))
 
1181
            return rv;
 
1182
 
 
1183
        nsCAutoString allocatedNewName;
 
1184
        if (newName.IsEmpty())
 
1185
        {
 
1186
            PRBool isLink;
 
1187
            IsSymlink(&isLink);
 
1188
            if (isLink)
 
1189
            {
 
1190
                nsCAutoString temp;
 
1191
                GetNativeTarget(temp);
 
1192
                const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp.get(), '\\');
 
1193
                if (leaf[0] == '\\')
 
1194
                    leaf++;
 
1195
                allocatedNewName = leaf;
 
1196
            }
 
1197
            else
 
1198
            {
 
1199
                GetNativeLeafName(allocatedNewName);// this should be the leaf name of the
 
1200
            }
 
1201
        }
 
1202
        else
 
1203
        {
 
1204
            allocatedNewName = newName;
 
1205
        }
 
1206
 
 
1207
        rv = target->AppendNative(allocatedNewName);
 
1208
        if (NS_FAILED(rv))
 
1209
            return rv;
 
1210
 
 
1211
        allocatedNewName.Truncate();
 
1212
 
 
1213
        // check if the destination directory already exists
 
1214
        target->Exists(&exists);
 
1215
        if (!exists)
 
1216
        {
 
1217
            // if the destination directory cannot be created, return an error
 
1218
            rv = target->Create(DIRECTORY_TYPE, 0644);  // TODO, what permissions should we use
 
1219
            if (NS_FAILED(rv))
 
1220
                return rv;
 
1221
        }
 
1222
        else
 
1223
        {
 
1224
            // check if the destination directory is writable and empty
 
1225
            PRBool isWritable;
 
1226
 
 
1227
            target->IsWritable(&isWritable);
 
1228
            if (!isWritable)
 
1229
                return NS_ERROR_FILE_ACCESS_DENIED;
 
1230
 
 
1231
            nsCOMPtr<nsISimpleEnumerator> targetIterator;
 
1232
            rv = target->GetDirectoryEntries(getter_AddRefs(targetIterator));
 
1233
 
 
1234
            PRBool more;
 
1235
            targetIterator->HasMoreElements(&more);
 
1236
            // return error if target directory is not empty
 
1237
            if (more)
 
1238
                return NS_ERROR_FILE_DIR_NOT_EMPTY;
 
1239
        }
 
1240
 
 
1241
        nsDirEnumerator dirEnum;
 
1242
 
 
1243
        rv = dirEnum.Init(this);
 
1244
        if (NS_FAILED(rv)) {
 
1245
            NS_WARNING("dirEnum initalization failed");
 
1246
            return rv;
 
1247
        }
 
1248
 
 
1249
        PRBool more;
 
1250
        while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more)
 
1251
        {
 
1252
            nsCOMPtr<nsISupports> item;
 
1253
            nsCOMPtr<nsIFile> file;
 
1254
            dirEnum.GetNext(getter_AddRefs(item));
 
1255
            file = do_QueryInterface(item);
 
1256
            if (file)
 
1257
            {
 
1258
                PRBool isDir, isLink;
 
1259
 
 
1260
                file->IsDirectory(&isDir);
 
1261
                file->IsSymlink(&isLink);
 
1262
 
 
1263
                if (move)
 
1264
                {
 
1265
                    if (followSymlinks)
 
1266
                        return NS_ERROR_FAILURE;
 
1267
 
 
1268
                    rv = file->MoveToNative(target, nsCString());
 
1269
                    NS_ENSURE_SUCCESS(rv,rv);
 
1270
                }
 
1271
                else
 
1272
                {
 
1273
                    if (followSymlinks)
 
1274
                        rv = file->CopyToFollowingLinksNative(target, nsCString());
 
1275
                    else
 
1276
                        rv = file->CopyToNative(target, nsCString());
 
1277
                    NS_ENSURE_SUCCESS(rv,rv);
 
1278
                }
 
1279
            }
 
1280
        }
 
1281
        // we've finished moving all the children of this directory
 
1282
        // in the new directory.  so now delete the directory
 
1283
        // note, we don't need to do a recursive delete.
 
1284
        // MoveTo() is recursive.  At this point,
 
1285
        // we've already moved the children of the current folder
 
1286
        // to the new location.  nothing should be left in the folder.
 
1287
        if (move)
 
1288
        {
 
1289
          rv = Remove(PR_FALSE /* recursive */);
 
1290
          NS_ENSURE_SUCCESS(rv,rv);
 
1291
        }
 
1292
    }
 
1293
 
 
1294
 
 
1295
    // If we moved, we want to adjust this.
 
1296
    if (move)
 
1297
    {
 
1298
        MakeDirty();
 
1299
 
 
1300
        nsCAutoString newParentPath;
 
1301
        newParentDir->GetNativePath(newParentPath);
 
1302
 
 
1303
        if (newParentPath.IsEmpty())
 
1304
            return NS_ERROR_FAILURE;
 
1305
 
 
1306
        if (newName.IsEmpty())
 
1307
        {
 
1308
            nsCAutoString aFileName;
 
1309
            GetNativeLeafName(aFileName);
 
1310
 
 
1311
            InitWithNativePath(newParentPath);
 
1312
            AppendNative(aFileName);
 
1313
        }
 
1314
        else
 
1315
        {
 
1316
            InitWithNativePath(newParentPath);
 
1317
            AppendNative(newName);
 
1318
        }
 
1319
    }
 
1320
 
 
1321
    return NS_OK;
 
1322
}
 
1323
 
 
1324
NS_IMETHODIMP
 
1325
nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName)
 
1326
{
 
1327
    return CopyMove(newParentDir, newName, PR_FALSE, PR_FALSE);
 
1328
}
 
1329
 
 
1330
NS_IMETHODIMP
 
1331
nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName)
 
1332
{
 
1333
    return CopyMove(newParentDir, newName, PR_TRUE, PR_FALSE);
 
1334
}
 
1335
 
 
1336
NS_IMETHODIMP
 
1337
nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName)
 
1338
{
 
1339
    return CopyMove(newParentDir, newName, PR_FALSE, PR_TRUE);
 
1340
}
 
1341
 
 
1342
NS_IMETHODIMP
 
1343
nsLocalFile::Load(PRLibrary * *_retval)
 
1344
{
 
1345
    PRBool isFile;
 
1346
    nsresult rv = IsFile(&isFile);
 
1347
 
 
1348
    if (NS_FAILED(rv))
 
1349
        return rv;
 
1350
 
 
1351
    if (! isFile)
 
1352
        return NS_ERROR_FILE_IS_DIRECTORY;
 
1353
 
 
1354
    NS_TIMELINE_START_TIMER("PR_LoadLibrary");
 
1355
    *_retval =  PR_LoadLibrary(mResolvedPath.get());
 
1356
    NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
 
1357
    NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mResolvedPath.get());
 
1358
 
 
1359
    if (*_retval)
 
1360
        return NS_OK;
 
1361
 
 
1362
    return NS_ERROR_NULL_POINTER;
 
1363
}
 
1364
 
 
1365
NS_IMETHODIMP
 
1366
nsLocalFile::Remove(PRBool recursive)
 
1367
{
 
1368
    nsresult rv;
 
1369
    PRBool isDir, isLink;
 
1370
    nsXPIDLCString buf;
 
1371
    const char *filePath;
 
1372
 
 
1373
    // NOTE:
 
1374
    //
 
1375
    // if the working path points to a shortcut, then we will only
 
1376
    // delete the shortcut itself.  even if the shortcut points to
 
1377
    // a directory, we will not recurse into that directory or 
 
1378
    // delete that directory itself.  likewise, if the shortcut
 
1379
    // points to a normal file, we will not delete the real file.
 
1380
    // this is done to be consistent with the other platforms that
 
1381
    // behave this way.  we do this even if the followLinks attribute
 
1382
    // is set to true.  this helps protect against misuse that could
 
1383
    // lead to security bugs (e.g., bug 210588).
 
1384
    //
 
1385
    // in the case of non-terminal shortcuts, those are all followed
 
1386
    // unconditionally.  this is done because 1) we only delete 
 
1387
    // terminal nodes and possibly their children, and 2) the remove
 
1388
    // and rmdir CRT calls don't know how to handle shortcuts.
 
1389
 
 
1390
    IsSymlink(&isLink);
 
1391
    if (isLink)
 
1392
    {
 
1393
        isDir = PR_FALSE;
 
1394
        // resolve non-terminal nodes only.
 
1395
        rv = ResolvePath(mWorkingPath.get(), PR_FALSE, getter_Copies(buf));
 
1396
        if (NS_FAILED(rv))
 
1397
            return rv;
 
1398
        filePath = buf.get();
 
1399
    }
 
1400
    else
 
1401
    {
 
1402
        rv = IsDirectory(&isDir);
 
1403
        if (NS_FAILED(rv))
 
1404
            return rv;
 
1405
        // in this case, it doesn't matter that terminal nodes were
 
1406
        // resolved, so we can safely leverage mResolvedPath.
 
1407
        filePath = mResolvedPath.get();
 
1408
    }
 
1409
 
 
1410
    if (isDir)
 
1411
    {
 
1412
        if (recursive)
 
1413
        {
 
1414
            nsDirEnumerator dirEnum;
 
1415
 
 
1416
            rv = dirEnum.Init(this);
 
1417
            if (NS_FAILED(rv))
 
1418
                return rv;
 
1419
 
 
1420
            PRBool more;
 
1421
            while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more)
 
1422
            {
 
1423
                nsCOMPtr<nsISupports> item;
 
1424
                dirEnum.GetNext(getter_AddRefs(item));
 
1425
                nsCOMPtr<nsIFile> file = do_QueryInterface(item);
 
1426
                if (file)
 
1427
                    file->Remove(recursive);
 
1428
            }
 
1429
        }
 
1430
        rv = rmdir(filePath);
 
1431
    }
 
1432
    else
 
1433
    {
 
1434
        rv = remove(filePath);
 
1435
    }
 
1436
 
 
1437
    // fixup error code if necessary...
 
1438
    if (rv == -1)
 
1439
        rv = NSRESULT_FOR_ERRNO();
 
1440
    
 
1441
    MakeDirty();
 
1442
    return rv;
 
1443
}
 
1444
 
 
1445
NS_IMETHODIMP
 
1446
nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
 
1447
{
 
1448
    NS_ENSURE_ARG(aLastModifiedTime);
 
1449
 
 
1450
    *aLastModifiedTime = 0;
 
1451
 
 
1452
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1453
 
 
1454
    if (NS_FAILED(rv))
 
1455
        return rv;
 
1456
 
 
1457
    // microseconds -> milliseconds
 
1458
    *aLastModifiedTime = mFileInfo64.modifyTime / PR_USEC_PER_MSEC;
 
1459
    return NS_OK;
 
1460
}
 
1461
 
 
1462
 
 
1463
NS_IMETHODIMP
 
1464
nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime)
 
1465
{
 
1466
    NS_ENSURE_ARG(aLastModifiedTime);
 
1467
 
 
1468
    *aLastModifiedTime = 0;
 
1469
 
 
1470
    nsresult rv = ResolveAndStat(PR_FALSE);
 
1471
 
 
1472
    if (NS_FAILED(rv))
 
1473
        return rv;
 
1474
 
 
1475
    // microseconds -> milliseconds
 
1476
    *aLastModifiedTime = mFileInfo64.modifyTime / PR_USEC_PER_MSEC;
 
1477
 
 
1478
    return NS_OK;
 
1479
}
 
1480
 
 
1481
 
 
1482
NS_IMETHODIMP
 
1483
nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
 
1484
{
 
1485
    return nsLocalFile::SetModDate(aLastModifiedTime, PR_TRUE);
 
1486
}
 
1487
 
 
1488
 
 
1489
NS_IMETHODIMP
 
1490
nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime)
 
1491
{
 
1492
    return nsLocalFile::SetModDate(aLastModifiedTime, PR_FALSE);
 
1493
}
 
1494
 
 
1495
nsresult
 
1496
nsLocalFile::SetModDate(PRInt64 aLastModifiedTime, PRBool resolveTerminal)
 
1497
{
 
1498
    nsresult rv = ResolveAndStat(resolveTerminal);
 
1499
 
 
1500
    if (NS_FAILED(rv))
 
1501
        return rv;
 
1502
 
 
1503
    const char *filePath = mResolvedPath.get();
 
1504
 
 
1505
    HANDLE file = CreateFile(  filePath,          // pointer to name of the file
 
1506
                               GENERIC_WRITE,     // access (write) mode
 
1507
                               0,                 // share mode
 
1508
                               NULL,              // pointer to security attributes
 
1509
                               OPEN_EXISTING,     // how to create
 
1510
                               0,                 // file attributes
 
1511
                               NULL);
 
1512
 
 
1513
    MakeDirty();
 
1514
 
 
1515
    if (!file)
 
1516
    {
 
1517
        return ConvertWinError(GetLastError());
 
1518
    }
 
1519
 
 
1520
    FILETIME lft, ft;
 
1521
    SYSTEMTIME st;
 
1522
    PRExplodedTime pret;
 
1523
 
 
1524
    // PR_ExplodeTime expects usecs...
 
1525
    PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret);
 
1526
    st.wYear            = pret.tm_year;
 
1527
    st.wMonth           = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0
 
1528
    st.wDayOfWeek       = pret.tm_wday;
 
1529
    st.wDay             = pret.tm_mday;
 
1530
    st.wHour            = pret.tm_hour;
 
1531
    st.wMinute          = pret.tm_min;
 
1532
    st.wSecond          = pret.tm_sec;
 
1533
    st.wMilliseconds    = pret.tm_usec/1000;
 
1534
 
 
1535
    if ( 0 == SystemTimeToFileTime(&st, &lft) )
 
1536
    {
 
1537
        rv = ConvertWinError(GetLastError());
 
1538
    }
 
1539
    else if ( 0 == LocalFileTimeToFileTime(&lft, &ft) )
 
1540
    {
 
1541
        rv = ConvertWinError(GetLastError());
 
1542
    }
 
1543
    else if ( 0 == SetFileTime(file, NULL, &ft, &ft) )
 
1544
    {
 
1545
        // could not set time
 
1546
        rv = ConvertWinError(GetLastError());
 
1547
    }
 
1548
 
 
1549
    CloseHandle( file );
 
1550
    return rv;
 
1551
}
 
1552
 
 
1553
NS_IMETHODIMP
 
1554
nsLocalFile::GetPermissions(PRUint32 *aPermissions)
 
1555
{
 
1556
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1557
 
 
1558
    if (NS_FAILED(rv))
 
1559
        return rv;
 
1560
 
 
1561
    const char *filePath = mResolvedPath.get();
 
1562
 
 
1563
 
 
1564
    return NS_OK;
 
1565
}
 
1566
 
 
1567
NS_IMETHODIMP
 
1568
nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
 
1569
{
 
1570
    return NS_ERROR_NOT_IMPLEMENTED;
 
1571
}
 
1572
 
 
1573
 
 
1574
NS_IMETHODIMP
 
1575
nsLocalFile::SetPermissions(PRUint32 aPermissions)
 
1576
{
 
1577
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1578
 
 
1579
    if (NS_FAILED(rv))
 
1580
        return rv;
 
1581
 
 
1582
    const char *filePath = mResolvedPath.get();
 
1583
    if( chmod(filePath, aPermissions) == -1 )
 
1584
        return NS_ERROR_FAILURE;
 
1585
 
 
1586
    return NS_OK;
 
1587
}
 
1588
 
 
1589
NS_IMETHODIMP
 
1590
nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions)
 
1591
{
 
1592
    nsresult rv = ResolveAndStat(PR_FALSE);
 
1593
 
 
1594
    if (NS_FAILED(rv))
 
1595
        return rv;
 
1596
 
 
1597
    const char *filePath = mResolvedPath.get();
 
1598
    if( chmod(filePath, aPermissions) == -1 )
 
1599
        return NS_ERROR_FAILURE;
 
1600
 
 
1601
    return NS_OK;
 
1602
}
 
1603
 
 
1604
 
 
1605
NS_IMETHODIMP
 
1606
nsLocalFile::GetFileSize(PRInt64 *aFileSize)
 
1607
{
 
1608
    NS_ENSURE_ARG(aFileSize);
 
1609
 
 
1610
    *aFileSize = 0;
 
1611
 
 
1612
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1613
 
 
1614
    if (NS_FAILED(rv))
 
1615
        return rv;
 
1616
 
 
1617
 
 
1618
    *aFileSize = mFileInfo64.size;
 
1619
    return NS_OK;
 
1620
}
 
1621
 
 
1622
 
 
1623
NS_IMETHODIMP
 
1624
nsLocalFile::SetFileSize(PRInt64 aFileSize)
 
1625
{
 
1626
 
 
1627
    DWORD status;
 
1628
    HANDLE hFile;
 
1629
 
 
1630
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1631
 
 
1632
    if (NS_FAILED(rv))
 
1633
        return rv;
 
1634
 
 
1635
    const char *filePath = mResolvedPath.get();
 
1636
 
 
1637
 
 
1638
    // Leave it to Microsoft to open an existing file with a function
 
1639
    // named "CreateFile".
 
1640
    hFile = CreateFile(filePath,
 
1641
                       GENERIC_WRITE,
 
1642
                       FILE_SHARE_READ,
 
1643
                       NULL,
 
1644
                       OPEN_EXISTING,
 
1645
                       FILE_ATTRIBUTE_NORMAL,
 
1646
                       NULL);
 
1647
 
 
1648
    if (hFile == INVALID_HANDLE_VALUE)
 
1649
    {
 
1650
        MakeDirty();
 
1651
        return NS_ERROR_FAILURE;
 
1652
    }
 
1653
 
 
1654
    // Seek to new, desired end of file
 
1655
    PRInt32 hi, lo;
 
1656
    myLL_L2II(aFileSize, &hi, &lo );
 
1657
 
 
1658
    status = SetFilePointer(hFile, lo, NULL, FILE_BEGIN);
 
1659
    if (status == 0xffffffff)
 
1660
        goto error;
 
1661
 
 
1662
    // Truncate file at current cursor position
 
1663
    if (!SetEndOfFile(hFile))
 
1664
        goto error;
 
1665
 
 
1666
    if (!CloseHandle(hFile))
 
1667
        return NS_ERROR_FAILURE;
 
1668
 
 
1669
    MakeDirty();
 
1670
    return NS_OK;
 
1671
 
 
1672
 error:
 
1673
    MakeDirty();
 
1674
    CloseHandle(hFile);
 
1675
    return NS_ERROR_FAILURE;
 
1676
}
 
1677
 
 
1678
NS_IMETHODIMP
 
1679
nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize)
 
1680
{
 
1681
    NS_ENSURE_ARG(aFileSize);
 
1682
 
 
1683
    *aFileSize = 0;
 
1684
 
 
1685
    nsresult rv = ResolveAndStat(PR_FALSE);
 
1686
 
 
1687
    if (NS_FAILED(rv))
 
1688
        return rv;
 
1689
 
 
1690
    *aFileSize = mFileInfo64.size;
 
1691
    return NS_OK;
 
1692
}
 
1693
 
 
1694
NS_IMETHODIMP
 
1695
nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
 
1696
{
 
1697
    NS_ENSURE_ARG(aDiskSpaceAvailable);
 
1698
 
 
1699
    ResolveAndStat(PR_FALSE);
 
1700
 
 
1701
    PRInt64 int64;
 
1702
 
 
1703
    LL_I2L(int64 , LONG_MAX);
 
1704
 
 
1705
    // Check disk space
 
1706
    DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus;
 
1707
    ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes, liTotalNumberOfFreeBytes;
 
1708
    double nBytes = 0;
 
1709
 
 
1710
    BOOL (WINAPI* getDiskFreeSpaceExA)(LPCTSTR lpDirectoryName,
 
1711
                                       PULARGE_INTEGER lpFreeBytesAvailableToCaller,
 
1712
                                       PULARGE_INTEGER lpTotalNumberOfBytes,
 
1713
                                       PULARGE_INTEGER lpTotalNumberOfFreeBytes) = NULL;
 
1714
 
 
1715
    HINSTANCE hInst = LoadLibrary("KERNEL32.DLL");
 
1716
    NS_ASSERTION(hInst != NULL, "COULD NOT LOAD KERNEL32.DLL");
 
1717
    if (hInst != NULL)
 
1718
    {
 
1719
        getDiskFreeSpaceExA =  (BOOL (WINAPI*)(LPCTSTR lpDirectoryName,
 
1720
                                               PULARGE_INTEGER lpFreeBytesAvailableToCaller,
 
1721
                                               PULARGE_INTEGER lpTotalNumberOfBytes,
 
1722
                                               PULARGE_INTEGER lpTotalNumberOfFreeBytes))
 
1723
        GetProcAddress(hInst, "GetDiskFreeSpaceExA");
 
1724
        FreeLibrary(hInst);
 
1725
    }
 
1726
 
 
1727
    if (getDiskFreeSpaceExA && (*getDiskFreeSpaceExA)(mResolvedPath.get(),
 
1728
                                                      &liFreeBytesAvailableToCaller,
 
1729
                                                      &liTotalNumberOfBytes,
 
1730
                                                      &liTotalNumberOfFreeBytes))
 
1731
    {
 
1732
        nBytes = (double)(signed __int64)liFreeBytesAvailableToCaller.QuadPart;
 
1733
    }
 
1734
    else {
 
1735
        char aDrive[_MAX_DRIVE + 2];
 
1736
        _splitpath( mResolvedPath.get(), aDrive, NULL, NULL, NULL);
 
1737
        strcat(aDrive, "\\");
 
1738
 
 
1739
        if ( GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus))
 
1740
        {
 
1741
            nBytes = (double)dwFreeClus*(double)dwSecPerClus*(double) dwBytesPerSec;
 
1742
        }
 
1743
    }
 
1744
    LL_D2L(*aDiskSpaceAvailable, nBytes);
 
1745
 
 
1746
    return NS_OK;
 
1747
 
 
1748
}
 
1749
 
 
1750
NS_IMETHODIMP
 
1751
nsLocalFile::GetParent(nsIFile * *aParent)
 
1752
{
 
1753
    NS_ENSURE_ARG_POINTER(aParent);
 
1754
 
 
1755
    nsCAutoString parentPath(mWorkingPath);
 
1756
 
 
1757
    // cannot use nsCString::RFindChar() due to 0x5c problem
 
1758
    PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\')
 
1759
                     - (const unsigned char *) parentPath.get());
 
1760
    if (offset < 0)
 
1761
        return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
1762
 
 
1763
    parentPath.Truncate(offset);
 
1764
 
 
1765
    nsCOMPtr<nsILocalFile> localFile;
 
1766
    nsresult rv =  NS_NewNativeLocalFile(parentPath, mFollowSymlinks, getter_AddRefs(localFile));
 
1767
 
 
1768
    if(NS_SUCCEEDED(rv) && localFile)
 
1769
    {
 
1770
        return CallQueryInterface(localFile, aParent);
 
1771
    }
 
1772
    return rv;
 
1773
}
 
1774
 
 
1775
NS_IMETHODIMP
 
1776
nsLocalFile::Exists(PRBool *_retval)
 
1777
{
 
1778
    NS_ENSURE_ARG(_retval);
 
1779
 
 
1780
    MakeDirty();
 
1781
    nsresult rv = ResolveAndStat( PR_TRUE );
 
1782
 
 
1783
    if (NS_SUCCEEDED(rv))
 
1784
        *_retval = PR_TRUE;
 
1785
    else
 
1786
        *_retval = PR_FALSE;
 
1787
 
 
1788
    return NS_OK;
 
1789
}
 
1790
 
 
1791
NS_IMETHODIMP
 
1792
nsLocalFile::IsWritable(PRBool *_retval)
 
1793
{
 
1794
    NS_ENSURE_ARG(_retval);
 
1795
    *_retval = PR_FALSE;
 
1796
 
 
1797
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1798
 
 
1799
    if (NS_FAILED(rv))
 
1800
        return rv;
 
1801
 
 
1802
    const char *workingFilePath = mWorkingPath.get();
 
1803
    DWORD word = GetFileAttributes(workingFilePath);
 
1804
 
 
1805
    *_retval = !((word & FILE_ATTRIBUTE_READONLY) != 0);
 
1806
 
 
1807
    return NS_OK;
 
1808
}
 
1809
 
 
1810
NS_IMETHODIMP
 
1811
nsLocalFile::IsReadable(PRBool *_retval)
 
1812
{
 
1813
    NS_ENSURE_ARG(_retval);
 
1814
    *_retval = PR_FALSE;
 
1815
 
 
1816
    nsresult rv = ResolveAndStat( PR_TRUE );
 
1817
    if (NS_FAILED(rv))
 
1818
        return rv;
 
1819
 
 
1820
    *_retval = PR_TRUE;
 
1821
    return NS_OK;
 
1822
}
 
1823
 
 
1824
 
 
1825
NS_IMETHODIMP
 
1826
nsLocalFile::IsExecutable(PRBool *_retval)
 
1827
{
 
1828
    NS_ENSURE_ARG(_retval);
 
1829
    *_retval = PR_FALSE;
 
1830
 
 
1831
 
 
1832
    nsresult rv = ResolveAndStat( PR_TRUE );
 
1833
    if (NS_FAILED(rv))
 
1834
        return rv;
 
1835
 
 
1836
    nsCAutoString path;
 
1837
    PRBool symLink;
 
1838
 
 
1839
    rv = IsSymlink(&symLink);
 
1840
    if (NS_FAILED(rv))
 
1841
        return rv;
 
1842
 
 
1843
    if (symLink)
 
1844
        GetNativeTarget(path);
 
1845
    else
 
1846
        GetNativePath(path);
 
1847
 
 
1848
    // Get extension.
 
1849
    char* ext = ::strrchr( path.BeginWriting(), '.' );
 
1850
    if ( ext ) {
 
1851
        // Convert extension to lower case.
 
1852
        for( char *p = ext; *p; p++ ) {
 
1853
            if ( ::isupper( *p ) ) {
 
1854
                *p = ::tolower( *p );
 
1855
            }
 
1856
        }
 
1857
        // Search for any of the set of executable extensions.
 
1858
        const char * const executableExts[] = {
 
1859
            ".ad",
 
1860
            ".adp",
 
1861
            ".asp",
 
1862
            ".bas",
 
1863
            ".bat",
 
1864
            ".chm",
 
1865
            ".cmd",
 
1866
            ".com",
 
1867
            ".cpl",
 
1868
            ".crt",
 
1869
            ".exe",
 
1870
            ".hlp",
 
1871
            ".hta",
 
1872
            ".inf",
 
1873
            ".ins",
 
1874
            ".isp",
 
1875
            ".js",
 
1876
            ".jse",
 
1877
            ".lnk",
 
1878
            ".mdb",
 
1879
            ".mde",
 
1880
            ".msc",
 
1881
            ".msi",
 
1882
            ".msp",
 
1883
            ".mst",
 
1884
            ".pcd",
 
1885
            ".pif",
 
1886
            ".reg",
 
1887
            ".scr",
 
1888
            ".sct",
 
1889
            ".shb",
 
1890
            ".shs",
 
1891
            ".url",
 
1892
            ".vb",
 
1893
            ".vbe",
 
1894
            ".vbs",
 
1895
            ".vsd",
 
1896
            ".vss",
 
1897
            ".vst",
 
1898
            ".vsw",
 
1899
            ".ws",
 
1900
            ".wsc",
 
1901
            ".wsf",
 
1902
            ".wsh",
 
1903
            0 };
 
1904
        for ( int i = 0; executableExts[i]; i++ ) {
 
1905
            if ( ::strcmp( executableExts[i], ext ) == 0 ) {
 
1906
                // Found a match.  Set result and quit.
 
1907
                *_retval = PR_TRUE;
 
1908
                break;
 
1909
            }
 
1910
        }
 
1911
    }
 
1912
 
 
1913
    return NS_OK;
 
1914
}
 
1915
 
 
1916
 
 
1917
NS_IMETHODIMP
 
1918
nsLocalFile::IsDirectory(PRBool *_retval)
 
1919
{
 
1920
    NS_PRECONDITION(_retval, "null pointer");
 
1921
 
 
1922
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1923
    if (NS_FAILED(rv)) {
 
1924
        *_retval = PR_FALSE;
 
1925
        return rv;
 
1926
    }
 
1927
 
 
1928
    *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); 
 
1929
    return NS_OK;
 
1930
}
 
1931
 
 
1932
NS_IMETHODIMP
 
1933
nsLocalFile::IsFile(PRBool *_retval)
 
1934
{
 
1935
    NS_ENSURE_ARG(_retval);
 
1936
    *_retval = PR_FALSE;
 
1937
 
 
1938
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1939
 
 
1940
    if (NS_FAILED(rv))
 
1941
        return rv;
 
1942
 
 
1943
    *_retval = (mFileInfo64.type == PR_FILE_FILE);
 
1944
    return rv;
 
1945
}
 
1946
 
 
1947
NS_IMETHODIMP
 
1948
nsLocalFile::IsHidden(PRBool *_retval)
 
1949
{
 
1950
    NS_ENSURE_ARG(_retval);
 
1951
    *_retval = PR_FALSE;
 
1952
 
 
1953
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1954
 
 
1955
    if (NS_FAILED(rv))
 
1956
        return rv;
 
1957
 
 
1958
    DWORD word;
 
1959
    if (mFollowSymlinks)
 
1960
    {
 
1961
        const char *resolvedFilePath = mResolvedPath.get();
 
1962
        word = GetFileAttributes(resolvedFilePath);
 
1963
    }
 
1964
    else
 
1965
    {
 
1966
        const char *workingFilePath = mWorkingPath.get();
 
1967
        word = GetFileAttributes(workingFilePath);
 
1968
    }
 
1969
 
 
1970
    *_retval =  ((word & FILE_ATTRIBUTE_HIDDEN)  != 0);
 
1971
 
 
1972
    return NS_OK;
 
1973
}
 
1974
 
 
1975
NS_IMETHODIMP
 
1976
nsLocalFile::IsSymlink(PRBool *_retval)
 
1977
{
 
1978
    NS_PRECONDITION(_retval, "null pointer");
 
1979
 
 
1980
    PRUint32 len = mWorkingPath.Length();
 
1981
    if (len < 4)
 
1982
        *_retval = PR_FALSE;
 
1983
    else {
 
1984
        const char* leaf = mWorkingPath.get() + len - 4;
 
1985
        *_retval = (strnicmp(leaf, ".lnk", 4) == 0);
 
1986
    }
 
1987
    return NS_OK;
 
1988
}
 
1989
 
 
1990
NS_IMETHODIMP
 
1991
nsLocalFile::IsSpecial(PRBool *_retval)
 
1992
{
 
1993
    NS_ENSURE_ARG(_retval);
 
1994
    *_retval = PR_FALSE;
 
1995
 
 
1996
    nsresult rv = ResolveAndStat(PR_TRUE);
 
1997
 
 
1998
    if (NS_FAILED(rv))
 
1999
        return rv;
 
2000
 
 
2001
    const char *workingFilePath = mWorkingPath.get();
 
2002
    DWORD word = GetFileAttributes(workingFilePath);
 
2003
 
 
2004
    *_retval = ((word & FILE_ATTRIBUTE_SYSTEM)  != 0);
 
2005
 
 
2006
    return NS_OK;
 
2007
}
 
2008
 
 
2009
NS_IMETHODIMP
 
2010
nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
 
2011
{
 
2012
    NS_ENSURE_ARG(inFile);
 
2013
    NS_ENSURE_ARG(_retval);
 
2014
 
 
2015
    nsCAutoString inFilePath;
 
2016
    inFile->GetNativePath(inFilePath);
 
2017
 
 
2018
    *_retval = inFilePath.Equals(mWorkingPath);
 
2019
    return NS_OK;
 
2020
}
 
2021
 
 
2022
NS_IMETHODIMP
 
2023
nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
 
2024
{
 
2025
    *_retval = PR_FALSE;
 
2026
 
 
2027
    nsCAutoString myFilePath;
 
2028
    if ( NS_FAILED(GetNativeTarget(myFilePath)))
 
2029
        GetNativePath(myFilePath);
 
2030
 
 
2031
    PRInt32 myFilePathLen = myFilePath.Length();
 
2032
 
 
2033
    nsCAutoString inFilePath;
 
2034
    if ( NS_FAILED(inFile->GetNativeTarget(inFilePath)))
 
2035
        inFile->GetNativePath(inFilePath);
 
2036
 
 
2037
    if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0)
 
2038
    {
 
2039
        // now make sure that the |inFile|'s path has a trailing
 
2040
        // separator.
 
2041
 
 
2042
        if (inFilePath[myFilePathLen] == '\\')
 
2043
        {
 
2044
            *_retval = PR_TRUE;
 
2045
        }
 
2046
 
 
2047
    }
 
2048
 
 
2049
    return NS_OK;
 
2050
}
 
2051
 
 
2052
 
 
2053
 
 
2054
NS_IMETHODIMP
 
2055
nsLocalFile::GetNativeTarget(nsACString &_retval)
 
2056
{
 
2057
    _retval.Truncate();
 
2058
#if STRICT_FAKE_SYMLINKS
 
2059
    PRBool symLink;
 
2060
 
 
2061
    nsresult rv = IsSymlink(&symLink);
 
2062
    if (NS_FAILED(rv))
 
2063
        return rv;
 
2064
 
 
2065
    if (!symLink)
 
2066
    {
 
2067
        return NS_ERROR_FILE_INVALID_PATH;
 
2068
    }
 
2069
#endif
 
2070
    ResolveAndStat(PR_TRUE);
 
2071
 
 
2072
    _retval = mResolvedPath;
 
2073
    return NS_OK;
 
2074
}
 
2075
 
 
2076
 
 
2077
/* attribute PRBool followLinks; */
 
2078
NS_IMETHODIMP
 
2079
nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
 
2080
{
 
2081
    *aFollowLinks = mFollowSymlinks;
 
2082
    return NS_OK;
 
2083
}
 
2084
NS_IMETHODIMP
 
2085
nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
 
2086
{
 
2087
    MakeDirty();
 
2088
    mFollowSymlinks = aFollowLinks;
 
2089
    return NS_OK;
 
2090
}
 
2091
 
 
2092
 
 
2093
NS_IMETHODIMP
 
2094
nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries)
 
2095
{
 
2096
    nsresult rv;
 
2097
 
 
2098
    *entries = nsnull;
 
2099
 
 
2100
    PRBool isDir;
 
2101
    rv = IsDirectory(&isDir);
 
2102
    if (NS_FAILED(rv))
 
2103
        return rv;
 
2104
    if (!isDir)
 
2105
        return NS_ERROR_FILE_NOT_DIRECTORY;
 
2106
 
 
2107
    nsDirEnumerator* dirEnum = new nsDirEnumerator();
 
2108
    if (dirEnum == nsnull)
 
2109
        return NS_ERROR_OUT_OF_MEMORY;
 
2110
    NS_ADDREF(dirEnum);
 
2111
    rv = dirEnum->Init(this);
 
2112
    if (NS_FAILED(rv))
 
2113
    {
 
2114
        NS_RELEASE(dirEnum);
 
2115
        return rv;
 
2116
    }
 
2117
 
 
2118
    *entries = dirEnum;
 
2119
    return NS_OK;
 
2120
}
 
2121
 
 
2122
NS_IMETHODIMP
 
2123
nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor)
 
2124
{
 
2125
    return GetNativePath(aPersistentDescriptor);
 
2126
}
 
2127
 
 
2128
NS_IMETHODIMP
 
2129
nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor)
 
2130
{
 
2131
   return InitWithNativePath(aPersistentDescriptor);
 
2132
}
 
2133
 
 
2134
NS_IMETHODIMP
 
2135
nsLocalFile::Reveal()
 
2136
{
 
2137
  nsresult rv = NS_OK;
 
2138
  PRBool isDirectory = PR_FALSE;
 
2139
  nsCAutoString path;
 
2140
  nsAutoString unicodePath;
 
2141
 
 
2142
  IsDirectory(&isDirectory);
 
2143
  if (isDirectory)
 
2144
  {
 
2145
    GetNativePath(path);
 
2146
  }
 
2147
  else
 
2148
  {
 
2149
    nsCOMPtr<nsIFile> parent;
 
2150
    GetParent(getter_AddRefs(parent));
 
2151
    if (parent)
 
2152
    {
 
2153
      parent->GetNativePath(path);
 
2154
      parent->GetPath(unicodePath);
 
2155
    }
 
2156
  }
 
2157
 
 
2158
  // Remember the current fg window.
 
2159
  HWND origWin, fgWin;
 
2160
  origWin = fgWin = ::GetForegroundWindow();
 
2161
 
 
2162
  // use the app registry name to launch a shell execute....
 
2163
  LONG r = (LONG) ::ShellExecute( NULL, "open", path.get(), NULL, NULL, SW_SHOWNORMAL);
 
2164
  if (r < 32)
 
2165
    return NS_ERROR_FAILURE;
 
2166
 
 
2167
  // If this is a directory, then we don't need to select a file.
 
2168
  if (isDirectory)
 
2169
    return NS_OK;
 
2170
 
 
2171
  // Resources we may need to free when done.
 
2172
  IShellFolder *desktopFolder   = 0;
 
2173
  IMalloc      *shellMalloc     = 0;
 
2174
  IShellFolder *folder          = 0;
 
2175
  LPITEMIDLIST  folder_pidl     = 0;
 
2176
  LPITEMIDLIST  file_pidl       = 0;
 
2177
  LPITEMIDLIST  win95_file_pidl = 0;
 
2178
  HMODULE       shell32         = 0;
 
2179
 
 
2180
  // We break out of this do/while non-loop at any point where we have to give up.
 
2181
  do {
 
2182
    // Wait for the window to open.  We wait a maximum of 2 seconds.
 
2183
    // If we get the wrong window, that will be dealt with below.
 
2184
    for (int iter = 10; iter; iter--)
 
2185
    {
 
2186
      fgWin = ::GetForegroundWindow();
 
2187
      if (fgWin != origWin)
 
2188
          break; // for loopo
 
2189
      ::Sleep(200);
 
2190
    }
 
2191
    // If we failed to locate the new window, give up.
 
2192
    if (origWin == fgWin)
 
2193
      break; // do/while
 
2194
 
 
2195
    // Now we have the explorer window.  We need to send it the "select item"
 
2196
    // message (which isn't trivial, so buckly your seat belt)...
 
2197
 
 
2198
    // We need the explorer's process id.
 
2199
    DWORD pid = 0;
 
2200
    ::GetWindowThreadProcessId(fgWin, &pid);
 
2201
 
 
2202
    // Get desktop folder.
 
2203
    HRESULT rc = ::SHGetDesktopFolder(&desktopFolder);
 
2204
    if (!desktopFolder)
 
2205
      break;
 
2206
 
 
2207
    // Get IMalloc interface to use for shell pidls.
 
2208
    rc = ::SHGetMalloc(&shellMalloc);
 
2209
    if (!shellMalloc)
 
2210
      break;
 
2211
 
 
2212
    // Convert folder path to pidl.  This requires the Unicode path name.
 
2213
    // It returns a pidl that must be freed via shellMalloc->Free.
 
2214
    ULONG eaten = 0;
 
2215
    rc = desktopFolder->ParseDisplayName( 0,
 
2216
                                          0,
 
2217
                                          (LPOLESTR)unicodePath.get(),
 
2218
                                          &eaten,
 
2219
                                          &folder_pidl,
 
2220
                                          0 );
 
2221
    if (!folder_pidl)
 
2222
      break;
 
2223
 
 
2224
    // Now get IShellFolder interface for the folder we opened.
 
2225
    rc = desktopFolder->BindToObject( folder_pidl,
 
2226
                                      0,
 
2227
                                      IID_IShellFolder,
 
2228
                                      (void**)&folder );
 
2229
    if (!folder)
 
2230
      break;
 
2231
 
 
2232
    // Now get file name pidl from that folder.
 
2233
    nsAutoString unicodeLeaf;
 
2234
    if (NS_FAILED(GetLeafName(unicodeLeaf)))
 
2235
      break;
 
2236
    rc = folder->ParseDisplayName( 0,
 
2237
                                   0,
 
2238
                                   (LPOLESTR)unicodeLeaf.get(),
 
2239
                                   &eaten,
 
2240
                                   &file_pidl,
 
2241
                                   0 );
 
2242
    if (!file_pidl)
 
2243
      break;
 
2244
 
 
2245
    // We need the module handle for shell32.dll.
 
2246
    shell32 = ::GetModuleHandle("shell32.dll");
 
2247
    if (!shell32)
 
2248
      break;
 
2249
 
 
2250
    // Allocate shared memory copy of pidl.  This uses the undocumented "SHAllocShared"
 
2251
    // function.  Note that it is freed automatically after the ::SendMessage so we
 
2252
    // don't have to free it.
 
2253
    static HANDLE(WINAPI*SHAllocShared)(LPVOID,ULONG,DWORD) = (HANDLE(WINAPI*)(LPVOID,ULONG,DWORD))::GetProcAddress(shell32, (LPCTSTR)520);
 
2254
    HANDLE pidlHandle = 0;
 
2255
    if (SHAllocShared)
 
2256
    {
 
2257
      // We need the size of the pidl, which we get via another undocumented
 
2258
      // API: "ILGetSize".
 
2259
      UINT (WINAPI*ILGetSize)(LPCITEMIDLIST) = (UINT(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32, (LPCTSTR)152);
 
2260
      if (!ILGetSize)
 
2261
        break;
 
2262
      pidlHandle = SHAllocShared((void*)(ITEMIDLIST*)file_pidl,
 
2263
                                 ILGetSize(file_pidl),
 
2264
                                 pid);
 
2265
      if (!pidlHandle)
 
2266
        break;
 
2267
    }
 
2268
    else
 
2269
    {
 
2270
      // On Win95, there is no SHAllocShared.  Instead, we clone the file's pidl in
 
2271
      // the shell's global heap (via ILGlobalClone) and pass that.
 
2272
      LPITEMIDLIST(WINAPI*ILGlobalClone)(LPCITEMIDLIST) = (LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32, (LPCTSTR)20);
 
2273
      if (!ILGlobalClone)
 
2274
        break;
 
2275
      win95_file_pidl = ILGlobalClone(file_pidl);
 
2276
      if (!win95_file_pidl)
 
2277
        break;
 
2278
      // Arrange so that this pidl is passed on the ::SendMessage.
 
2279
      pidlHandle = win95_file_pidl;
 
2280
    }
 
2281
 
 
2282
    // Send message to select this file.
 
2283
    ::SendMessage(fgWin,
 
2284
                  WM_USER+5,
 
2285
                  SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE,
 
2286
                  (LPARAM)pidlHandle );
 
2287
  } while ( PR_FALSE );
 
2288
 
 
2289
  // Clean up (freeing stuff as needed, in reverse order).
 
2290
  if (win95_file_pidl)
 
2291
  {
 
2292
    // We need to free this using ILGlobalFree, another undocumented API.
 
2293
    static void (WINAPI*ILGlobalFree)(LPCITEMIDLIST) = (void(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32,(LPCTSTR)156);
 
2294
    if (ILGlobalFree)
 
2295
      ILGlobalFree(win95_file_pidl);
 
2296
  }
 
2297
  if (file_pidl)
 
2298
    shellMalloc->Free(file_pidl);
 
2299
  if (folder_pidl)
 
2300
    shellMalloc->Free(folder_pidl);
 
2301
  if (folder)
 
2302
    folder->Release();
 
2303
  if (shellMalloc)
 
2304
    shellMalloc->Release();
 
2305
  if (desktopFolder)
 
2306
    desktopFolder->Release();
 
2307
 
 
2308
  return rv;
 
2309
}
 
2310
 
 
2311
 
 
2312
NS_IMETHODIMP
 
2313
nsLocalFile::Launch()
 
2314
{
 
2315
    nsresult rv = NS_OK;
 
2316
    const nsCString &path = mWorkingPath;
 
2317
 
 
2318
    // use the app registry name to launch a shell execute....
 
2319
    LONG r = (LONG) ::ShellExecute( NULL, NULL, path.get(), NULL, NULL, SW_SHOWNORMAL);
 
2320
 
 
2321
    // if the file has no association, we launch windows' "what do you want to do" dialog
 
2322
    if (r == SE_ERR_NOASSOC) {
 
2323
        nsCAutoString shellArg;
 
2324
        shellArg.Assign(NS_LITERAL_CSTRING("shell32.dll,OpenAs_RunDLL ") + path);
 
2325
        r = (LONG) ::ShellExecute(NULL, NULL, "RUNDLL32.EXE",  shellArg.get(),
 
2326
                                  NULL, SW_SHOWNORMAL);
 
2327
    }
 
2328
    if (r < 32) {
 
2329
        switch (r) {
 
2330
          case 0:
 
2331
          case SE_ERR_OOM:
 
2332
            return NS_ERROR_OUT_OF_MEMORY;
 
2333
          case ERROR_FILE_NOT_FOUND:
 
2334
            return NS_ERROR_FILE_NOT_FOUND;
 
2335
          case ERROR_PATH_NOT_FOUND:
 
2336
            return NS_ERROR_FILE_UNRECOGNIZED_PATH;
 
2337
          case ERROR_BAD_FORMAT:
 
2338
            return NS_ERROR_FILE_CORRUPTED;
 
2339
          case SE_ERR_ACCESSDENIED:
 
2340
            return NS_ERROR_FILE_ACCESS_DENIED;
 
2341
          case SE_ERR_ASSOCINCOMPLETE:
 
2342
          case SE_ERR_NOASSOC:
 
2343
            return NS_ERROR_UNEXPECTED;
 
2344
          case SE_ERR_DDEBUSY:
 
2345
          case SE_ERR_DDEFAIL:
 
2346
          case SE_ERR_DDETIMEOUT:
 
2347
            return NS_ERROR_NOT_AVAILABLE;
 
2348
          case SE_ERR_DLLNOTFOUND:
 
2349
            return NS_ERROR_FAILURE;
 
2350
          case SE_ERR_SHARE:
 
2351
            return NS_ERROR_FILE_IS_LOCKED;
 
2352
          default:
 
2353
            return NS_ERROR_FILE_EXECUTION_FAILED;
 
2354
        }
 
2355
    }
 
2356
    return NS_OK;
 
2357
}
 
2358
 
 
2359
nsresult
 
2360
NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result)
 
2361
{
 
2362
    nsLocalFile* file = new nsLocalFile();
 
2363
    if (file == nsnull)
 
2364
        return NS_ERROR_OUT_OF_MEMORY;
 
2365
    NS_ADDREF(file);
 
2366
 
 
2367
    file->SetFollowLinks(followLinks);
 
2368
 
 
2369
    if (!path.IsEmpty()) {
 
2370
        nsresult rv = file->InitWithNativePath(path);
 
2371
        if (NS_FAILED(rv)) {
 
2372
            NS_RELEASE(file);
 
2373
            return rv;
 
2374
        }
 
2375
    }
 
2376
 
 
2377
    *result = file;
 
2378
    return NS_OK;
 
2379
}
 
2380
 
 
2381
//-----------------------------------------------------------------------------
 
2382
// UCS2 interface
 
2383
//-----------------------------------------------------------------------------
 
2384
 
 
2385
nsresult
 
2386
nsLocalFile::InitWithPath(const nsAString &filePath)
 
2387
{
 
2388
    nsCAutoString tmp;
 
2389
    nsresult rv = NS_CopyUnicodeToNative(filePath, tmp);
 
2390
    if (NS_SUCCEEDED(rv))
 
2391
        return InitWithNativePath(tmp);
 
2392
 
 
2393
    return rv;
 
2394
}
 
2395
 
 
2396
nsresult
 
2397
nsLocalFile::Append(const nsAString &node)
 
2398
{
 
2399
    nsCAutoString tmp;
 
2400
    nsresult rv = NS_CopyUnicodeToNative(node, tmp);
 
2401
    if (NS_SUCCEEDED(rv))
 
2402
        return AppendNative(tmp);
 
2403
 
 
2404
    return rv;
 
2405
}
 
2406
 
 
2407
nsresult
 
2408
nsLocalFile::AppendRelativePath(const nsAString &node)
 
2409
{
 
2410
    nsCAutoString tmp;
 
2411
    nsresult rv = NS_CopyUnicodeToNative(node, tmp);
 
2412
    if (NS_SUCCEEDED(rv))
 
2413
        return AppendRelativeNativePath(tmp);
 
2414
    return rv;
 
2415
}
 
2416
 
 
2417
nsresult
 
2418
nsLocalFile::GetLeafName(nsAString &aLeafName)
 
2419
{
 
2420
    nsCAutoString tmp;
 
2421
    nsresult rv = GetNativeLeafName(tmp);
 
2422
    if (NS_SUCCEEDED(rv))
 
2423
        rv = NS_CopyNativeToUnicode(tmp, aLeafName);
 
2424
 
 
2425
    return rv;
 
2426
}
 
2427
 
 
2428
nsresult
 
2429
nsLocalFile::SetLeafName(const nsAString &aLeafName)
 
2430
{
 
2431
    nsCAutoString tmp;
 
2432
    nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp);
 
2433
    if (NS_SUCCEEDED(rv))
 
2434
        return SetNativeLeafName(tmp);
 
2435
 
 
2436
    return rv;
 
2437
}
 
2438
 
 
2439
nsresult
 
2440
nsLocalFile::GetPath(nsAString &_retval)
 
2441
{
 
2442
    return NS_CopyNativeToUnicode(mWorkingPath, _retval);
 
2443
}
 
2444
 
 
2445
nsresult
 
2446
nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName)
 
2447
{
 
2448
    if (newName.IsEmpty())
 
2449
        return CopyToNative(newParentDir, nsCString());
 
2450
 
 
2451
    nsCAutoString tmp;
 
2452
    nsresult rv = NS_CopyUnicodeToNative(newName, tmp);
 
2453
    if (NS_SUCCEEDED(rv))
 
2454
        return CopyToNative(newParentDir, tmp);
 
2455
 
 
2456
    return rv;
 
2457
}
 
2458
 
 
2459
nsresult
 
2460
nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName)
 
2461
{
 
2462
    if (newName.IsEmpty())
 
2463
        return CopyToFollowingLinksNative(newParentDir, nsCString());
 
2464
 
 
2465
    nsCAutoString tmp;
 
2466
    nsresult rv = NS_CopyUnicodeToNative(newName, tmp);
 
2467
    if (NS_SUCCEEDED(rv))
 
2468
        return CopyToFollowingLinksNative(newParentDir, tmp);
 
2469
 
 
2470
    return rv;
 
2471
}
 
2472
 
 
2473
nsresult
 
2474
nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName)
 
2475
{
 
2476
    if (newName.IsEmpty())
 
2477
        return MoveToNative(newParentDir, nsCString());
 
2478
 
 
2479
    nsCAutoString tmp;
 
2480
    nsresult rv = NS_CopyUnicodeToNative(newName, tmp);
 
2481
    if (NS_SUCCEEDED(rv))
 
2482
        return MoveToNative(newParentDir, tmp);
 
2483
 
 
2484
    return rv;
 
2485
}
 
2486
 
 
2487
nsresult
 
2488
nsLocalFile::GetTarget(nsAString &_retval)
 
2489
{
 
2490
    nsCAutoString tmp;
 
2491
    nsresult rv = GetNativeTarget(tmp);
 
2492
    if (NS_SUCCEEDED(rv))
 
2493
        rv = NS_CopyNativeToUnicode(tmp, _retval);
 
2494
 
 
2495
    return rv;
 
2496
}
 
2497
 
 
2498
nsresult
 
2499
NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result)
 
2500
{
 
2501
    nsCAutoString buf;
 
2502
    nsresult rv = NS_CopyUnicodeToNative(path, buf);
 
2503
    if (NS_FAILED(rv)) {
 
2504
        *result = nsnull;
 
2505
        return rv;
 
2506
    }
 
2507
    return NS_NewNativeLocalFile(buf, followLinks, result);
 
2508
}
 
2509
 
 
2510
//-----------------------------------------------------------------------------
 
2511
// nsLocalFile <static members>
 
2512
//-----------------------------------------------------------------------------
 
2513
 
 
2514
void
 
2515
nsLocalFile::GlobalInit()
 
2516
{
 
2517
    nsresult rv = NS_CreateShortcutResolver();
 
2518
    NS_ASSERTION(NS_SUCCEEDED(rv), "Shortcut resolver could not be created");
 
2519
}
 
2520
 
 
2521
void
 
2522
nsLocalFile::GlobalShutdown()
 
2523
{
 
2524
    NS_DestroyShortcutResolver();
 
2525
}