1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
15 * The Original Code is Mozilla Communicator client code, released
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998-1999
21 * the Initial Developer. All Rights Reserved.
24 * Mike Shaver <shaver@mozilla.org>
25 * Christopher Blizzard <blizzard@mozilla.org>
26 * Jason Eager <jce2@po.cwru.edu>
27 * Stuart Parmenter <pavlov@netscape.com>
28 * Brendan Eich <brendan@mozilla.org>
29 * Pete Collins <petejc@mozdev.org>
30 * Paul Ashford <arougthopher@lizardland.net>
31 * Fredrik Holmqvist <thesuckiestemail@yahoo.se>
32 * Josh Aas <josh@mozilla.com>
34 * Alternatively, the contents of this file may be used under the terms of
35 * either of the GNU General Public License Version 2 or later (the "GPL"),
36 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 * in which case the provisions of the GPL or the LGPL are applicable instead
38 * of those above. If you wish to allow use of your version of this file only
39 * under the terms of either the GPL or the LGPL, and not to allow others to
40 * use your version of this file under the terms of the MPL, indicate your
41 * decision by deleting the provisions above and replace them with the notice
42 * and other provisions required by the GPL or the LGPL. If you do not delete
43 * the provisions above, a recipient may use your version of this file under
44 * the terms of any one of the MPL, the GPL or the LGPL.
46 * ***** END LICENSE BLOCK ***** */
49 * Implementation of nsIFile for ``Unixy'' systems.
52 #include <sys/types.h>
70 #include "nsDirectoryServiceDefs.h"
76 #include "nsReadableUtils.h"
77 #include "nsLocalFile.h"
78 #include "nsIComponentManager.h"
79 #include "nsXPIDLString.h"
81 #include "nsIDirectoryEnumerator.h"
82 #include "nsISimpleEnumerator.h"
83 #include "nsITimelineService.h"
85 #ifdef MOZ_WIDGET_GTK2
86 #include "nsIGnomeVFSService.h"
89 #include "nsNativeCharsetUtils.h"
90 #include "nsTraceRefcntImpl.h"
92 // On some platforms file/directory name comparisons need to
95 #define FILE_STRCMP strcasecmp
96 #define FILE_STRNCMP strncasecmp
98 #define FILE_STRCMP strcmp
99 #define FILE_STRNCMP strncmp
102 #define ENSURE_STAT_CACHE() \
104 if (!FillStatCache()) \
105 return NSRESULT_FOR_ERRNO(); \
108 #define CHECK_mPath() \
110 if (mPath.IsEmpty()) \
111 return NS_ERROR_NOT_INITIALIZED; \
114 /* directory enumerator */
116 nsDirEnumeratorUnix
: public nsISimpleEnumerator
,
117 public nsIDirectoryEnumerator
120 nsDirEnumeratorUnix();
122 // nsISupports interface
125 // nsISimpleEnumerator interface
126 NS_DECL_NSISIMPLEENUMERATOR
128 // nsIDirectoryEnumerator interface
129 NS_DECL_NSIDIRECTORYENUMERATOR
131 NS_IMETHOD
Init(nsLocalFile
*parent
, PRBool ignored
);
134 ~nsDirEnumeratorUnix();
137 NS_IMETHOD
GetNextEntry();
140 struct dirent
*mEntry
;
141 nsCString mParentPath
;
144 nsDirEnumeratorUnix::nsDirEnumeratorUnix() :
150 nsDirEnumeratorUnix::~nsDirEnumeratorUnix()
155 NS_IMPL_ISUPPORTS2(nsDirEnumeratorUnix
, nsISimpleEnumerator
, nsIDirectoryEnumerator
)
158 nsDirEnumeratorUnix::Init(nsLocalFile
*parent
, PRBool resolveSymlinks
/*ignored*/)
160 nsCAutoString dirPath
;
161 if (NS_FAILED(parent
->GetNativePath(dirPath
)) ||
163 return NS_ERROR_FILE_INVALID_PATH
;
166 if (NS_FAILED(parent
->GetNativePath(mParentPath
)))
167 return NS_ERROR_FAILURE
;
169 mDir
= opendir(dirPath
.get());
171 return NSRESULT_FOR_ERRNO();
172 return GetNextEntry();
176 nsDirEnumeratorUnix::HasMoreElements(PRBool
*result
)
178 *result
= mDir
&& mEntry
;
185 nsDirEnumeratorUnix::GetNext(nsISupports
**_retval
)
187 nsCOMPtr
<nsIFile
> file
;
188 nsresult rv
= GetNextFile(getter_AddRefs(file
));
191 NS_IF_ADDREF(*_retval
= file
);
196 nsDirEnumeratorUnix::GetNextEntry()
200 mEntry
= readdir(mDir
);
202 // end of dir or error
204 return NSRESULT_FOR_ERRNO();
206 // keep going past "." and ".."
207 } while (mEntry
->d_name
[0] == '.' &&
208 (mEntry
->d_name
[1] == '\0' || // .\0
209 (mEntry
->d_name
[1] == '.' &&
210 mEntry
->d_name
[2] == '\0'))); // ..\0
215 nsDirEnumeratorUnix::GetNextFile(nsIFile
**_retval
)
218 if (!mDir
|| !mEntry
) {
223 nsCOMPtr
<nsILocalFile
> file
= new nsLocalFile();
225 return NS_ERROR_OUT_OF_MEMORY
;
227 if (NS_FAILED(rv
= file
->InitWithNativePath(mParentPath
)) ||
228 NS_FAILED(rv
= file
->AppendNative(nsDependentCString(mEntry
->d_name
))))
233 return GetNextEntry();
237 nsDirEnumeratorUnix::Close()
246 nsLocalFile::nsLocalFile()
250 nsLocalFile::nsLocalFile(const nsLocalFile
& other
)
255 NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile
,
261 nsLocalFile::nsLocalFileConstructor(nsISupports
*outer
,
265 NS_ENSURE_ARG_POINTER(aInstancePtr
);
266 NS_ENSURE_NO_AGGREGATION(outer
);
268 *aInstancePtr
= nsnull
;
270 nsCOMPtr
<nsIFile
> inst
= new nsLocalFile();
272 return NS_ERROR_OUT_OF_MEMORY
;
273 return inst
->QueryInterface(aIID
, aInstancePtr
);
277 nsLocalFile::FillStatCache() {
279 if (stat64(mPath
.get(), &mCachedStat
) == -1) {
280 // try lstat it may be a symlink
281 if (lstat64(mPath
.get(), &mCachedStat
) == -1) {
286 if (stat(mPath
.get(), &mCachedStat
) == -1) {
287 // try lstat it may be a symlink
288 if (lstat(mPath
.get(), &mCachedStat
) == -1) {
297 nsLocalFile::Clone(nsIFile
**file
)
299 // Just copy-construct ourselves
300 *file
= new nsLocalFile(*this);
302 return NS_ERROR_OUT_OF_MEMORY
;
310 nsLocalFile::InitWithNativePath(const nsACString
&filePath
)
312 if (Substring(filePath
, 0, 2).EqualsLiteral("~/")) {
313 nsCOMPtr
<nsIFile
> homeDir
;
314 nsCAutoString homePath
;
315 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR
,
316 getter_AddRefs(homeDir
))) ||
317 NS_FAILED(homeDir
->GetNativePath(homePath
))) {
318 return NS_ERROR_FAILURE
;
321 mPath
= homePath
+ Substring(filePath
, 1, filePath
.Length() - 1);
323 if (filePath
.IsEmpty() || filePath
.First() != '/')
324 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
328 // trim off trailing slashes
329 ssize_t len
= mPath
.Length();
330 while ((len
> 1) && (mPath
[len
- 1] == '/'))
332 mPath
.SetLength(len
);
338 nsLocalFile::CreateAllAncestors(PRUint32 permissions
)
340 // <jband> I promise to play nice
341 char *buffer
= mPath
.BeginWriting(),
345 fprintf(stderr
, "nsIFile: before: %s\n", buffer
);
348 while ((slashp
= strchr(slashp
+ 1, '/'))) {
350 * Sequences of '/' are equivalent to a single '/'.
352 if (slashp
[1] == '/')
356 * If the path has a trailing slash, don't make the last component,
357 * because we'll get EEXIST in Create when we try to build the final
358 * component again, and it's easier to condition the logic here than
361 if (slashp
[1] == '\0')
364 /* Temporarily NUL-terminate here */
367 fprintf(stderr
, "nsIFile: mkdir(\"%s\")\n", buffer
);
369 int mkdir_result
= mkdir(buffer
, permissions
);
370 int mkdir_errno
= errno
;
371 if (mkdir_result
== -1) {
373 * Always set |errno| to EEXIST if the dir already exists
374 * (we have to do this here since the errno value is not consistent
375 * in all cases - various reasons like different platform,
376 * automounter-controlled dir, etc. can affect it (see bug 125489
379 if (access(buffer
, F_OK
) == 0) {
380 mkdir_errno
= EEXIST
;
384 /* Put the / back before we (maybe) return */
388 * We could get EEXIST for an existing file -- not directory --
389 * with the name of one of our ancestors, but that's OK: we'll get
390 * ENOTDIR when we try to make the next component in the path,
391 * either here on back in Create, and error out appropriately.
393 if (mkdir_result
== -1 && mkdir_errno
!= EEXIST
)
394 return nsresultForErrno(mkdir_errno
);
398 fprintf(stderr
, "nsIFile: after: %s\n", buffer
);
405 nsLocalFile::OpenNSPRFileDesc(PRInt32 flags
, PRInt32 mode
, PRFileDesc
**_retval
)
407 *_retval
= PR_Open(mPath
.get(), flags
, mode
);
409 return NS_ErrorAccordingToNSPR();
415 nsLocalFile::OpenANSIFileDesc(const char *mode
, FILE **_retval
)
417 *_retval
= fopen(mPath
.get(), mode
);
419 return NS_ERROR_FAILURE
;
425 do_create(const char *path
, PRIntn flags
, mode_t mode
, PRFileDesc
**_retval
)
427 *_retval
= PR_Open(path
, flags
, mode
);
428 return *_retval
? 0 : -1;
432 do_mkdir(const char *path
, PRIntn flags
, mode_t mode
, PRFileDesc
**_retval
)
435 return mkdir(path
, mode
);
439 nsLocalFile::CreateAndKeepOpen(PRUint32 type
, PRIntn flags
,
440 PRUint32 permissions
, PRFileDesc
**_retval
)
442 if (type
!= NORMAL_FILE_TYPE
&& type
!= DIRECTORY_TYPE
)
443 return NS_ERROR_FILE_UNKNOWN_TYPE
;
446 int (*createFunc
)(const char *, PRIntn
, mode_t
, PRFileDesc
**) =
447 (type
== NORMAL_FILE_TYPE
) ? do_create
: do_mkdir
;
449 result
= createFunc(mPath
.get(), flags
, permissions
, _retval
);
450 if (result
== -1 && errno
== ENOENT
) {
452 * If we failed because of missing ancestor components, try to create
453 * them and then retry the original creation.
455 * Ancestor directories get the same permissions as the file we're
456 * creating, with the X bit set for each of (user,group,other) with
457 * an R bit in the original permissions. If you want to do anything
458 * fancy like setgid or sticky bits, do it by hand.
460 int dirperm
= permissions
;
461 if (permissions
& S_IRUSR
)
463 if (permissions
& S_IRGRP
)
465 if (permissions
& S_IROTH
)
469 fprintf(stderr
, "nsIFile: perm = %o, dirperm = %o\n", permissions
,
473 if (NS_FAILED(CreateAllAncestors(dirperm
)))
474 return NS_ERROR_FAILURE
;
477 fprintf(stderr
, "nsIFile: Create(\"%s\") again\n", mPath
.get());
479 result
= createFunc(mPath
.get(), flags
, permissions
, _retval
);
481 return NSRESULT_FOR_RETURN(result
);
485 nsLocalFile::Create(PRUint32 type
, PRUint32 permissions
)
487 PRFileDesc
*junk
= nsnull
;
488 nsresult rv
= CreateAndKeepOpen(type
,
489 PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
|
499 nsLocalFile::AppendNative(const nsACString
&fragment
)
501 if (fragment
.IsEmpty())
504 // only one component of path can be appended
505 nsACString::const_iterator begin
, end
;
506 if (FindCharInReadable('/', fragment
.BeginReading(begin
),
507 fragment
.EndReading(end
)))
508 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
510 return AppendRelativeNativePath(fragment
);
514 nsLocalFile::AppendRelativeNativePath(const nsACString
&fragment
)
516 if (fragment
.IsEmpty())
520 if (fragment
.First() == '/')
521 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
523 if (mPath
.EqualsLiteral("/"))
524 mPath
.Append(fragment
);
526 mPath
.Append(NS_LITERAL_CSTRING("/") + fragment
);
532 nsLocalFile::Normalize()
534 char resolved_path
[PATH_MAX
] = "";
535 char *resolved_path_ptr
= nsnull
;
538 BEntry
be_e(mPath
.get(), true);
541 if ((err
= be_e
.GetPath(&be_p
)) == B_OK
) {
542 resolved_path_ptr
= (char *)be_p
.Path();
543 PL_strncpyz(resolved_path
, resolved_path_ptr
, PATH_MAX
- 1);
546 resolved_path_ptr
= realpath(mPath
.get(), resolved_path
);
548 // if there is an error, the return is null.
549 if (!resolved_path_ptr
)
550 return NSRESULT_FOR_ERRNO();
552 mPath
= resolved_path
;
557 nsLocalFile::LocateNativeLeafName(nsACString::const_iterator
&begin
,
558 nsACString::const_iterator
&end
)
560 // XXX perhaps we should cache this??
562 mPath
.BeginReading(begin
);
563 mPath
.EndReading(end
);
565 nsACString::const_iterator it
= end
;
566 nsACString::const_iterator stop
= begin
;
568 while (--it
!= stop
) {
574 // else, the entire path is the leaf name (which means this
575 // isn't an absolute path... unexpected??)
579 nsLocalFile::GetNativeLeafName(nsACString
&aLeafName
)
581 nsACString::const_iterator begin
, end
;
582 LocateNativeLeafName(begin
, end
);
583 aLeafName
= Substring(begin
, end
);
588 nsLocalFile::SetNativeLeafName(const nsACString
&aLeafName
)
590 nsACString::const_iterator begin
, end
;
591 LocateNativeLeafName(begin
, end
);
592 mPath
.Replace(begin
.get() - mPath
.get(), Distance(begin
, end
), aLeafName
);
597 nsLocalFile::GetNativePath(nsACString
&_retval
)
604 nsLocalFile::GetNativeTargetPathName(nsIFile
*newParent
,
605 const nsACString
&newName
,
609 nsCOMPtr
<nsIFile
> oldParent
;
612 if (NS_FAILED(rv
= GetParent(getter_AddRefs(oldParent
))))
614 newParent
= oldParent
.get();
616 // check to see if our target directory exists
618 if (NS_FAILED(rv
= newParent
->Exists(&targetExists
)))
622 // XXX create the new directory with some permissions
623 rv
= newParent
->Create(DIRECTORY_TYPE
, 0755);
627 // make sure that the target is actually a directory
628 PRBool targetIsDirectory
;
629 if (NS_FAILED(rv
= newParent
->IsDirectory(&targetIsDirectory
)))
631 if (!targetIsDirectory
)
632 return NS_ERROR_FILE_DESTINATION_NOT_DIR
;
636 nsACString::const_iterator nameBegin
, nameEnd
;
637 if (!newName
.IsEmpty()) {
638 newName
.BeginReading(nameBegin
);
639 newName
.EndReading(nameEnd
);
642 LocateNativeLeafName(nameBegin
, nameEnd
);
644 nsCAutoString dirName
;
645 if (NS_FAILED(rv
= newParent
->GetNativePath(dirName
)))
649 + NS_LITERAL_CSTRING("/")
650 + Substring(nameBegin
, nameEnd
);
655 nsLocalFile::CopyDirectoryTo(nsIFile
*newParent
)
659 * dirCheck is used for various boolean test results such as from Equals,
660 * Exists, isDir, etc.
662 PRBool dirCheck
, isSymlink
;
665 if (NS_FAILED(rv
= IsDirectory(&dirCheck
)))
668 return CopyToNative(newParent
, EmptyCString());
670 if (NS_FAILED(rv
= Equals(newParent
, &dirCheck
)))
673 // can't copy dir to itself
674 return NS_ERROR_INVALID_ARG
;
677 if (NS_FAILED(rv
= newParent
->Exists(&dirCheck
)))
679 // get the dirs old permissions
680 if (NS_FAILED(rv
= GetPermissions(&oldPerms
)))
683 if (NS_FAILED(rv
= newParent
->Create(DIRECTORY_TYPE
, oldPerms
)))
685 } else { // dir exists lets try to use leaf
686 nsCAutoString leafName
;
687 if (NS_FAILED(rv
= GetNativeLeafName(leafName
)))
689 if (NS_FAILED(rv
= newParent
->AppendNative(leafName
)))
691 if (NS_FAILED(rv
= newParent
->Exists(&dirCheck
)))
694 return NS_ERROR_FILE_ALREADY_EXISTS
; // dest exists
695 if (NS_FAILED(rv
= newParent
->Create(DIRECTORY_TYPE
, oldPerms
)))
699 nsCOMPtr
<nsISimpleEnumerator
> dirIterator
;
700 if (NS_FAILED(rv
= GetDirectoryEntries(getter_AddRefs(dirIterator
))))
703 PRBool hasMore
= PR_FALSE
;
704 while (dirIterator
->HasMoreElements(&hasMore
), hasMore
) {
705 nsCOMPtr
<nsIFile
> entry
;
706 rv
= dirIterator
->GetNext((nsISupports
**)getter_AddRefs(entry
));
709 if (NS_FAILED(rv
= entry
->IsSymlink(&isSymlink
)))
711 if (NS_FAILED(rv
= entry
->IsDirectory(&dirCheck
)))
713 if (dirCheck
&& !isSymlink
) {
714 nsCOMPtr
<nsIFile
> destClone
;
715 rv
= newParent
->Clone(getter_AddRefs(destClone
));
716 if (NS_SUCCEEDED(rv
)) {
717 nsCOMPtr
<nsILocalFile
> newDir(do_QueryInterface(destClone
));
718 if (NS_FAILED(rv
= entry
->CopyToNative(newDir
, EmptyCString()))) {
721 nsCAutoString pathName
;
722 if (NS_FAILED(rv2
= entry
->GetNativePath(pathName
)))
724 printf("Operation not supported: %s\n", pathName
.get());
726 if (rv
== NS_ERROR_OUT_OF_MEMORY
)
732 if (NS_FAILED(rv
= entry
->CopyToNative(newParent
, EmptyCString()))) {
735 nsCAutoString pathName
;
736 if (NS_FAILED(rv2
= entry
->GetNativePath(pathName
)))
738 printf("Operation not supported: %s\n", pathName
.get());
740 if (rv
== NS_ERROR_OUT_OF_MEMORY
)
750 nsLocalFile::CopyToNative(nsIFile
*newParent
, const nsACString
&newName
)
753 // check to make sure that this has been initialized properly
756 // we copy the parent here so 'newParent' remains immutable
757 nsCOMPtr
<nsIFile
> workParent
;
759 if (NS_FAILED(rv
= newParent
->Clone(getter_AddRefs(workParent
))))
762 if (NS_FAILED(rv
= GetParent(getter_AddRefs(workParent
))))
766 // check to see if we are a directory or if we are a file
768 if (NS_FAILED(rv
= IsDirectory(&isDirectory
)))
771 nsCAutoString newPathName
;
773 if (!newName
.IsEmpty()) {
774 if (NS_FAILED(rv
= workParent
->AppendNative(newName
)))
777 if (NS_FAILED(rv
= GetNativeLeafName(newPathName
)))
779 if (NS_FAILED(rv
= workParent
->AppendNative(newPathName
)))
782 if (NS_FAILED(rv
= CopyDirectoryTo(workParent
)))
785 rv
= GetNativeTargetPathName(workParent
, newName
, newPathName
);
789 #ifdef DEBUG_blizzard
790 printf("nsLocalFile::CopyTo() %s -> %s\n", mPath
.get(), newPathName
.get());
793 // actually create the file.
794 nsLocalFile
*newFile
= new nsLocalFile();
796 return NS_ERROR_OUT_OF_MEMORY
;
798 nsCOMPtr
<nsILocalFile
> fileRef(newFile
); // release on exit
800 rv
= newFile
->InitWithNativePath(newPathName
);
804 // get the old permissions
806 GetPermissions(&myPerms
);
808 // Create the new file with the old file's permissions, even if write
809 // permission is missing. We can't create with write permission and
810 // then change back to myPerm on all filesystems (FAT on Linux, e.g.).
811 // But we can write to a read-only file on all Unix filesystems if we
812 // open it successfully for writing.
815 rv
= newFile
->CreateAndKeepOpen(NORMAL_FILE_TYPE
,
816 PR_WRONLY
|PR_CREATE_FILE
|PR_TRUNCATE
,
822 // open the old file, too
824 if (NS_FAILED(rv
= IsSpecial(&specialFile
))) {
830 printf("Operation not supported: %s\n", mPath
.get());
832 // make sure to clean up properly
838 rv
= OpenNSPRFileDesc(PR_RDONLY
, myPerms
, &oldFD
);
840 // make sure to clean up properly
845 #ifdef DEBUG_blizzard
846 PRInt32 totalRead
= 0;
847 PRInt32 totalWritten
= 0;
852 while ((bytesRead
= PR_Read(oldFD
, buf
, BUFSIZ
)) > 0) {
853 #ifdef DEBUG_blizzard
854 totalRead
+= bytesRead
;
857 // PR_Write promises never to do a short write
858 PRInt32 bytesWritten
= PR_Write(newFD
, buf
, bytesRead
);
859 if (bytesWritten
< 0) {
863 NS_ASSERTION(bytesWritten
== bytesRead
, "short PR_Write?");
865 #ifdef DEBUG_blizzard
866 totalWritten
+= bytesWritten
;
870 #ifdef DEBUG_blizzard
871 printf("read %d bytes, wrote %d bytes\n",
872 totalRead
, totalWritten
);
879 // check for read (or write) error after cleaning up
881 return NS_ERROR_OUT_OF_MEMORY
;
887 nsLocalFile::CopyToFollowingLinksNative(nsIFile
*newParent
, const nsACString
&newName
)
889 return CopyToNative(newParent
, newName
);
893 nsLocalFile::MoveToNative(nsIFile
*newParent
, const nsACString
&newName
)
897 // check to make sure that this has been initialized properly
900 // check to make sure that we have a new parent
901 nsCAutoString newPathName
;
902 rv
= GetNativeTargetPathName(newParent
, newName
, newPathName
);
906 // try for atomic rename, falling back to copy/delete
907 if (rename(mPath
.get(), newPathName
.get()) < 0) {
909 if (errno
== EXDEV
|| errno
== ENXIO
) {
911 if (errno
== EXDEV
) {
913 rv
= CopyToNative(newParent
, newName
);
914 if (NS_SUCCEEDED(rv
))
915 rv
= Remove(PR_TRUE
);
917 rv
= NSRESULT_FOR_ERRNO();
924 nsLocalFile::Remove(PRBool recursive
)
931 nsresult rv
= IsSymlink(&isSymLink
);
935 if (!recursive
&& isSymLink
)
936 return NSRESULT_FOR_RETURN(unlink(mPath
.get()));
938 if (S_ISDIR(mCachedStat
.st_mode
)) {
940 nsDirEnumeratorUnix
*dir
= new nsDirEnumeratorUnix();
942 return NS_ERROR_OUT_OF_MEMORY
;
944 nsCOMPtr
<nsISimpleEnumerator
> dirRef(dir
); // release on exit
946 rv
= dir
->Init(this, PR_FALSE
);
951 while (dir
->HasMoreElements(&more
), more
) {
952 nsCOMPtr
<nsISupports
> item
;
953 rv
= dir
->GetNext(getter_AddRefs(item
));
955 return NS_ERROR_FAILURE
;
957 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(item
, &rv
);
959 return NS_ERROR_FAILURE
;
960 if (NS_FAILED(rv
= file
->Remove(recursive
)))
965 if (rmdir(mPath
.get()) == -1)
966 return NSRESULT_FOR_ERRNO();
968 if (unlink(mPath
.get()) == -1)
969 return NSRESULT_FOR_ERRNO();
976 nsLocalFile::GetLastModifiedTime(PRInt64
*aLastModTime
)
979 NS_ENSURE_ARG(aLastModTime
);
982 if (PR_GetFileInfo64(mPath
.get(), &info
) != PR_SUCCESS
)
983 return NSRESULT_FOR_ERRNO();
985 // PRTime is a 64 bit value
986 // microseconds -> milliseconds
988 LL_I2L(usecPerMsec
, PR_USEC_PER_MSEC
);
989 LL_DIV(*aLastModTime
, info
.modifyTime
, usecPerMsec
);
994 nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime
)
999 if (! LL_IS_ZERO(aLastModTime
)) {
1000 ENSURE_STAT_CACHE();
1002 ut
.actime
= mCachedStat
.st_atime
;
1004 // convert milliseconds to seconds since the unix epoch
1006 LL_L2D(dTime
, aLastModTime
);
1007 ut
.modtime
= (time_t) (dTime
/ PR_MSEC_PER_SEC
);
1008 result
= utime(mPath
.get(), &ut
);
1010 result
= utime(mPath
.get(), nsnull
);
1012 return NSRESULT_FOR_RETURN(result
);
1016 nsLocalFile::GetLastModifiedTimeOfLink(PRInt64
*aLastModTimeOfLink
)
1019 NS_ENSURE_ARG(aLastModTimeOfLink
);
1022 if (lstat(mPath
.get(), &sbuf
) == -1)
1023 return NSRESULT_FOR_ERRNO();
1024 LL_I2L(*aLastModTimeOfLink
, (PRInt32
)sbuf
.st_mtime
);
1026 // lstat returns st_mtime in seconds
1028 LL_I2L(msecPerSec
, PR_MSEC_PER_SEC
);
1029 LL_MUL(*aLastModTimeOfLink
, *aLastModTimeOfLink
, msecPerSec
);
1035 * utime(2) may or may not dereference symlinks, joy.
1038 nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink
)
1040 return SetLastModifiedTime(aLastModTimeOfLink
);
1044 * Only send back permissions bits: maybe we want to send back the whole
1045 * mode_t to permit checks against other file types?
1048 #define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO))
1051 nsLocalFile::GetPermissions(PRUint32
*aPermissions
)
1053 NS_ENSURE_ARG(aPermissions
);
1054 ENSURE_STAT_CACHE();
1055 *aPermissions
= NORMALIZE_PERMS(mCachedStat
.st_mode
);
1060 nsLocalFile::GetPermissionsOfLink(PRUint32
*aPermissionsOfLink
)
1063 NS_ENSURE_ARG(aPermissionsOfLink
);
1066 if (lstat(mPath
.get(), &sbuf
) == -1)
1067 return NSRESULT_FOR_ERRNO();
1068 *aPermissionsOfLink
= NORMALIZE_PERMS(sbuf
.st_mode
);
1073 nsLocalFile::SetPermissions(PRUint32 aPermissions
)
1078 * Race condition here: we should use fchmod instead, there's no way to
1079 * guarantee the name still refers to the same file.
1081 if (chmod(mPath
.get(), aPermissions
) < 0)
1082 return NSRESULT_FOR_ERRNO();
1087 nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions
)
1089 // There isn't a consistent mechanism for doing this on UNIX platforms. We
1090 // might want to carefully implement this in the future though.
1091 return NS_ERROR_NOT_IMPLEMENTED
;
1095 nsLocalFile::GetFileSize(PRInt64
*aFileSize
)
1097 NS_ENSURE_ARG_POINTER(aFileSize
);
1098 *aFileSize
= LL_ZERO
;
1099 ENSURE_STAT_CACHE();
1102 /* Only two record formats can report correct file content size */
1103 if ((mCachedStat
.st_fab_rfm
!= FAB$C_STMLF
) &&
1104 (mCachedStat
.st_fab_rfm
!= FAB$C_STMCR
)) {
1105 return NS_ERROR_FAILURE
;
1109 if (!S_ISDIR(mCachedStat
.st_mode
)) {
1111 *aFileSize
= mCachedStat
.st_size
;
1113 LL_UI2L(*aFileSize
, (PRUint32
)mCachedStat
.st_size
);
1120 nsLocalFile::SetFileSize(PRInt64 aFileSize
)
1125 LL_L2I(size
, aFileSize
);
1126 /* XXX truncate64? */
1127 if (truncate(mPath
.get(), (off_t
)size
) == -1)
1128 return NSRESULT_FOR_ERRNO();
1133 nsLocalFile::GetFileSizeOfLink(PRInt64
*aFileSize
)
1136 NS_ENSURE_ARG(aFileSize
);
1140 if (lstat64(mPath
.get(), &sbuf
) == -1)
1141 return NSRESULT_FOR_ERRNO();
1142 *aFileSize
= sbuf
.st_size
;
1145 if (lstat(mPath
.get(), &sbuf
) == -1)
1146 return NSRESULT_FOR_ERRNO();
1147 LL_UI2L(*aFileSize
, (PRUint32
)sbuf
.st_size
);
1153 nsLocalFile::GetDiskSpaceAvailable(PRInt64
*aDiskSpaceAvailable
)
1155 NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable
);
1157 // These systems have the operations necessary to check disk space.
1159 #if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H)
1161 // check to make sure that mPath is properly initialized
1164 struct STATFS fs_buf
;
1167 * Members of the STATFS struct that you should know about:
1168 * f_bsize = block size on disk.
1169 * f_bavail = number of free blocks available to a non-superuser.
1170 * f_bfree = number of total free blocks in file system.
1173 if (STATFS(mPath
.get(), &fs_buf
) < 0) {
1174 // The call to STATFS failed.
1176 printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n");
1178 return NS_ERROR_FAILURE
;
1180 #ifdef DEBUG_DISK_SPACE
1181 printf("DiskSpaceAvailable: %d bytes\n",
1182 fs_buf
.f_bsize
* (fs_buf
.f_bavail
- 1));
1186 * The number of bytes free == The number of free blocks available to
1187 * a non-superuser, minus one as a fudge factor, multiplied by the size
1188 * of the aforementioned blocks.
1190 PRInt64 bsize
, bavail
;
1192 LL_I2L(bsize
, fs_buf
.f_bsize
);
1193 LL_I2L(bavail
, fs_buf
.f_bavail
- 1);
1194 LL_MUL(*aDiskSpaceAvailable
, bsize
, bavail
);
1199 * This platform doesn't have statfs or statvfs. I'm sure that there's
1200 * a way to check for free disk space on platforms that don't have statfs
1201 * (I'm SURE they have df, for example).
1203 * Until we figure out how to do that, lets be honest and say that this
1204 * command isn't implemented properly for these platforms yet.
1207 printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n");
1209 return NS_ERROR_NOT_IMPLEMENTED
;
1211 #endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */
1216 nsLocalFile::GetParent(nsIFile
**aParent
)
1219 NS_ENSURE_ARG_POINTER(aParent
);
1222 // if '/' we are at the top of the volume, return null
1223 if (mPath
.Equals("/"))
1226 // <brendan, after jband> I promise to play nice
1227 char *buffer
= mPath
.BeginWriting(),
1230 // find the last significant slash in buffer
1231 slashp
= strrchr(buffer
, '/');
1232 NS_ASSERTION(slashp
, "non-canonical mPath?");
1234 return NS_ERROR_FILE_INVALID_PATH
;
1236 // for the case where we are at '/'
1237 if (slashp
== buffer
)
1240 // temporarily terminate buffer at the last significant slash
1244 nsCOMPtr
<nsILocalFile
> localFile
;
1245 nsresult rv
= NS_NewNativeLocalFile(nsDependentCString(buffer
), PR_TRUE
,
1246 getter_AddRefs(localFile
));
1248 // make buffer whole again
1251 if (NS_SUCCEEDED(rv
) && localFile
)
1252 rv
= CallQueryInterface(localFile
, aParent
);
1257 * The results of Exists, isWritable and isReadable are not cached.
1261 #if defined(XP_BEOS) || defined(SOLARIS)
1262 // access() is buggy in BeOS POSIX implementation, at least for BFS, using stat() instead
1263 // see bug 169506, https://bugzilla.mozilla.org/show_bug.cgi?id=169506
1264 // access() problem also exists in Solaris POSIX implementation
1265 // see bug 351595, https://bugzilla.mozilla.org/show_bug.cgi?id=351595
1267 nsLocalFile::Exists(PRBool
*_retval
)
1270 NS_ENSURE_ARG_POINTER(_retval
);
1273 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1278 nsLocalFile::IsWritable(PRBool
*_retval
)
1281 NS_ENSURE_ARG_POINTER(_retval
);
1284 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1285 if (*_retval
|| errno
== EACCES
) {
1286 *_retval
= *_retval
&& (buf
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
));
1289 return NSRESULT_FOR_ERRNO();
1293 nsLocalFile::IsReadable(PRBool
*_retval
)
1296 NS_ENSURE_ARG_POINTER(_retval
);
1299 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1300 if (*_retval
|| errno
== EACCES
) {
1301 *_retval
= *_retval
&& (buf
.st_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
));
1304 return NSRESULT_FOR_ERRNO();
1308 nsLocalFile::IsExecutable(PRBool
*_retval
)
1311 NS_ENSURE_ARG_POINTER(_retval
);
1314 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1315 if (*_retval
|| errno
== EACCES
) {
1316 *_retval
= *_retval
&& (buf
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
));
1319 return NSRESULT_FOR_ERRNO();
1324 nsLocalFile::Exists(PRBool
*_retval
)
1327 NS_ENSURE_ARG_POINTER(_retval
);
1329 *_retval
= (access(mPath
.get(), F_OK
) == 0);
1335 nsLocalFile::IsWritable(PRBool
*_retval
)
1338 NS_ENSURE_ARG_POINTER(_retval
);
1340 *_retval
= (access(mPath
.get(), W_OK
) == 0);
1341 if (*_retval
|| errno
== EACCES
)
1343 return NSRESULT_FOR_ERRNO();
1347 nsLocalFile::IsReadable(PRBool
*_retval
)
1350 NS_ENSURE_ARG_POINTER(_retval
);
1352 *_retval
= (access(mPath
.get(), R_OK
) == 0);
1353 if (*_retval
|| errno
== EACCES
)
1355 return NSRESULT_FOR_ERRNO();
1359 nsLocalFile::IsExecutable(PRBool
*_retval
)
1362 NS_ENSURE_ARG_POINTER(_retval
);
1364 *_retval
= (access(mPath
.get(), X_OK
) == 0);
1365 if (*_retval
|| errno
== EACCES
)
1367 return NSRESULT_FOR_ERRNO();
1371 nsLocalFile::IsDirectory(PRBool
*_retval
)
1373 NS_ENSURE_ARG_POINTER(_retval
);
1374 *_retval
= PR_FALSE
;
1375 ENSURE_STAT_CACHE();
1376 *_retval
= S_ISDIR(mCachedStat
.st_mode
);
1381 nsLocalFile::IsFile(PRBool
*_retval
)
1383 NS_ENSURE_ARG_POINTER(_retval
);
1384 *_retval
= PR_FALSE
;
1385 ENSURE_STAT_CACHE();
1386 *_retval
= S_ISREG(mCachedStat
.st_mode
);
1391 nsLocalFile::IsHidden(PRBool
*_retval
)
1393 NS_ENSURE_ARG_POINTER(_retval
);
1394 nsACString::const_iterator begin
, end
;
1395 LocateNativeLeafName(begin
, end
);
1396 *_retval
= (*begin
== '.');
1401 nsLocalFile::IsSymlink(PRBool
*_retval
)
1403 NS_ENSURE_ARG_POINTER(_retval
);
1406 struct stat symStat
;
1407 lstat(mPath
.get(), &symStat
);
1408 *_retval
=S_ISLNK(symStat
.st_mode
);
1413 nsLocalFile::IsSpecial(PRBool
*_retval
)
1415 NS_ENSURE_ARG_POINTER(_retval
);
1416 ENSURE_STAT_CACHE();
1417 *_retval
= S_ISCHR(mCachedStat
.st_mode
) ||
1418 S_ISBLK(mCachedStat
.st_mode
) ||
1420 S_ISSOCK(mCachedStat
.st_mode
) ||
1422 S_ISFIFO(mCachedStat
.st_mode
);
1428 nsLocalFile::Equals(nsIFile
*inFile
, PRBool
*_retval
)
1430 NS_ENSURE_ARG(inFile
);
1431 NS_ENSURE_ARG_POINTER(_retval
);
1432 *_retval
= PR_FALSE
;
1435 nsCAutoString inPath
;
1437 if (NS_FAILED(rv
= inFile
->GetNativePath(inPath
)))
1440 *_retval
= !FILE_STRCMP(inPath
.get(), mPath
.get());
1445 nsLocalFile::Contains(nsIFile
*inFile
, PRBool recur
, PRBool
*_retval
)
1448 NS_ENSURE_ARG(inFile
);
1449 NS_ENSURE_ARG_POINTER(_retval
);
1451 nsCAutoString inPath
;
1454 if (NS_FAILED(rv
= inFile
->GetNativePath(inPath
)))
1457 *_retval
= PR_FALSE
;
1459 ssize_t len
= mPath
.Length();
1460 if (FILE_STRNCMP(mPath
.get(), inPath
.get(), len
) == 0) {
1461 // Now make sure that the |inFile|'s path has a separator at len,
1462 // which implies that it has more components after len.
1463 if (inPath
[len
] == '/')
1471 nsLocalFile::GetNativeTarget(nsACString
&_retval
)
1476 struct stat symStat
;
1477 lstat(mPath
.get(), &symStat
);
1478 if (!S_ISLNK(symStat
.st_mode
))
1479 return NS_ERROR_FILE_INVALID_PATH
;
1481 PRInt64 targetSize64
;
1482 if (NS_FAILED(GetFileSizeOfLink(&targetSize64
)))
1483 return NS_ERROR_FAILURE
;
1486 LL_L2I(size
, targetSize64
);
1487 char *target
= (char *)nsMemory::Alloc(size
+ 1);
1489 return NS_ERROR_OUT_OF_MEMORY
;
1491 if (readlink(mPath
.get(), target
, (size_t)size
) < 0) {
1492 nsMemory::Free(target
);
1493 return NSRESULT_FOR_ERRNO();
1495 target
[size
] = '\0';
1499 nsCOMPtr
<nsIFile
> self(this);
1500 nsCOMPtr
<nsIFile
> parent
;
1501 while (NS_SUCCEEDED(rv
= self
->GetParent(getter_AddRefs(parent
)))) {
1502 NS_ASSERTION(parent
!= nsnull
, "no parent?!");
1504 if (target
[0] != '/') {
1505 nsCOMPtr
<nsILocalFile
> localFile(do_QueryInterface(parent
, &rv
));
1508 if (NS_FAILED(rv
= localFile
->AppendRelativeNativePath(nsDependentCString(target
))))
1510 if (NS_FAILED(rv
= localFile
->GetNativePath(_retval
)))
1512 if (NS_FAILED(rv
= parent
->IsSymlink(&isSymlink
)))
1516 nsCOMPtr
<nsILocalFile
> localFile
;
1517 rv
= NS_NewNativeLocalFile(nsDependentCString(target
), PR_TRUE
,
1518 getter_AddRefs(localFile
));
1521 if (NS_FAILED(rv
= localFile
->IsSymlink(&isSymlink
)))
1523 _retval
= target
; // XXX can we avoid this buffer copy?
1524 self
= do_QueryInterface(localFile
);
1526 if (NS_FAILED(rv
) || !isSymlink
)
1529 const nsPromiseFlatCString
&flatRetval
= PromiseFlatCString(_retval
);
1531 // strip off any and all trailing '/'
1532 PRInt32 len
= strlen(target
);
1533 while (target
[len
-1] == '/' && len
> 1)
1534 target
[--len
] = '\0';
1535 if (lstat(flatRetval
.get(), &symStat
) < 0) {
1536 rv
= NSRESULT_FOR_ERRNO();
1539 if (!S_ISLNK(symStat
.st_mode
)) {
1540 rv
= NS_ERROR_FILE_INVALID_PATH
;
1543 size
= symStat
.st_size
;
1544 if (readlink(flatRetval
.get(), target
, size
) < 0) {
1545 rv
= NSRESULT_FOR_ERRNO();
1548 target
[size
] = '\0';
1553 nsMemory::Free(target
);
1560 /* attribute PRBool followLinks; */
1562 nsLocalFile::GetFollowLinks(PRBool
*aFollowLinks
)
1564 *aFollowLinks
= PR_TRUE
;
1569 nsLocalFile::SetFollowLinks(PRBool aFollowLinks
)
1575 nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator
**entries
)
1577 nsDirEnumeratorUnix
*dir
= new nsDirEnumeratorUnix();
1579 return NS_ERROR_OUT_OF_MEMORY
;
1582 nsresult rv
= dir
->Init(this, PR_FALSE
);
1583 if (NS_FAILED(rv
)) {
1587 *entries
= dir
; // transfer reference
1594 nsLocalFile::Load(PRLibrary
**_retval
)
1597 NS_ENSURE_ARG_POINTER(_retval
);
1599 NS_TIMELINE_START_TIMER("PR_LoadLibrary");
1601 #ifdef NS_BUILD_REFCNT_LOGGING
1602 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE
);
1605 *_retval
= PR_LoadLibrary(mPath
.get());
1607 #ifdef NS_BUILD_REFCNT_LOGGING
1608 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE
);
1611 NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
1612 NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath
.get());
1615 return NS_ERROR_FAILURE
;
1620 nsLocalFile::GetPersistentDescriptor(nsACString
&aPersistentDescriptor
)
1622 return GetNativePath(aPersistentDescriptor
);
1626 nsLocalFile::SetPersistentDescriptor(const nsACString
&aPersistentDescriptor
)
1628 return InitWithNativePath(aPersistentDescriptor
);
1633 nsLocalFile::Reveal()
1635 BPath
bPath(mPath
.get());
1637 if (NS_FAILED(IsDirectory(&isDirectory
)))
1638 return NS_ERROR_FAILURE
;
1641 bPath
.GetParent(&bPath
);
1643 get_ref_for_path(bPath
.Path(),&ref
);
1644 BMessage
message(B_REFS_RECEIVED
);
1645 message
.AddRef("refs",&ref
);
1646 BMessenger
messenger("application/x-vnd.Be-TRAK");
1647 messenger
.SendMessage(&message
);
1652 nsLocalFile::Launch()
1655 get_ref_for_path (mPath
.get(), &ref
);
1656 be_roster
->Launch (&ref
);
1662 nsLocalFile::Reveal()
1664 #ifdef MOZ_WIDGET_GTK2
1665 nsCOMPtr
<nsIGnomeVFSService
> vfs
= do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID
);
1667 return NS_ERROR_FAILURE
;
1670 if (NS_FAILED(IsDirectory(&isDirectory
)))
1671 return NS_ERROR_FAILURE
;
1674 return vfs
->ShowURIForInput(mPath
);
1676 nsCOMPtr
<nsIFile
> parentDir
;
1677 nsCAutoString dirPath
;
1678 if (NS_FAILED(GetParent(getter_AddRefs(parentDir
))))
1679 return NS_ERROR_FAILURE
;
1680 if (NS_FAILED(parentDir
->GetNativePath(dirPath
)))
1681 return NS_ERROR_FAILURE
;
1683 return vfs
->ShowURIForInput(dirPath
);
1686 return NS_ERROR_FAILURE
;
1691 nsLocalFile::Launch()
1693 #ifdef MOZ_WIDGET_GTK2
1694 nsCOMPtr
<nsIGnomeVFSService
> vfs
= do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID
);
1696 return NS_ERROR_FAILURE
;
1698 return vfs
->ShowURIForInput(mPath
);
1700 return NS_ERROR_FAILURE
;
1706 NS_NewNativeLocalFile(const nsACString
&path
, PRBool followSymlinks
, nsILocalFile
**result
)
1708 nsLocalFile
*file
= new nsLocalFile();
1710 return NS_ERROR_OUT_OF_MEMORY
;
1713 if (!path
.IsEmpty()) {
1714 nsresult rv
= file
->InitWithNativePath(path
);
1715 if (NS_FAILED(rv
)) {
1724 //-----------------------------------------------------------------------------
1726 //-----------------------------------------------------------------------------
1728 #define SET_UCS(func, ucsArg) \
1730 nsCAutoString buf; \
1731 nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
1732 if (NS_FAILED(rv)) \
1734 return (func)(buf); \
1737 #define GET_UCS(func, ucsArg) \
1739 nsCAutoString buf; \
1740 nsresult rv = (func)(buf); \
1741 if (NS_FAILED(rv)) return rv; \
1742 return NS_CopyNativeToUnicode(buf, ucsArg); \
1745 #define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \
1747 nsCAutoString buf; \
1748 nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
1749 if (NS_FAILED(rv)) \
1751 return (func)(opaqueArg, buf); \
1754 // Unicode interface Wrapper
1756 nsLocalFile::InitWithPath(const nsAString
&filePath
)
1758 SET_UCS(InitWithNativePath
, filePath
);
1761 nsLocalFile::Append(const nsAString
&node
)
1763 SET_UCS(AppendNative
, node
);
1766 nsLocalFile::AppendRelativePath(const nsAString
&node
)
1768 SET_UCS(AppendRelativeNativePath
, node
);
1771 nsLocalFile::GetLeafName(nsAString
&aLeafName
)
1773 GET_UCS(GetNativeLeafName
, aLeafName
);
1776 nsLocalFile::SetLeafName(const nsAString
&aLeafName
)
1778 SET_UCS(SetNativeLeafName
, aLeafName
);
1781 nsLocalFile::GetPath(nsAString
&_retval
)
1783 return NS_CopyNativeToUnicode(mPath
, _retval
);
1786 nsLocalFile::CopyTo(nsIFile
*newParentDir
, const nsAString
&newName
)
1788 SET_UCS_2ARGS_2(CopyToNative
, newParentDir
, newName
);
1791 nsLocalFile::CopyToFollowingLinks(nsIFile
*newParentDir
, const nsAString
&newName
)
1793 SET_UCS_2ARGS_2(CopyToFollowingLinksNative
, newParentDir
, newName
);
1796 nsLocalFile::MoveTo(nsIFile
*newParentDir
, const nsAString
&newName
)
1798 SET_UCS_2ARGS_2(MoveToNative
, newParentDir
, newName
);
1801 nsLocalFile::GetTarget(nsAString
&_retval
)
1803 GET_UCS(GetNativeTarget
, _retval
);
1809 nsLocalFile::Equals(nsIHashable
* aOther
, PRBool
*aResult
)
1811 nsCOMPtr
<nsIFile
> otherFile(do_QueryInterface(aOther
));
1813 *aResult
= PR_FALSE
;
1817 return Equals(otherFile
, aResult
);
1821 nsLocalFile::GetHashCode(PRUint32
*aResult
)
1823 *aResult
= nsCRT::HashCode(mPath
.get());
1828 NS_NewLocalFile(const nsAString
&path
, PRBool followLinks
, nsILocalFile
* *result
)
1831 nsresult rv
= NS_CopyUnicodeToNative(path
, buf
);
1834 return NS_NewNativeLocalFile(buf
, followLinks
, result
);
1837 //-----------------------------------------------------------------------------
1838 // global init/shutdown
1839 //-----------------------------------------------------------------------------
1842 nsLocalFile::GlobalInit()
1847 nsLocalFile::GlobalShutdown()