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>
33 * Alternatively, the contents of this file may be used under the terms of
34 * either of the GNU General Public License Version 2 or later (the "GPL"),
35 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 * in which case the provisions of the GPL or the LGPL are applicable instead
37 * of those above. If you wish to allow use of your version of this file only
38 * under the terms of either the GPL or the LGPL, and not to allow others to
39 * use your version of this file under the terms of the MPL, indicate your
40 * decision by deleting the provisions above and replace them with the notice
41 * and other provisions required by the GPL or the LGPL. If you do not delete
42 * the provisions above, a recipient may use your version of this file under
43 * the terms of any one of the MPL, the GPL or the LGPL.
45 * ***** END LICENSE BLOCK ***** */
48 * Implementation of nsIFile for ``Unixy'' systems.
51 // We're going to need some autoconf loving, I can just tell.
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 VALIDATE_STAT_CACHE() \
104 if (!mHaveCachedStat) { \
106 if (!mHaveCachedStat) \
107 return NSRESULT_FOR_ERRNO(); \
111 #define CHECK_mPath() \
113 if (mPath.IsEmpty()) \
114 return NS_ERROR_NOT_INITIALIZED; \
117 /* directory enumerator */
119 nsDirEnumeratorUnix
: public nsISimpleEnumerator
,
120 public nsIDirectoryEnumerator
123 nsDirEnumeratorUnix();
125 // nsISupports interface
128 // nsISimpleEnumerator interface
129 NS_DECL_NSISIMPLEENUMERATOR
131 // nsIDirectoryEnumerator interface
132 NS_DECL_NSIDIRECTORYENUMERATOR
134 NS_IMETHOD
Init(nsLocalFile
*parent
, PRBool ignored
);
137 ~nsDirEnumeratorUnix();
140 NS_IMETHOD
GetNextEntry();
143 struct dirent
*mEntry
;
144 nsCString mParentPath
;
147 nsDirEnumeratorUnix::nsDirEnumeratorUnix() :
153 nsDirEnumeratorUnix::~nsDirEnumeratorUnix()
158 NS_IMPL_ISUPPORTS2(nsDirEnumeratorUnix
, nsISimpleEnumerator
, nsIDirectoryEnumerator
)
161 nsDirEnumeratorUnix::Init(nsLocalFile
*parent
, PRBool resolveSymlinks
/*ignored*/)
163 nsCAutoString dirPath
;
164 if (NS_FAILED(parent
->GetNativePath(dirPath
)) ||
166 return NS_ERROR_FILE_INVALID_PATH
;
169 if (NS_FAILED(parent
->GetNativePath(mParentPath
)))
170 return NS_ERROR_FAILURE
;
172 mDir
= opendir(dirPath
.get());
174 return NSRESULT_FOR_ERRNO();
175 return GetNextEntry();
179 nsDirEnumeratorUnix::HasMoreElements(PRBool
*result
)
181 *result
= mDir
&& mEntry
;
188 nsDirEnumeratorUnix::GetNext(nsISupports
**_retval
)
190 nsCOMPtr
<nsIFile
> file
;
191 nsresult rv
= GetNextFile(getter_AddRefs(file
));
194 NS_IF_ADDREF(*_retval
= file
);
199 nsDirEnumeratorUnix::GetNextEntry()
203 mEntry
= readdir(mDir
);
205 // end of dir or error
207 return NSRESULT_FOR_ERRNO();
209 // keep going past "." and ".."
210 } while (mEntry
->d_name
[0] == '.' &&
211 (mEntry
->d_name
[1] == '\0' || // .\0
212 (mEntry
->d_name
[1] == '.' &&
213 mEntry
->d_name
[2] == '\0'))); // ..\0
218 nsDirEnumeratorUnix::GetNextFile(nsIFile
**_retval
)
221 if (!mDir
|| !mEntry
) {
226 nsCOMPtr
<nsILocalFile
> file
= new nsLocalFile();
228 return NS_ERROR_OUT_OF_MEMORY
;
230 if (NS_FAILED(rv
= file
->InitWithNativePath(mParentPath
)) ||
231 NS_FAILED(rv
= file
->AppendNative(nsDependentCString(mEntry
->d_name
))))
236 return GetNextEntry();
240 nsDirEnumeratorUnix::Close()
249 nsLocalFile::nsLocalFile() :
250 mHaveCachedStat(PR_FALSE
)
254 nsLocalFile::nsLocalFile(const nsLocalFile
& other
)
256 , mHaveCachedStat(PR_FALSE
)
260 NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile
,
266 nsLocalFile::nsLocalFileConstructor(nsISupports
*outer
,
270 NS_ENSURE_ARG_POINTER(aInstancePtr
);
271 NS_ENSURE_NO_AGGREGATION(outer
);
273 *aInstancePtr
= nsnull
;
275 nsCOMPtr
<nsIFile
> inst
= new nsLocalFile();
277 return NS_ERROR_OUT_OF_MEMORY
;
278 return inst
->QueryInterface(aIID
, aInstancePtr
);
282 nsLocalFile::FillStatCache() {
284 if (stat64(mPath
.get(), &mCachedStat
) == -1) {
285 // try lstat it may be a symlink
286 if (lstat64(mPath
.get(), &mCachedStat
) == -1) {
287 return NSRESULT_FOR_ERRNO();
291 if (stat(mPath
.get(), &mCachedStat
) == -1) {
292 // try lstat it may be a symlink
293 if (lstat(mPath
.get(), &mCachedStat
) == -1) {
294 return NSRESULT_FOR_ERRNO();
298 mHaveCachedStat
= PR_TRUE
;
303 nsLocalFile::Clone(nsIFile
**file
)
305 // Just copy-construct ourselves
306 *file
= new nsLocalFile(*this);
308 return NS_ERROR_OUT_OF_MEMORY
;
316 nsLocalFile::InitWithNativePath(const nsACString
&filePath
)
318 if (Substring(filePath
, 0, 2).EqualsLiteral("~/")) {
319 nsCOMPtr
<nsIFile
> homeDir
;
320 nsCAutoString homePath
;
321 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR
,
322 getter_AddRefs(homeDir
))) ||
323 NS_FAILED(homeDir
->GetNativePath(homePath
))) {
324 return NS_ERROR_FAILURE
;
327 mPath
= homePath
+ Substring(filePath
, 1, filePath
.Length() - 1);
329 if (filePath
.IsEmpty() || filePath
.First() != '/')
330 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
334 // trim off trailing slashes
335 ssize_t len
= mPath
.Length();
336 while ((len
> 1) && (mPath
[len
- 1] == '/'))
338 mPath
.SetLength(len
);
345 nsLocalFile::CreateAllAncestors(PRUint32 permissions
)
347 // <jband> I promise to play nice
348 char *buffer
= mPath
.BeginWriting(),
352 fprintf(stderr
, "nsIFile: before: %s\n", buffer
);
355 while ((slashp
= strchr(slashp
+ 1, '/'))) {
357 * Sequences of '/' are equivalent to a single '/'.
359 if (slashp
[1] == '/')
363 * If the path has a trailing slash, don't make the last component,
364 * because we'll get EEXIST in Create when we try to build the final
365 * component again, and it's easier to condition the logic here than
368 if (slashp
[1] == '\0')
371 /* Temporarily NUL-terminate here */
374 fprintf(stderr
, "nsIFile: mkdir(\"%s\")\n", buffer
);
376 int mkdir_result
= mkdir(buffer
, permissions
);
377 int mkdir_errno
= errno
;
378 if (mkdir_result
== -1) {
380 * Always set |errno| to EEXIST if the dir already exists
381 * (we have to do this here since the errno value is not consistent
382 * in all cases - various reasons like different platform,
383 * automounter-controlled dir, etc. can affect it (see bug 125489
386 if (access(buffer
, F_OK
) == 0) {
387 mkdir_errno
= EEXIST
;
391 /* Put the / back before we (maybe) return */
395 * We could get EEXIST for an existing file -- not directory --
396 * with the name of one of our ancestors, but that's OK: we'll get
397 * ENOTDIR when we try to make the next component in the path,
398 * either here on back in Create, and error out appropriately.
400 if (mkdir_result
== -1 && mkdir_errno
!= EEXIST
)
401 return nsresultForErrno(mkdir_errno
);
405 fprintf(stderr
, "nsIFile: after: %s\n", buffer
);
412 nsLocalFile::OpenNSPRFileDesc(PRInt32 flags
, PRInt32 mode
, PRFileDesc
**_retval
)
414 *_retval
= PR_Open(mPath
.get(), flags
, mode
);
416 return NS_ErrorAccordingToNSPR();
422 nsLocalFile::OpenANSIFileDesc(const char *mode
, FILE **_retval
)
424 *_retval
= fopen(mPath
.get(), mode
);
426 return NS_ERROR_FAILURE
;
432 do_create(const char *path
, PRIntn flags
, mode_t mode
, PRFileDesc
**_retval
)
434 *_retval
= PR_Open(path
, flags
, mode
);
435 return *_retval
? 0 : -1;
439 do_mkdir(const char *path
, PRIntn flags
, mode_t mode
, PRFileDesc
**_retval
)
442 return mkdir(path
, mode
);
446 nsLocalFile::CreateAndKeepOpen(PRUint32 type
, PRIntn flags
,
447 PRUint32 permissions
, PRFileDesc
**_retval
)
449 if (type
!= NORMAL_FILE_TYPE
&& type
!= DIRECTORY_TYPE
)
450 return NS_ERROR_FILE_UNKNOWN_TYPE
;
453 int (*createFunc
)(const char *, PRIntn
, mode_t
, PRFileDesc
**) =
454 (type
== NORMAL_FILE_TYPE
) ? do_create
: do_mkdir
;
456 result
= createFunc(mPath
.get(), flags
, permissions
, _retval
);
457 if (result
== -1 && errno
== ENOENT
) {
459 * If we failed because of missing ancestor components, try to create
460 * them and then retry the original creation.
462 * Ancestor directories get the same permissions as the file we're
463 * creating, with the X bit set for each of (user,group,other) with
464 * an R bit in the original permissions. If you want to do anything
465 * fancy like setgid or sticky bits, do it by hand.
467 int dirperm
= permissions
;
468 if (permissions
& S_IRUSR
)
470 if (permissions
& S_IRGRP
)
472 if (permissions
& S_IROTH
)
476 fprintf(stderr
, "nsIFile: perm = %o, dirperm = %o\n", permissions
,
480 if (NS_FAILED(CreateAllAncestors(dirperm
)))
481 return NS_ERROR_FAILURE
;
484 fprintf(stderr
, "nsIFile: Create(\"%s\") again\n", mPath
.get());
486 result
= createFunc(mPath
.get(), flags
, permissions
, _retval
);
488 return NSRESULT_FOR_RETURN(result
);
492 nsLocalFile::Create(PRUint32 type
, PRUint32 permissions
)
494 PRFileDesc
*junk
= nsnull
;
495 nsresult rv
= CreateAndKeepOpen(type
,
496 PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
|
506 nsLocalFile::AppendNative(const nsACString
&fragment
)
508 if (fragment
.IsEmpty())
511 // only one component of path can be appended
512 nsACString::const_iterator begin
, end
;
513 if (FindCharInReadable('/', fragment
.BeginReading(begin
),
514 fragment
.EndReading(end
)))
515 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
517 return AppendRelativeNativePath(fragment
);
521 nsLocalFile::AppendRelativeNativePath(const nsACString
&fragment
)
523 if (fragment
.IsEmpty())
527 if (fragment
.First() == '/')
528 return NS_ERROR_FILE_UNRECOGNIZED_PATH
;
530 if (mPath
.EqualsLiteral("/"))
531 mPath
.Append(fragment
);
533 mPath
.Append(NS_LITERAL_CSTRING("/") + fragment
);
540 nsLocalFile::Normalize()
542 char resolved_path
[PATH_MAX
] = "";
543 char *resolved_path_ptr
= nsnull
;
546 BEntry
be_e(mPath
.get(), true);
549 if ((err
= be_e
.GetPath(&be_p
)) == B_OK
) {
550 resolved_path_ptr
= (char *)be_p
.Path();
551 PL_strncpyz(resolved_path
, resolved_path_ptr
, PATH_MAX
- 1);
554 resolved_path_ptr
= realpath(mPath
.get(), resolved_path
);
556 // if there is an error, the return is null.
557 if (!resolved_path_ptr
)
558 return NSRESULT_FOR_ERRNO();
560 mPath
= resolved_path
;
565 nsLocalFile::LocateNativeLeafName(nsACString::const_iterator
&begin
,
566 nsACString::const_iterator
&end
)
568 // XXX perhaps we should cache this??
570 mPath
.BeginReading(begin
);
571 mPath
.EndReading(end
);
573 nsACString::const_iterator it
= end
;
574 nsACString::const_iterator stop
= begin
;
576 while (--it
!= stop
) {
582 // else, the entire path is the leaf name (which means this
583 // isn't an absolute path... unexpected??)
587 nsLocalFile::GetNativeLeafName(nsACString
&aLeafName
)
589 nsACString::const_iterator begin
, end
;
590 LocateNativeLeafName(begin
, end
);
591 aLeafName
= Substring(begin
, end
);
596 nsLocalFile::SetNativeLeafName(const nsACString
&aLeafName
)
598 nsACString::const_iterator begin
, end
;
599 LocateNativeLeafName(begin
, end
);
600 mPath
.Replace(begin
.get() - mPath
.get(), Distance(begin
, end
), aLeafName
);
606 nsLocalFile::GetNativePath(nsACString
&_retval
)
613 nsLocalFile::GetNativeTargetPathName(nsIFile
*newParent
,
614 const nsACString
&newName
,
618 nsCOMPtr
<nsIFile
> oldParent
;
621 if (NS_FAILED(rv
= GetParent(getter_AddRefs(oldParent
))))
623 newParent
= oldParent
.get();
625 // check to see if our target directory exists
627 if (NS_FAILED(rv
= newParent
->Exists(&targetExists
)))
631 // XXX create the new directory with some permissions
632 rv
= newParent
->Create(DIRECTORY_TYPE
, 0755);
636 // make sure that the target is actually a directory
637 PRBool targetIsDirectory
;
638 if (NS_FAILED(rv
= newParent
->IsDirectory(&targetIsDirectory
)))
640 if (!targetIsDirectory
)
641 return NS_ERROR_FILE_DESTINATION_NOT_DIR
;
645 nsACString::const_iterator nameBegin
, nameEnd
;
646 if (!newName
.IsEmpty()) {
647 newName
.BeginReading(nameBegin
);
648 newName
.EndReading(nameEnd
);
651 LocateNativeLeafName(nameBegin
, nameEnd
);
653 nsCAutoString dirName
;
654 if (NS_FAILED(rv
= newParent
->GetNativePath(dirName
)))
658 + NS_LITERAL_CSTRING("/")
659 + Substring(nameBegin
, nameEnd
);
664 nsLocalFile::CopyDirectoryTo(nsIFile
*newParent
)
668 * dirCheck is used for various boolean test results such as from Equals,
669 * Exists, isDir, etc.
671 PRBool dirCheck
, isSymlink
;
674 if (NS_FAILED(rv
= IsDirectory(&dirCheck
)))
677 return CopyToNative(newParent
, EmptyCString());
679 if (NS_FAILED(rv
= Equals(newParent
, &dirCheck
)))
682 // can't copy dir to itself
683 return NS_ERROR_INVALID_ARG
;
686 if (NS_FAILED(rv
= newParent
->Exists(&dirCheck
)))
688 // get the dirs old permissions
689 if (NS_FAILED(rv
= GetPermissions(&oldPerms
)))
692 if (NS_FAILED(rv
= newParent
->Create(DIRECTORY_TYPE
, oldPerms
)))
694 } else { // dir exists lets try to use leaf
695 nsCAutoString leafName
;
696 if (NS_FAILED(rv
= GetNativeLeafName(leafName
)))
698 if (NS_FAILED(rv
= newParent
->AppendNative(leafName
)))
700 if (NS_FAILED(rv
= newParent
->Exists(&dirCheck
)))
703 return NS_ERROR_FILE_ALREADY_EXISTS
; // dest exists
704 if (NS_FAILED(rv
= newParent
->Create(DIRECTORY_TYPE
, oldPerms
)))
708 nsCOMPtr
<nsISimpleEnumerator
> dirIterator
;
709 if (NS_FAILED(rv
= GetDirectoryEntries(getter_AddRefs(dirIterator
))))
712 PRBool hasMore
= PR_FALSE
;
713 while (dirIterator
->HasMoreElements(&hasMore
), hasMore
) {
714 nsCOMPtr
<nsIFile
> entry
;
715 rv
= dirIterator
->GetNext((nsISupports
**)getter_AddRefs(entry
));
718 if (NS_FAILED(rv
= entry
->IsSymlink(&isSymlink
)))
720 if (NS_FAILED(rv
= entry
->IsDirectory(&dirCheck
)))
722 if (dirCheck
&& !isSymlink
) {
723 nsCOMPtr
<nsIFile
> destClone
;
724 rv
= newParent
->Clone(getter_AddRefs(destClone
));
725 if (NS_SUCCEEDED(rv
)) {
726 nsCOMPtr
<nsILocalFile
> newDir(do_QueryInterface(destClone
));
727 if (NS_FAILED(rv
= entry
->CopyToNative(newDir
, EmptyCString()))) {
730 nsCAutoString pathName
;
731 if (NS_FAILED(rv2
= entry
->GetNativePath(pathName
)))
733 printf("Operation not supported: %s\n", pathName
.get());
735 if (rv
== NS_ERROR_OUT_OF_MEMORY
)
741 if (NS_FAILED(rv
= entry
->CopyToNative(newParent
, EmptyCString()))) {
744 nsCAutoString pathName
;
745 if (NS_FAILED(rv2
= entry
->GetNativePath(pathName
)))
747 printf("Operation not supported: %s\n", pathName
.get());
749 if (rv
== NS_ERROR_OUT_OF_MEMORY
)
759 nsLocalFile::CopyToNative(nsIFile
*newParent
, const nsACString
&newName
)
762 // check to make sure that this has been initialized properly
765 // we copy the parent here so 'newParent' remains immutable
766 nsCOMPtr
<nsIFile
> workParent
;
768 if (NS_FAILED(rv
= newParent
->Clone(getter_AddRefs(workParent
))))
771 if (NS_FAILED(rv
= GetParent(getter_AddRefs(workParent
))))
775 // check to see if we are a directory or if we are a file
777 if (NS_FAILED(rv
= IsDirectory(&isDirectory
)))
780 nsCAutoString newPathName
;
782 if (!newName
.IsEmpty()) {
783 if (NS_FAILED(rv
= workParent
->AppendNative(newName
)))
786 if (NS_FAILED(rv
= GetNativeLeafName(newPathName
)))
788 if (NS_FAILED(rv
= workParent
->AppendNative(newPathName
)))
791 if (NS_FAILED(rv
= CopyDirectoryTo(workParent
)))
794 rv
= GetNativeTargetPathName(workParent
, newName
, newPathName
);
798 #ifdef DEBUG_blizzard
799 printf("nsLocalFile::CopyTo() %s -> %s\n", mPath
.get(), newPathName
.get());
802 // actually create the file.
803 nsLocalFile
*newFile
= new nsLocalFile();
805 return NS_ERROR_OUT_OF_MEMORY
;
807 nsCOMPtr
<nsILocalFile
> fileRef(newFile
); // release on exit
809 rv
= newFile
->InitWithNativePath(newPathName
);
813 // get the old permissions
815 GetPermissions(&myPerms
);
817 // Create the new file with the old file's permissions, even if write
818 // permission is missing. We can't create with write permission and
819 // then change back to myPerm on all filesystems (FAT on Linux, e.g.).
820 // But we can write to a read-only file on all Unix filesystems if we
821 // open it successfully for writing.
824 rv
= newFile
->CreateAndKeepOpen(NORMAL_FILE_TYPE
,
825 PR_WRONLY
|PR_CREATE_FILE
|PR_TRUNCATE
,
831 // open the old file, too
833 if (NS_FAILED(rv
= IsSpecial(&specialFile
))) {
839 printf("Operation not supported: %s\n", mPath
.get());
841 // make sure to clean up properly
847 rv
= OpenNSPRFileDesc(PR_RDONLY
, myPerms
, &oldFD
);
849 // make sure to clean up properly
854 #ifdef DEBUG_blizzard
855 PRInt32 totalRead
= 0;
856 PRInt32 totalWritten
= 0;
861 while ((bytesRead
= PR_Read(oldFD
, buf
, BUFSIZ
)) > 0) {
862 #ifdef DEBUG_blizzard
863 totalRead
+= bytesRead
;
866 // PR_Write promises never to do a short write
867 PRInt32 bytesWritten
= PR_Write(newFD
, buf
, bytesRead
);
868 if (bytesWritten
< 0) {
872 NS_ASSERTION(bytesWritten
== bytesRead
, "short PR_Write?");
874 #ifdef DEBUG_blizzard
875 totalWritten
+= bytesWritten
;
879 #ifdef DEBUG_blizzard
880 printf("read %d bytes, wrote %d bytes\n",
881 totalRead
, totalWritten
);
888 // check for read (or write) error after cleaning up
890 return NS_ERROR_OUT_OF_MEMORY
;
896 nsLocalFile::CopyToFollowingLinksNative(nsIFile
*newParent
, const nsACString
&newName
)
898 return CopyToNative(newParent
, newName
);
902 nsLocalFile::MoveToNative(nsIFile
*newParent
, const nsACString
&newName
)
906 // check to make sure that this has been initialized properly
909 // check to make sure that we have a new parent
910 nsCAutoString newPathName
;
911 rv
= GetNativeTargetPathName(newParent
, newName
, newPathName
);
915 // try for atomic rename, falling back to copy/delete
916 if (rename(mPath
.get(), newPathName
.get()) < 0) {
918 if (errno
== EXDEV
|| errno
== ENXIO
) {
920 if (errno
== EXDEV
) {
922 rv
= CopyToNative(newParent
, newName
);
923 if (NS_SUCCEEDED(rv
))
924 rv
= Remove(PR_TRUE
);
926 rv
= NSRESULT_FOR_ERRNO();
933 nsLocalFile::Remove(PRBool recursive
)
937 VALIDATE_STAT_CACHE();
938 PRBool isSymLink
, isDir
;
940 nsresult rv
= IsSymlink(&isSymLink
);
944 if (!recursive
&& isSymLink
)
945 return NSRESULT_FOR_RETURN(unlink(mPath
.get()));
947 isDir
= S_ISDIR(mCachedStat
.st_mode
);
951 nsDirEnumeratorUnix
*dir
= new nsDirEnumeratorUnix();
953 return NS_ERROR_OUT_OF_MEMORY
;
955 nsCOMPtr
<nsISimpleEnumerator
> dirRef(dir
); // release on exit
957 rv
= dir
->Init(this, PR_FALSE
);
962 while (dir
->HasMoreElements(&more
), more
) {
963 nsCOMPtr
<nsISupports
> item
;
964 rv
= dir
->GetNext(getter_AddRefs(item
));
966 return NS_ERROR_FAILURE
;
968 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(item
, &rv
);
970 return NS_ERROR_FAILURE
;
971 if (NS_FAILED(rv
= file
->Remove(recursive
)))
976 if (rmdir(mPath
.get()) == -1)
977 return NSRESULT_FOR_ERRNO();
979 if (unlink(mPath
.get()) == -1)
980 return NSRESULT_FOR_ERRNO();
987 nsLocalFile::GetLastModifiedTime(PRInt64
*aLastModTime
)
990 NS_ENSURE_ARG(aLastModTime
);
993 if (PR_GetFileInfo64(mPath
.get(), &info
) != PR_SUCCESS
)
994 return NSRESULT_FOR_ERRNO();
996 // PRTime is a 64 bit value
997 // microseconds -> milliseconds
999 LL_I2L(usecPerMsec
, PR_USEC_PER_MSEC
);
1000 LL_DIV(*aLastModTime
, info
.modifyTime
, usecPerMsec
);
1005 nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime
)
1010 if (! LL_IS_ZERO(aLastModTime
)) {
1011 VALIDATE_STAT_CACHE();
1013 ut
.actime
= mCachedStat
.st_atime
;
1015 // convert milliseconds to seconds since the unix epoch
1017 LL_L2D(dTime
, aLastModTime
);
1018 ut
.modtime
= (time_t) (dTime
/ PR_MSEC_PER_SEC
);
1019 result
= utime(mPath
.get(), &ut
);
1021 result
= utime(mPath
.get(), nsnull
);
1024 return NSRESULT_FOR_RETURN(result
);
1028 nsLocalFile::GetLastModifiedTimeOfLink(PRInt64
*aLastModTimeOfLink
)
1031 NS_ENSURE_ARG(aLastModTimeOfLink
);
1034 if (lstat(mPath
.get(), &sbuf
) == -1)
1035 return NSRESULT_FOR_ERRNO();
1036 LL_I2L(*aLastModTimeOfLink
, (PRInt32
)sbuf
.st_mtime
);
1038 // lstat returns st_mtime in seconds
1040 LL_I2L(msecPerSec
, PR_MSEC_PER_SEC
);
1041 LL_MUL(*aLastModTimeOfLink
, *aLastModTimeOfLink
, msecPerSec
);
1047 * utime(2) may or may not dereference symlinks, joy.
1050 nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink
)
1052 return SetLastModifiedTime(aLastModTimeOfLink
);
1056 * Only send back permissions bits: maybe we want to send back the whole
1057 * mode_t to permit checks against other file types?
1060 #define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO))
1063 nsLocalFile::GetPermissions(PRUint32
*aPermissions
)
1065 NS_ENSURE_ARG(aPermissions
);
1066 VALIDATE_STAT_CACHE();
1067 *aPermissions
= NORMALIZE_PERMS(mCachedStat
.st_mode
);
1072 nsLocalFile::GetPermissionsOfLink(PRUint32
*aPermissionsOfLink
)
1075 NS_ENSURE_ARG(aPermissionsOfLink
);
1078 if (lstat(mPath
.get(), &sbuf
) == -1)
1079 return NSRESULT_FOR_ERRNO();
1080 *aPermissionsOfLink
= NORMALIZE_PERMS(sbuf
.st_mode
);
1085 nsLocalFile::SetPermissions(PRUint32 aPermissions
)
1092 * Race condition here: we should use fchmod instead, there's no way to
1093 * guarantee the name still refers to the same file.
1095 if (chmod(mPath
.get(), aPermissions
) < 0)
1096 return NSRESULT_FOR_ERRNO();
1101 nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions
)
1103 return SetPermissions(aPermissions
);
1107 nsLocalFile::GetFileSize(PRInt64
*aFileSize
)
1109 NS_ENSURE_ARG_POINTER(aFileSize
);
1110 *aFileSize
= LL_ZERO
;
1111 VALIDATE_STAT_CACHE();
1114 /* Only two record formats can report correct file content size */
1115 if ((mCachedStat
.st_fab_rfm
!= FAB$C_STMLF
) &&
1116 (mCachedStat
.st_fab_rfm
!= FAB$C_STMCR
)) {
1117 return NS_ERROR_FAILURE
;
1121 if (!S_ISDIR(mCachedStat
.st_mode
)) {
1123 *aFileSize
= mCachedStat
.st_size
;
1125 LL_UI2L(*aFileSize
, (PRUint32
)mCachedStat
.st_size
);
1132 nsLocalFile::SetFileSize(PRInt64 aFileSize
)
1137 LL_L2I(size
, aFileSize
);
1138 /* XXX truncate64? */
1140 if (truncate(mPath
.get(), (off_t
)size
) == -1)
1141 return NSRESULT_FOR_ERRNO();
1146 nsLocalFile::GetFileSizeOfLink(PRInt64
*aFileSize
)
1149 NS_ENSURE_ARG(aFileSize
);
1153 if (lstat64(mPath
.get(), &sbuf
) == -1)
1154 return NSRESULT_FOR_ERRNO();
1155 *aFileSize
= sbuf
.st_size
;
1158 if (lstat(mPath
.get(), &sbuf
) == -1)
1159 return NSRESULT_FOR_ERRNO();
1160 LL_UI2L(*aFileSize
, (PRUint32
)sbuf
.st_size
);
1166 nsLocalFile::GetDiskSpaceAvailable(PRInt64
*aDiskSpaceAvailable
)
1168 NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable
);
1170 // These systems have the operations necessary to check disk space.
1172 #if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H)
1174 // check to make sure that mPath is properly initialized
1177 struct STATFS fs_buf
;
1180 * Members of the STATFS struct that you should know about:
1181 * f_bsize = block size on disk.
1182 * f_bavail = number of free blocks available to a non-superuser.
1183 * f_bfree = number of total free blocks in file system.
1186 if (STATFS(mPath
.get(), &fs_buf
) < 0) {
1187 // The call to STATFS failed.
1189 printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n");
1191 return NS_ERROR_FAILURE
;
1193 #ifdef DEBUG_DISK_SPACE
1194 printf("DiskSpaceAvailable: %d bytes\n",
1195 fs_buf
.f_bsize
* (fs_buf
.f_bavail
- 1));
1199 * The number of bytes free == The number of free blocks available to
1200 * a non-superuser, minus one as a fudge factor, multiplied by the size
1201 * of the aforementioned blocks.
1203 PRInt64 bsize
, bavail
;
1205 LL_I2L(bsize
, fs_buf
.f_bsize
);
1206 LL_I2L(bavail
, fs_buf
.f_bavail
- 1);
1207 LL_MUL(*aDiskSpaceAvailable
, bsize
, bavail
);
1212 * This platform doesn't have statfs or statvfs. I'm sure that there's
1213 * a way to check for free disk space on platforms that don't have statfs
1214 * (I'm SURE they have df, for example).
1216 * Until we figure out how to do that, lets be honest and say that this
1217 * command isn't implemented properly for these platforms yet.
1220 printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n");
1222 return NS_ERROR_NOT_IMPLEMENTED
;
1224 #endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */
1229 nsLocalFile::GetParent(nsIFile
**aParent
)
1232 NS_ENSURE_ARG_POINTER(aParent
);
1235 // if '/' we are at the top of the volume, return null
1236 if (mPath
.Equals("/"))
1239 // <brendan, after jband> I promise to play nice
1240 char *buffer
= mPath
.BeginWriting(),
1243 // find the last significant slash in buffer
1244 slashp
= strrchr(buffer
, '/');
1245 NS_ASSERTION(slashp
, "non-canonical mPath?");
1247 return NS_ERROR_FILE_INVALID_PATH
;
1249 // for the case where we are at '/'
1250 if (slashp
== buffer
)
1253 // temporarily terminate buffer at the last significant slash
1257 nsCOMPtr
<nsILocalFile
> localFile
;
1258 nsresult rv
= NS_NewNativeLocalFile(nsDependentCString(buffer
), PR_TRUE
,
1259 getter_AddRefs(localFile
));
1261 // make buffer whole again
1264 if (NS_SUCCEEDED(rv
) && localFile
)
1265 rv
= CallQueryInterface(localFile
, aParent
);
1270 * The results of Exists, isWritable and isReadable are not cached.
1274 #if defined(XP_BEOS) || defined(SOLARIS)
1275 // access() is buggy in BeOS POSIX implementation, at least for BFS, using stat() instead
1276 // see bug 169506, https://bugzilla.mozilla.org/show_bug.cgi?id=169506
1277 // access() problem also exists in Solaris POSIX implementation
1278 // see bug 351595, https://bugzilla.mozilla.org/show_bug.cgi?id=351595
1280 nsLocalFile::Exists(PRBool
*_retval
)
1283 NS_ENSURE_ARG_POINTER(_retval
);
1286 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1291 nsLocalFile::IsWritable(PRBool
*_retval
)
1294 NS_ENSURE_ARG_POINTER(_retval
);
1297 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1298 if (*_retval
|| errno
== EACCES
) {
1299 *_retval
= *_retval
&& (buf
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
));
1302 return NSRESULT_FOR_ERRNO();
1306 nsLocalFile::IsReadable(PRBool
*_retval
)
1309 NS_ENSURE_ARG_POINTER(_retval
);
1312 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1313 if (*_retval
|| errno
== EACCES
) {
1314 *_retval
= *_retval
&& (buf
.st_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
));
1317 return NSRESULT_FOR_ERRNO();
1321 nsLocalFile::IsExecutable(PRBool
*_retval
)
1324 NS_ENSURE_ARG_POINTER(_retval
);
1327 *_retval
= (stat(mPath
.get(), &buf
) == 0);
1328 if (*_retval
|| errno
== EACCES
) {
1329 *_retval
= *_retval
&& (buf
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
));
1332 return NSRESULT_FOR_ERRNO();
1337 nsLocalFile::Exists(PRBool
*_retval
)
1340 NS_ENSURE_ARG_POINTER(_retval
);
1342 *_retval
= (access(mPath
.get(), F_OK
) == 0);
1348 nsLocalFile::IsWritable(PRBool
*_retval
)
1351 NS_ENSURE_ARG_POINTER(_retval
);
1353 *_retval
= (access(mPath
.get(), W_OK
) == 0);
1354 if (*_retval
|| errno
== EACCES
)
1356 return NSRESULT_FOR_ERRNO();
1360 nsLocalFile::IsReadable(PRBool
*_retval
)
1363 NS_ENSURE_ARG_POINTER(_retval
);
1365 *_retval
= (access(mPath
.get(), R_OK
) == 0);
1366 if (*_retval
|| errno
== EACCES
)
1368 return NSRESULT_FOR_ERRNO();
1372 nsLocalFile::IsExecutable(PRBool
*_retval
)
1375 NS_ENSURE_ARG_POINTER(_retval
);
1377 *_retval
= (access(mPath
.get(), X_OK
) == 0);
1378 if (*_retval
|| errno
== EACCES
)
1380 return NSRESULT_FOR_ERRNO();
1384 nsLocalFile::IsDirectory(PRBool
*_retval
)
1386 NS_ENSURE_ARG_POINTER(_retval
);
1387 *_retval
= PR_FALSE
;
1388 VALIDATE_STAT_CACHE();
1389 *_retval
= S_ISDIR(mCachedStat
.st_mode
);
1394 nsLocalFile::IsFile(PRBool
*_retval
)
1396 NS_ENSURE_ARG_POINTER(_retval
);
1397 *_retval
= PR_FALSE
;
1398 VALIDATE_STAT_CACHE();
1399 *_retval
= S_ISREG(mCachedStat
.st_mode
);
1404 nsLocalFile::IsHidden(PRBool
*_retval
)
1406 NS_ENSURE_ARG_POINTER(_retval
);
1407 nsACString::const_iterator begin
, end
;
1408 LocateNativeLeafName(begin
, end
);
1409 *_retval
= (*begin
== '.');
1414 nsLocalFile::IsSymlink(PRBool
*_retval
)
1416 NS_ENSURE_ARG_POINTER(_retval
);
1419 struct stat symStat
;
1420 lstat(mPath
.get(), &symStat
);
1421 *_retval
=S_ISLNK(symStat
.st_mode
);
1426 nsLocalFile::IsSpecial(PRBool
*_retval
)
1428 NS_ENSURE_ARG_POINTER(_retval
);
1429 VALIDATE_STAT_CACHE();
1430 *_retval
= S_ISCHR(mCachedStat
.st_mode
) ||
1431 S_ISBLK(mCachedStat
.st_mode
) ||
1433 S_ISSOCK(mCachedStat
.st_mode
) ||
1435 S_ISFIFO(mCachedStat
.st_mode
);
1441 nsLocalFile::Equals(nsIFile
*inFile
, PRBool
*_retval
)
1443 NS_ENSURE_ARG(inFile
);
1444 NS_ENSURE_ARG_POINTER(_retval
);
1445 *_retval
= PR_FALSE
;
1448 nsCAutoString inPath
;
1450 if (NS_FAILED(rv
= inFile
->GetNativePath(inPath
)))
1453 *_retval
= !FILE_STRCMP(inPath
.get(), mPath
.get());
1458 nsLocalFile::Contains(nsIFile
*inFile
, PRBool recur
, PRBool
*_retval
)
1461 NS_ENSURE_ARG(inFile
);
1462 NS_ENSURE_ARG_POINTER(_retval
);
1464 nsCAutoString inPath
;
1467 if (NS_FAILED(rv
= inFile
->GetNativePath(inPath
)))
1470 *_retval
= PR_FALSE
;
1472 ssize_t len
= mPath
.Length();
1473 if (FILE_STRNCMP(mPath
.get(), inPath
.get(), len
) == 0) {
1474 // Now make sure that the |inFile|'s path has a separator at len,
1475 // which implies that it has more components after len.
1476 if (inPath
[len
] == '/')
1484 nsLocalFile::GetNativeTarget(nsACString
&_retval
)
1489 struct stat symStat
;
1490 lstat(mPath
.get(), &symStat
);
1491 if (!S_ISLNK(symStat
.st_mode
))
1492 return NS_ERROR_FILE_INVALID_PATH
;
1494 PRInt64 targetSize64
;
1495 if (NS_FAILED(GetFileSizeOfLink(&targetSize64
)))
1496 return NS_ERROR_FAILURE
;
1499 LL_L2I(size
, targetSize64
);
1500 char *target
= (char *)nsMemory::Alloc(size
+ 1);
1502 return NS_ERROR_OUT_OF_MEMORY
;
1504 if (readlink(mPath
.get(), target
, (size_t)size
) < 0) {
1505 nsMemory::Free(target
);
1506 return NSRESULT_FOR_ERRNO();
1508 target
[size
] = '\0';
1512 nsCOMPtr
<nsIFile
> self(this);
1513 nsCOMPtr
<nsIFile
> parent
;
1514 while (NS_SUCCEEDED(rv
= self
->GetParent(getter_AddRefs(parent
)))) {
1515 NS_ASSERTION(parent
!= nsnull
, "no parent?!");
1517 if (target
[0] != '/') {
1518 nsCOMPtr
<nsILocalFile
> localFile(do_QueryInterface(parent
, &rv
));
1521 if (NS_FAILED(rv
= localFile
->AppendRelativeNativePath(nsDependentCString(target
))))
1523 if (NS_FAILED(rv
= localFile
->GetNativePath(_retval
)))
1525 if (NS_FAILED(rv
= parent
->IsSymlink(&isSymlink
)))
1529 nsCOMPtr
<nsILocalFile
> localFile
;
1530 rv
= NS_NewNativeLocalFile(nsDependentCString(target
), PR_TRUE
,
1531 getter_AddRefs(localFile
));
1534 if (NS_FAILED(rv
= localFile
->IsSymlink(&isSymlink
)))
1536 _retval
= target
; // XXX can we avoid this buffer copy?
1537 self
= do_QueryInterface(localFile
);
1539 if (NS_FAILED(rv
) || !isSymlink
)
1542 const nsPromiseFlatCString
&flatRetval
= PromiseFlatCString(_retval
);
1544 // strip off any and all trailing '/'
1545 PRInt32 len
= strlen(target
);
1546 while (target
[len
-1] == '/' && len
> 1)
1547 target
[--len
] = '\0';
1548 if (lstat(flatRetval
.get(), &symStat
) < 0) {
1549 rv
= NSRESULT_FOR_ERRNO();
1552 if (!S_ISLNK(symStat
.st_mode
)) {
1553 rv
= NS_ERROR_FILE_INVALID_PATH
;
1556 size
= symStat
.st_size
;
1557 if (readlink(flatRetval
.get(), target
, size
) < 0) {
1558 rv
= NSRESULT_FOR_ERRNO();
1561 target
[size
] = '\0';
1566 nsMemory::Free(target
);
1573 /* attribute PRBool followLinks; */
1575 nsLocalFile::GetFollowLinks(PRBool
*aFollowLinks
)
1577 *aFollowLinks
= PR_TRUE
;
1582 nsLocalFile::SetFollowLinks(PRBool aFollowLinks
)
1588 nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator
**entries
)
1590 nsDirEnumeratorUnix
*dir
= new nsDirEnumeratorUnix();
1592 return NS_ERROR_OUT_OF_MEMORY
;
1595 nsresult rv
= dir
->Init(this, PR_FALSE
);
1596 if (NS_FAILED(rv
)) {
1600 *entries
= dir
; // transfer reference
1607 nsLocalFile::Load(PRLibrary
**_retval
)
1610 NS_ENSURE_ARG_POINTER(_retval
);
1612 NS_TIMELINE_START_TIMER("PR_LoadLibrary");
1614 #ifdef NS_BUILD_REFCNT_LOGGING
1615 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE
);
1618 *_retval
= PR_LoadLibrary(mPath
.get());
1620 #ifdef NS_BUILD_REFCNT_LOGGING
1621 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE
);
1624 NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
1625 NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath
.get());
1628 return NS_ERROR_FAILURE
;
1633 nsLocalFile::GetPersistentDescriptor(nsACString
&aPersistentDescriptor
)
1635 return GetNativePath(aPersistentDescriptor
);
1639 nsLocalFile::SetPersistentDescriptor(const nsACString
&aPersistentDescriptor
)
1641 return InitWithNativePath(aPersistentDescriptor
);
1646 nsLocalFile::Reveal()
1648 BPath
bPath(mPath
.get());
1650 if (NS_FAILED(IsDirectory(&isDirectory
)))
1651 return NS_ERROR_FAILURE
;
1654 bPath
.GetParent(&bPath
);
1656 get_ref_for_path(bPath
.Path(),&ref
);
1657 BMessage
message(B_REFS_RECEIVED
);
1658 message
.AddRef("refs",&ref
);
1659 BMessenger
messenger("application/x-vnd.Be-TRAK");
1660 messenger
.SendMessage(&message
);
1665 nsLocalFile::Launch()
1668 get_ref_for_path (mPath
.get(), &ref
);
1669 be_roster
->Launch (&ref
);
1675 nsLocalFile::Reveal()
1677 #ifdef MOZ_WIDGET_GTK2
1678 nsCOMPtr
<nsIGnomeVFSService
> vfs
= do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID
);
1680 return NS_ERROR_FAILURE
;
1683 if (NS_FAILED(IsDirectory(&isDirectory
)))
1684 return NS_ERROR_FAILURE
;
1687 return vfs
->ShowURIForInput(mPath
);
1689 nsCOMPtr
<nsIFile
> parentDir
;
1690 nsCAutoString dirPath
;
1691 if (NS_FAILED(GetParent(getter_AddRefs(parentDir
))))
1692 return NS_ERROR_FAILURE
;
1693 if (NS_FAILED(parentDir
->GetNativePath(dirPath
)))
1694 return NS_ERROR_FAILURE
;
1696 return vfs
->ShowURIForInput(dirPath
);
1699 return NS_ERROR_FAILURE
;
1704 nsLocalFile::Launch()
1706 #ifdef MOZ_WIDGET_GTK2
1707 nsCOMPtr
<nsIGnomeVFSService
> vfs
= do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID
);
1709 return NS_ERROR_FAILURE
;
1711 return vfs
->ShowURIForInput(mPath
);
1713 return NS_ERROR_FAILURE
;
1719 NS_NewNativeLocalFile(const nsACString
&path
, PRBool followSymlinks
, nsILocalFile
**result
)
1721 nsLocalFile
*file
= new nsLocalFile();
1723 return NS_ERROR_OUT_OF_MEMORY
;
1726 if (!path
.IsEmpty()) {
1727 nsresult rv
= file
->InitWithNativePath(path
);
1728 if (NS_FAILED(rv
)) {
1737 //-----------------------------------------------------------------------------
1739 //-----------------------------------------------------------------------------
1741 #define SET_UCS(func, ucsArg) \
1743 nsCAutoString buf; \
1744 nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
1745 if (NS_FAILED(rv)) \
1747 return (func)(buf); \
1750 #define GET_UCS(func, ucsArg) \
1752 nsCAutoString buf; \
1753 nsresult rv = (func)(buf); \
1754 if (NS_FAILED(rv)) return rv; \
1755 return NS_CopyNativeToUnicode(buf, ucsArg); \
1758 #define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \
1760 nsCAutoString buf; \
1761 nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
1762 if (NS_FAILED(rv)) \
1764 return (func)(opaqueArg, buf); \
1767 // Unicode interface Wrapper
1769 nsLocalFile::InitWithPath(const nsAString
&filePath
)
1771 SET_UCS(InitWithNativePath
, filePath
);
1774 nsLocalFile::Append(const nsAString
&node
)
1776 SET_UCS(AppendNative
, node
);
1779 nsLocalFile::AppendRelativePath(const nsAString
&node
)
1781 SET_UCS(AppendRelativeNativePath
, node
);
1784 nsLocalFile::GetLeafName(nsAString
&aLeafName
)
1786 GET_UCS(GetNativeLeafName
, aLeafName
);
1789 nsLocalFile::SetLeafName(const nsAString
&aLeafName
)
1791 SET_UCS(SetNativeLeafName
, aLeafName
);
1794 nsLocalFile::GetPath(nsAString
&_retval
)
1796 return NS_CopyNativeToUnicode(mPath
, _retval
);
1799 nsLocalFile::CopyTo(nsIFile
*newParentDir
, const nsAString
&newName
)
1801 SET_UCS_2ARGS_2(CopyToNative
, newParentDir
, newName
);
1804 nsLocalFile::CopyToFollowingLinks(nsIFile
*newParentDir
, const nsAString
&newName
)
1806 SET_UCS_2ARGS_2(CopyToFollowingLinksNative
, newParentDir
, newName
);
1809 nsLocalFile::MoveTo(nsIFile
*newParentDir
, const nsAString
&newName
)
1811 SET_UCS_2ARGS_2(MoveToNative
, newParentDir
, newName
);
1814 nsLocalFile::GetTarget(nsAString
&_retval
)
1816 GET_UCS(GetNativeTarget
, _retval
);
1822 nsLocalFile::Equals(nsIHashable
* aOther
, PRBool
*aResult
)
1824 nsCOMPtr
<nsIFile
> otherFile(do_QueryInterface(aOther
));
1826 *aResult
= PR_FALSE
;
1830 return Equals(otherFile
, aResult
);
1834 nsLocalFile::GetHashCode(PRUint32
*aResult
)
1836 *aResult
= nsCRT::HashCode(mPath
.get());
1841 NS_NewLocalFile(const nsAString
&path
, PRBool followLinks
, nsILocalFile
* *result
)
1844 nsresult rv
= NS_CopyUnicodeToNative(path
, buf
);
1847 return NS_NewNativeLocalFile(buf
, followLinks
, result
);
1850 //-----------------------------------------------------------------------------
1851 // global init/shutdown
1852 //-----------------------------------------------------------------------------
1855 nsLocalFile::GlobalInit()
1860 nsLocalFile::GlobalShutdown()