LCOV - code coverage report
Current view: directory - xpcom/io - nsLocalFileUnix.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 752 549 73.0 %
Date: 2012-06-02 Functions: 89 77 86.5 %

       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
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code, released
      16                 :  * March 31, 1998.
      17                 :  *
      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.
      22                 :  *
      23                 :  * Contributor(s):
      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>
      33                 :  *
      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.
      45                 :  *
      46                 :  * ***** END LICENSE BLOCK ***** */
      47                 : 
      48                 : /**
      49                 :  * Implementation of nsIFile for "unixy" systems.
      50                 :  */
      51                 : 
      52                 : #include "mozilla/Util.h"
      53                 : 
      54                 : #include <sys/types.h>
      55                 : #include <sys/stat.h>
      56                 : #include <unistd.h>
      57                 : #include <fcntl.h>
      58                 : #include <errno.h>
      59                 : #include <utime.h>
      60                 : #include <dirent.h>
      61                 : #include <ctype.h>
      62                 : #include <locale.h>
      63                 : #if defined(VMS)
      64                 :     #include <fabdef.h>
      65                 : #endif
      66                 : 
      67                 : #if defined(HAVE_SYS_QUOTA_H) && defined(HAVE_LINUX_QUOTA_H)
      68                 : #define USE_LINUX_QUOTACTL
      69                 : #include <sys/quota.h>
      70                 : #endif
      71                 : 
      72                 : #if (MOZ_PLATFORM_MAEMO == 6)
      73                 : #include <QUrl>
      74                 : #include <QString>
      75                 : #if (MOZ_ENABLE_CONTENTACTION)
      76                 : #include <contentaction/contentaction.h>
      77                 : #endif
      78                 : #endif
      79                 : 
      80                 : #include "nsDirectoryServiceDefs.h"
      81                 : #include "nsCRT.h"
      82                 : #include "nsCOMPtr.h"
      83                 : #include "nsMemory.h"
      84                 : #include "nsIFile.h"
      85                 : #include "nsString.h"
      86                 : #include "nsReadableUtils.h"
      87                 : #include "nsLocalFile.h"
      88                 : #include "nsIComponentManager.h"
      89                 : #include "nsXPIDLString.h"
      90                 : #include "prproces.h"
      91                 : #include "nsIDirectoryEnumerator.h"
      92                 : #include "nsISimpleEnumerator.h"
      93                 : #include "private/pprio.h"
      94                 : 
      95                 : #ifdef MOZ_WIDGET_GTK2
      96                 : #include "nsIGIOService.h"
      97                 : #include "nsIGnomeVFSService.h"
      98                 : #endif
      99                 : 
     100                 : #ifdef MOZ_WIDGET_COCOA
     101                 : #include <Carbon/Carbon.h>
     102                 : #include "CocoaFileUtils.h"
     103                 : #include "prmem.h"
     104                 : #include "plbase64.h"
     105                 : 
     106                 : static nsresult MacErrorMapper(OSErr inErr);
     107                 : #endif
     108                 : 
     109                 : #if (MOZ_PLATFORM_MAEMO == 5)
     110                 : #include <glib.h>
     111                 : #include <hildon-uri.h>
     112                 : #include <hildon-mime.h>
     113                 : #include <libosso.h>
     114                 : #endif
     115                 : 
     116                 : #ifdef MOZ_WIDGET_ANDROID
     117                 : #include "AndroidBridge.h"
     118                 : #include "nsIMIMEService.h"
     119                 : #include <linux/magic.h>
     120                 : #endif
     121                 : 
     122                 : #include "nsNativeCharsetUtils.h"
     123                 : #include "nsTraceRefcntImpl.h"
     124                 : #include "nsHashKeys.h"
     125                 : 
     126                 : using namespace mozilla;
     127                 : 
     128                 : #define ENSURE_STAT_CACHE()                     \
     129                 :     PR_BEGIN_MACRO                              \
     130                 :         if (!FillStatCache())                   \
     131                 :              return NSRESULT_FOR_ERRNO();       \
     132                 :     PR_END_MACRO
     133                 : 
     134                 : #define CHECK_mPath()                           \
     135                 :     PR_BEGIN_MACRO                              \
     136                 :         if (mPath.IsEmpty())                    \
     137                 :             return NS_ERROR_NOT_INITIALIZED;    \
     138                 :     PR_END_MACRO
     139                 : 
     140                 : /* directory enumerator */
     141                 : class
     142                 : nsDirEnumeratorUnix : public nsISimpleEnumerator,
     143                 :                       public nsIDirectoryEnumerator
     144                 : {
     145                 :     public:
     146                 :     nsDirEnumeratorUnix();
     147                 : 
     148                 :     // nsISupports interface
     149                 :     NS_DECL_ISUPPORTS
     150                 : 
     151                 :     // nsISimpleEnumerator interface
     152                 :     NS_DECL_NSISIMPLEENUMERATOR
     153                 : 
     154                 :     // nsIDirectoryEnumerator interface
     155                 :     NS_DECL_NSIDIRECTORYENUMERATOR
     156                 : 
     157                 :     NS_IMETHOD Init(nsLocalFile *parent, bool ignored);
     158                 : 
     159                 :     private:
     160                 :     ~nsDirEnumeratorUnix();
     161                 : 
     162                 :     protected:
     163                 :     NS_IMETHOD GetNextEntry();
     164                 : 
     165                 :     DIR           *mDir;
     166                 :     struct dirent *mEntry;
     167                 :     nsCString      mParentPath;
     168                 : };
     169                 : 
     170           12472 : nsDirEnumeratorUnix::nsDirEnumeratorUnix() :
     171                 :                          mDir(nsnull), 
     172           12472 :                          mEntry(nsnull)
     173                 : {
     174           12472 : }
     175                 : 
     176           24944 : nsDirEnumeratorUnix::~nsDirEnumeratorUnix()
     177                 : {
     178           12472 :     Close();
     179           12472 : }
     180                 : 
     181          233448 : NS_IMPL_ISUPPORTS2(nsDirEnumeratorUnix, nsISimpleEnumerator, nsIDirectoryEnumerator)
     182                 : 
     183                 : NS_IMETHODIMP
     184           12472 : nsDirEnumeratorUnix::Init(nsLocalFile *parent, bool resolveSymlinks /*ignored*/)
     185                 : {
     186           24944 :     nsCAutoString dirPath;
     187           24944 :     if (NS_FAILED(parent->GetNativePath(dirPath)) ||
     188           12472 :         dirPath.IsEmpty()) {
     189               0 :         return NS_ERROR_FILE_INVALID_PATH;
     190                 :     }
     191                 : 
     192           12472 :     if (NS_FAILED(parent->GetNativePath(mParentPath)))
     193               0 :         return NS_ERROR_FAILURE;
     194                 : 
     195           12472 :     mDir = opendir(dirPath.get());
     196           12472 :     if (!mDir)
     197            1412 :         return NSRESULT_FOR_ERRNO();
     198           11060 :     return GetNextEntry();
     199                 : }
     200                 : 
     201                 : NS_IMETHODIMP
     202           19949 : nsDirEnumeratorUnix::HasMoreElements(bool *result)
     203                 : {
     204           19949 :     *result = mDir && mEntry;
     205           19949 :     if (!*result)
     206            5298 :         Close();
     207           19949 :     return NS_OK;
     208                 : }
     209                 : 
     210                 : NS_IMETHODIMP
     211           14561 : nsDirEnumeratorUnix::GetNext(nsISupports **_retval)
     212                 : {
     213           29122 :     nsCOMPtr<nsIFile> file;
     214           14561 :     nsresult rv = GetNextFile(getter_AddRefs(file));
     215           14561 :     if (NS_FAILED(rv))
     216               0 :         return rv;
     217           14561 :     NS_IF_ADDREF(*_retval = file);
     218           14561 :     return NS_OK;
     219                 : }
     220                 : 
     221                 : NS_IMETHODIMP
     222           56167 : nsDirEnumeratorUnix::GetNextEntry()
     223                 : {
     224          134412 :     do {
     225           56167 :         errno = 0;
     226           56167 :         mEntry = readdir(mDir);
     227                 : 
     228                 :         // end of dir or error
     229           56167 :         if (!mEntry)
     230           11013 :             return NSRESULT_FOR_ERRNO();
     231                 : 
     232                 :         // keep going past "." and ".."
     233           45154 :     } while (mEntry->d_name[0] == '.'     &&
     234           22047 :             (mEntry->d_name[1] == '\0'    ||   // .\0
     235           11034 :             (mEntry->d_name[1] == '.'     &&
     236           11023 :             mEntry->d_name[2] == '\0')));      // ..\0
     237           23118 :     return NS_OK;
     238                 : }
     239                 : 
     240                 : NS_IMETHODIMP
     241           28787 : nsDirEnumeratorUnix::GetNextFile(nsIFile **_retval)
     242                 : {
     243                 :     nsresult rv;
     244           28787 :     if (!mDir || !mEntry) {
     245            5716 :         *_retval = nsnull;
     246            5716 :         return NS_OK;
     247                 :     }
     248                 : 
     249           46142 :     nsCOMPtr<nsILocalFile> file = new nsLocalFile();
     250           23071 :     if (!file)
     251               0 :         return NS_ERROR_OUT_OF_MEMORY;
     252                 : 
     253           92284 :     if (NS_FAILED(rv = file->InitWithNativePath(mParentPath)) ||
     254           69213 :         NS_FAILED(rv = file->AppendNative(nsDependentCString(mEntry->d_name))))
     255               0 :         return rv;
     256                 : 
     257           23071 :     *_retval = file;
     258           23071 :     NS_ADDREF(*_retval);
     259           23071 :     return GetNextEntry();
     260                 : }
     261                 : 
     262                 : NS_IMETHODIMP 
     263           23881 : nsDirEnumeratorUnix::Close()
     264                 : {
     265           23881 :     if (mDir) {
     266           11060 :         closedir(mDir);
     267           11060 :         mDir = nsnull;
     268                 :     }
     269           23881 :     return NS_OK;
     270                 : }
     271                 : 
     272          561310 : nsLocalFile::nsLocalFile()
     273                 : {
     274          561310 : }
     275                 : 
     276          236238 : nsLocalFile::nsLocalFile(const nsLocalFile& other)
     277          236238 :   : mPath(other.mPath)
     278                 : {
     279          236238 : }
     280                 : 
     281                 : #ifdef MOZ_WIDGET_COCOA
     282                 : NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
     283                 :                               nsILocalFileMac,
     284                 :                               nsILocalFile,
     285                 :                               nsIFile,
     286                 :                               nsIHashable)
     287                 : #else
     288        15897806 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile,
     289                 :                               nsILocalFile,
     290                 :                               nsIFile,
     291                 :                               nsIHashable)
     292                 : #endif
     293                 : 
     294                 : nsresult
     295            8229 : nsLocalFile::nsLocalFileConstructor(nsISupports *outer, 
     296                 :                                     const nsIID &aIID,
     297                 :                                     void **aInstancePtr)
     298                 : {
     299            8229 :     NS_ENSURE_ARG_POINTER(aInstancePtr);
     300            8229 :     NS_ENSURE_NO_AGGREGATION(outer);
     301                 : 
     302            8229 :     *aInstancePtr = nsnull;
     303                 : 
     304           16458 :     nsCOMPtr<nsIFile> inst = new nsLocalFile();
     305            8229 :     if (!inst)
     306               0 :         return NS_ERROR_OUT_OF_MEMORY;
     307            8229 :     return inst->QueryInterface(aIID, aInstancePtr);
     308                 : }
     309                 : 
     310                 : bool 
     311          145472 : nsLocalFile::FillStatCache() {
     312          145472 :     if (STAT(mPath.get(), &mCachedStat) == -1) {
     313                 :         // try lstat it may be a symlink
     314            5701 :         if (LSTAT(mPath.get(), &mCachedStat) == -1) {
     315            5680 :             return false;
     316                 :         }
     317                 :     }
     318          139792 :     return true;
     319                 : }
     320                 : 
     321                 : NS_IMETHODIMP
     322          236238 : nsLocalFile::Clone(nsIFile **file)
     323                 : {
     324                 :     // Just copy-construct ourselves
     325          236238 :     *file = new nsLocalFile(*this);
     326          236238 :     if (!*file)
     327               0 :       return NS_ERROR_OUT_OF_MEMORY;
     328                 : 
     329          236238 :     NS_ADDREF(*file);
     330                 :     
     331          236238 :     return NS_OK;
     332                 : }
     333                 : 
     334                 : NS_IMETHODIMP
     335          561311 : nsLocalFile::InitWithNativePath(const nsACString &filePath)
     336                 : {
     337          561311 :     if (Substring(filePath, 0, 2).EqualsLiteral("~/")) {
     338             272 :         nsCOMPtr<nsIFile> homeDir;
     339             272 :         nsCAutoString homePath;
     340             272 :         if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR,
     341                 :                                              getter_AddRefs(homeDir))) ||
     342             136 :             NS_FAILED(homeDir->GetNativePath(homePath))) {
     343               0 :             return NS_ERROR_FAILURE;
     344                 :         }
     345                 :         
     346             272 :         mPath = homePath + Substring(filePath, 1, filePath.Length() - 1);
     347                 :     } else {
     348          561175 :         if (filePath.IsEmpty() || filePath.First() != '/')
     349              30 :             return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     350          561145 :         mPath = filePath;
     351                 :     }
     352                 : 
     353                 :     // trim off trailing slashes
     354          561281 :     ssize_t len = mPath.Length();
     355         1122629 :     while ((len > 1) && (mPath[len - 1] == '/'))
     356              67 :         --len;
     357          561281 :     mPath.SetLength(len);
     358                 : 
     359          561281 :     return NS_OK;
     360                 : }
     361                 : 
     362                 : NS_IMETHODIMP
     363             528 : nsLocalFile::CreateAllAncestors(PRUint32 permissions)
     364                 : {
     365                 :     // <jband> I promise to play nice
     366             528 :     char *buffer = mPath.BeginWriting(),
     367             528 :          *slashp = buffer;
     368                 : 
     369                 : #ifdef DEBUG_NSIFILE
     370                 :     fprintf(stderr, "nsIFile: before: %s\n", buffer);
     371                 : #endif
     372                 : 
     373            3245 :     while ((slashp = strchr(slashp + 1, '/'))) {
     374                 :         /*
     375                 :          * Sequences of '/' are equivalent to a single '/'.
     376                 :          */
     377            2189 :         if (slashp[1] == '/')
     378               0 :             continue;
     379                 : 
     380                 :         /*
     381                 :          * If the path has a trailing slash, don't make the last component,
     382                 :          * because we'll get EEXIST in Create when we try to build the final
     383                 :          * component again, and it's easier to condition the logic here than
     384                 :          * there.
     385                 :          */
     386            2189 :         if (slashp[1] == '\0')
     387               0 :             break;
     388                 : 
     389                 :         /* Temporarily NUL-terminate here */
     390            2189 :         *slashp = '\0';
     391                 : #ifdef DEBUG_NSIFILE
     392                 :         fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer);
     393                 : #endif
     394            2189 :         int mkdir_result = mkdir(buffer, permissions);
     395            2189 :         int mkdir_errno  = errno;
     396            2189 :         if (mkdir_result == -1) {
     397                 :             /*
     398                 :              * Always set |errno| to EEXIST if the dir already exists
     399                 :              * (we have to do this here since the errno value is not consistent
     400                 :              * in all cases - various reasons like different platform,
     401                 :              * automounter-controlled dir, etc. can affect it (see bug 125489
     402                 :              * for details)).
     403                 :              */
     404            1603 :             if (access(buffer, F_OK) == 0) {
     405            1603 :                 mkdir_errno = EEXIST;
     406                 :             }
     407                 :         }
     408                 : 
     409                 :         /* Put the / back before we (maybe) return */
     410            2189 :         *slashp = '/';
     411                 : 
     412                 :         /*
     413                 :          * We could get EEXIST for an existing file -- not directory --
     414                 :          * with the name of one of our ancestors, but that's OK: we'll get
     415                 :          * ENOTDIR when we try to make the next component in the path,
     416                 :          * either here on back in Create, and error out appropriately.
     417                 :          */
     418            2189 :         if (mkdir_result == -1 && mkdir_errno != EEXIST)
     419               0 :             return nsresultForErrno(mkdir_errno);
     420                 :     }
     421                 : 
     422                 : #ifdef DEBUG_NSIFILE
     423                 :     fprintf(stderr, "nsIFile: after: %s\n", buffer);
     424                 : #endif
     425                 : 
     426             528 :     return NS_OK;
     427                 : }
     428                 : 
     429                 : NS_IMETHODIMP
     430          353718 : nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
     431                 : {
     432          353718 :     *_retval = PR_Open(mPath.get(), flags, mode);
     433          353718 :     if (! *_retval)
     434             767 :         return NS_ErrorAccordingToNSPR();
     435                 : 
     436          352951 :     if (flags & DELETE_ON_CLOSE) {
     437               1 :         PR_Delete(mPath.get());
     438                 :     }
     439                 : 
     440                 : #if defined(LINUX) && !defined(ANDROID)
     441          352951 :     if (flags & OS_READAHEAD) {
     442               0 :         readahead(PR_FileDesc2NativeHandle(*_retval), 0, 0);
     443                 :     }
     444                 : #endif
     445          352951 :     return NS_OK;
     446                 : }
     447                 : 
     448                 : NS_IMETHODIMP
     449               0 : nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
     450                 : {
     451               0 :     *_retval = fopen(mPath.get(), mode);
     452               0 :     if (! *_retval)
     453               0 :         return NS_ERROR_FAILURE;
     454                 : 
     455               0 :     return NS_OK;
     456                 : }
     457                 : 
     458                 : static int
     459            3724 : do_create(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval)
     460                 : {
     461            3724 :     *_retval = PR_Open(path, flags, mode);
     462            3724 :     return *_retval ? 0 : -1;
     463                 : }
     464                 : 
     465                 : static int
     466            8430 : do_mkdir(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval)
     467                 : {
     468            8430 :     *_retval = nsnull;
     469            8430 :     return mkdir(path, mode);
     470                 : }
     471                 : 
     472                 : nsresult
     473           11626 : nsLocalFile::CreateAndKeepOpen(PRUint32 type, PRIntn flags,
     474                 :                                PRUint32 permissions, PRFileDesc **_retval)
     475                 : {
     476           11626 :     if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
     477               0 :         return NS_ERROR_FILE_UNKNOWN_TYPE;
     478                 : 
     479                 :     int result;
     480                 :     int (*createFunc)(const char *, PRIntn, mode_t, PRFileDesc **) =
     481           11626 :         (type == NORMAL_FILE_TYPE) ? do_create : do_mkdir;
     482                 : 
     483           11626 :     result = createFunc(mPath.get(), flags, permissions, _retval);
     484           11626 :     if (result == -1 && errno == ENOENT) {
     485                 :         /*
     486                 :          * If we failed because of missing ancestor components, try to create
     487                 :          * them and then retry the original creation.
     488                 :          *
     489                 :          * Ancestor directories get the same permissions as the file we're
     490                 :          * creating, with the X bit set for each of (user,group,other) with
     491                 :          * an R bit in the original permissions.    If you want to do anything
     492                 :          * fancy like setgid or sticky bits, do it by hand.
     493                 :          */
     494             528 :         int dirperm = permissions;
     495             528 :         if (permissions & S_IRUSR)
     496             528 :             dirperm |= S_IXUSR;
     497             528 :         if (permissions & S_IRGRP)
     498             528 :             dirperm |= S_IXGRP;
     499             528 :         if (permissions & S_IROTH)
     500             528 :             dirperm |= S_IXOTH;
     501                 : 
     502                 : #ifdef DEBUG_NSIFILE
     503                 :         fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions,
     504                 :                 dirperm);
     505                 : #endif
     506                 : 
     507             528 :         if (NS_FAILED(CreateAllAncestors(dirperm)))
     508               0 :             return NS_ERROR_FAILURE;
     509                 : 
     510                 : #ifdef DEBUG_NSIFILE
     511                 :         fprintf(stderr, "nsIFile: Create(\"%s\") again\n", mPath.get());
     512                 : #endif
     513             528 :         result = createFunc(mPath.get(), flags, permissions, _retval);
     514                 :     }
     515           11626 :     return NSRESULT_FOR_RETURN(result);
     516                 : }
     517                 : 
     518                 : NS_IMETHODIMP
     519           11122 : nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
     520                 : {
     521           11122 :     PRFileDesc *junk = nsnull;
     522                 :     nsresult rv = CreateAndKeepOpen(type,
     523                 :                                     PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE |
     524                 :                                     PR_EXCL,
     525                 :                                     permissions,
     526           11122 :                                     &junk);
     527           11122 :     if (junk)
     528            1621 :         PR_Close(junk);
     529           11122 :     return rv;
     530                 : }
     531                 : 
     532                 : NS_IMETHODIMP
     533           85976 : nsLocalFile::AppendNative(const nsACString &fragment)
     534                 : {
     535           85976 :     if (fragment.IsEmpty())
     536              75 :         return NS_OK;
     537                 : 
     538                 :     // only one component of path can be appended
     539           85901 :     nsACString::const_iterator begin, end;
     540           85901 :     if (FindCharInReadable('/', fragment.BeginReading(begin),
     541           85901 :                                 fragment.EndReading(end)))
     542               1 :         return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     543                 : 
     544           85900 :     return AppendRelativeNativePath(fragment);
     545                 : }
     546                 : 
     547                 : NS_IMETHODIMP
     548          545410 : nsLocalFile::AppendRelativeNativePath(const nsACString &fragment)
     549                 : {
     550          545410 :     if (fragment.IsEmpty())
     551               0 :         return NS_OK;
     552                 : 
     553                 :     // No leading '/' 
     554          545410 :     if (fragment.First() == '/')
     555               0 :         return NS_ERROR_FILE_UNRECOGNIZED_PATH;
     556                 : 
     557          545410 :     if (mPath.EqualsLiteral("/"))
     558               0 :         mPath.Append(fragment);
     559                 :     else
     560          545410 :         mPath.Append(NS_LITERAL_CSTRING("/") + fragment);
     561                 : 
     562          545410 :     return NS_OK;
     563                 : }
     564                 : 
     565                 : NS_IMETHODIMP
     566            1412 : nsLocalFile::Normalize()
     567                 : {
     568            1412 :     char    resolved_path[PATH_MAX] = "";
     569            1412 :     char *resolved_path_ptr = nsnull;
     570                 : 
     571            1412 :     resolved_path_ptr = realpath(mPath.get(), resolved_path);
     572                 : 
     573                 :     // if there is an error, the return is null.
     574            1412 :     if (!resolved_path_ptr)
     575             485 :         return NSRESULT_FOR_ERRNO();
     576                 : 
     577             927 :     mPath = resolved_path;
     578             927 :     return NS_OK;
     579                 : }
     580                 : 
     581                 : void
     582           72529 : nsLocalFile::LocateNativeLeafName(nsACString::const_iterator &begin, 
     583                 :                                   nsACString::const_iterator &end)
     584                 : {
     585                 :     // XXX perhaps we should cache this??
     586                 : 
     587           72529 :     mPath.BeginReading(begin);
     588           72529 :     mPath.EndReading(end);
     589                 :     
     590           72529 :     nsACString::const_iterator it = end;
     591           72529 :     nsACString::const_iterator stop = begin;
     592           72529 :     --stop;
     593           72529 :     while (--it != stop) {
     594         1265888 :         if (*it == '/') {
     595           72529 :             begin = ++it;
     596           72529 :             return;
     597                 :         }
     598                 :     }
     599                 :     // else, the entire path is the leaf name (which means this
     600                 :     // isn't an absolute path... unexpected??)
     601                 : }
     602                 : 
     603                 : NS_IMETHODIMP
     604           68338 : nsLocalFile::GetNativeLeafName(nsACString &aLeafName)
     605                 : {
     606           68338 :     nsACString::const_iterator begin, end;
     607           68338 :     LocateNativeLeafName(begin, end);
     608           68338 :     aLeafName = Substring(begin, end);
     609           68338 :     return NS_OK;
     610                 : }
     611                 : 
     612                 : NS_IMETHODIMP
     613            3007 : nsLocalFile::SetNativeLeafName(const nsACString &aLeafName)
     614                 : {
     615            3007 :     nsACString::const_iterator begin, end;
     616            3007 :     LocateNativeLeafName(begin, end);
     617            3007 :     mPath.Replace(begin.get() - mPath.get(), Distance(begin, end), aLeafName);
     618            3007 :     return NS_OK;
     619                 : }
     620                 : 
     621                 : NS_IMETHODIMP
     622          240002 : nsLocalFile::GetNativePath(nsACString &_retval)
     623                 : {
     624          240002 :     _retval = mPath;
     625          240002 :     return NS_OK;
     626                 : }
     627                 : 
     628                 : nsresult
     629            2598 : nsLocalFile::GetNativeTargetPathName(nsIFile *newParent, 
     630                 :                                      const nsACString &newName,
     631                 :                                      nsACString &_retval)
     632                 : {
     633                 :     nsresult rv;
     634            5196 :     nsCOMPtr<nsIFile> oldParent;
     635                 : 
     636            2598 :     if (!newParent) {
     637             828 :         if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent))))
     638               0 :             return rv;
     639             828 :         newParent = oldParent.get();
     640                 :     } else {
     641                 :         // check to see if our target directory exists
     642                 :         bool targetExists;
     643            1770 :         if (NS_FAILED(rv = newParent->Exists(&targetExists)))
     644               0 :             return rv;
     645                 : 
     646            1770 :         if (!targetExists) {
     647                 :             // XXX create the new directory with some permissions
     648             167 :             rv = newParent->Create(DIRECTORY_TYPE, 0755);
     649             167 :             if (NS_FAILED(rv))
     650               0 :                 return rv;
     651                 :         } else {
     652                 :             // make sure that the target is actually a directory
     653                 :             bool targetIsDirectory;
     654            1603 :             if (NS_FAILED(rv = newParent->IsDirectory(&targetIsDirectory)))
     655               0 :                 return rv;
     656            1603 :             if (!targetIsDirectory)
     657               0 :                 return NS_ERROR_FILE_DESTINATION_NOT_DIR;
     658                 :         }
     659                 :     }
     660                 : 
     661            2598 :     nsACString::const_iterator nameBegin, nameEnd;
     662            2598 :     if (!newName.IsEmpty()) {
     663            1487 :         newName.BeginReading(nameBegin);
     664            1487 :         newName.EndReading(nameEnd);
     665                 :     }
     666                 :     else
     667            1111 :         LocateNativeLeafName(nameBegin, nameEnd);
     668                 : 
     669            5196 :     nsCAutoString dirName;
     670            2598 :     if (NS_FAILED(rv = newParent->GetNativePath(dirName)))
     671               0 :         return rv;
     672                 : 
     673                 :     _retval = dirName
     674            5196 :             + NS_LITERAL_CSTRING("/")
     675            7794 :             + Substring(nameBegin, nameEnd);
     676            2598 :     return NS_OK;
     677                 : }
     678                 : 
     679                 : nsresult
     680               6 : nsLocalFile::CopyDirectoryTo(nsIFile *newParent)
     681                 : {
     682                 :     nsresult rv;
     683                 :     /*
     684                 :      * dirCheck is used for various boolean test results such as from Equals,
     685                 :      * Exists, isDir, etc.
     686                 :      */
     687                 :     bool dirCheck, isSymlink;
     688                 :     PRUint32 oldPerms;
     689                 : 
     690               6 :     if (NS_FAILED(rv = IsDirectory(&dirCheck)))
     691               0 :         return rv;
     692               6 :     if (!dirCheck)
     693               0 :         return CopyToNative(newParent, EmptyCString());
     694                 :     
     695               6 :     if (NS_FAILED(rv = Equals(newParent, &dirCheck)))
     696               0 :         return rv;
     697               6 :     if (dirCheck) { 
     698                 :         // can't copy dir to itself
     699               0 :         return NS_ERROR_INVALID_ARG;
     700                 :     }
     701                 :     
     702               6 :     if (NS_FAILED(rv = newParent->Exists(&dirCheck))) 
     703               0 :         return rv;
     704                 :     // get the dirs old permissions
     705               6 :     if (NS_FAILED(rv = GetPermissions(&oldPerms)))
     706               0 :         return rv;
     707               6 :     if (!dirCheck) {
     708               6 :         if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms)))
     709               0 :             return rv;
     710                 :     } else {    // dir exists lets try to use leaf
     711               0 :         nsCAutoString leafName;
     712               0 :         if (NS_FAILED(rv = GetNativeLeafName(leafName)))
     713               0 :             return rv;
     714               0 :         if (NS_FAILED(rv = newParent->AppendNative(leafName)))
     715               0 :             return rv;
     716               0 :         if (NS_FAILED(rv = newParent->Exists(&dirCheck)))
     717               0 :             return rv;
     718               0 :         if (dirCheck) 
     719               0 :             return NS_ERROR_FILE_ALREADY_EXISTS; // dest exists
     720               0 :         if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms)))
     721               0 :             return rv;
     722                 :     }
     723                 : 
     724              12 :     nsCOMPtr<nsISimpleEnumerator> dirIterator;
     725               6 :     if (NS_FAILED(rv = GetDirectoryEntries(getter_AddRefs(dirIterator))))
     726               0 :         return rv;
     727                 : 
     728               6 :     bool hasMore = false;
     729              24 :     while (dirIterator->HasMoreElements(&hasMore), hasMore) {
     730              24 :         nsCOMPtr<nsIFile> entry;
     731              12 :         rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(entry));
     732              12 :         if (NS_FAILED(rv)) 
     733               0 :             continue;
     734              12 :         if (NS_FAILED(rv = entry->IsSymlink(&isSymlink)))
     735               0 :             return rv;
     736              12 :         if (NS_FAILED(rv = entry->IsDirectory(&dirCheck)))
     737               0 :             return rv;
     738              12 :         if (dirCheck && !isSymlink) {
     739               8 :             nsCOMPtr<nsIFile> destClone;
     740               4 :             rv = newParent->Clone(getter_AddRefs(destClone));
     741               4 :             if (NS_SUCCEEDED(rv)) {
     742               8 :                 nsCOMPtr<nsILocalFile> newDir(do_QueryInterface(destClone));
     743               4 :                 if (NS_FAILED(rv = entry->CopyToNative(newDir, EmptyCString()))) {
     744                 : #ifdef DEBUG
     745                 :                     nsresult rv2;
     746               0 :                     nsCAutoString pathName;
     747               0 :                     if (NS_FAILED(rv2 = entry->GetNativePath(pathName)))
     748               0 :                         return rv2;
     749               0 :                     printf("Operation not supported: %s\n", pathName.get());
     750                 : #endif
     751               0 :                     if (rv == NS_ERROR_OUT_OF_MEMORY) 
     752               0 :                         return rv;
     753               0 :                     continue;
     754                 :                 }
     755               4 :             }
     756                 :         } else {
     757               8 :             if (NS_FAILED(rv = entry->CopyToNative(newParent, EmptyCString()))) {
     758                 : #ifdef DEBUG
     759                 :                 nsresult rv2;
     760               0 :                 nsCAutoString pathName;
     761               0 :                 if (NS_FAILED(rv2 = entry->GetNativePath(pathName)))
     762               0 :                     return rv2;
     763               0 :                 printf("Operation not supported: %s\n", pathName.get());
     764                 : #endif
     765               0 :                 if (rv == NS_ERROR_OUT_OF_MEMORY) 
     766               0 :                     return rv;
     767               0 :                 continue;
     768                 :             }
     769                 :         }
     770                 :     }
     771               6 :     return NS_OK;
     772                 : }
     773                 : 
     774                 : NS_IMETHODIMP
     775             510 : nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName)
     776                 : {
     777                 :     nsresult rv;
     778                 :     // check to make sure that this has been initialized properly
     779             510 :     CHECK_mPath();
     780                 : 
     781                 :     // we copy the parent here so 'newParent' remains immutable
     782            1020 :     nsCOMPtr <nsIFile> workParent;
     783             510 :     if (newParent) {
     784             506 :         if (NS_FAILED(rv = newParent->Clone(getter_AddRefs(workParent))))
     785               0 :             return rv;
     786                 :     } else {
     787               4 :         if (NS_FAILED(rv = GetParent(getter_AddRefs(workParent))))
     788               0 :             return rv;
     789                 :     }
     790                 :     
     791                 :     // check to see if we are a directory or if we are a file
     792                 :     bool isDirectory;
     793             510 :     if (NS_FAILED(rv = IsDirectory(&isDirectory)))
     794               0 :         return rv;
     795                 : 
     796            1020 :     nsCAutoString newPathName;
     797             510 :     if (isDirectory) {
     798               6 :         if (!newName.IsEmpty()) {
     799               2 :             if (NS_FAILED(rv = workParent->AppendNative(newName)))
     800               0 :                 return rv;
     801                 :         } else {
     802               4 :             if (NS_FAILED(rv = GetNativeLeafName(newPathName)))
     803               0 :                 return rv;
     804               4 :             if (NS_FAILED(rv = workParent->AppendNative(newPathName)))
     805               0 :                 return rv;
     806                 :         }
     807               6 :         if (NS_FAILED(rv = CopyDirectoryTo(workParent)))
     808               0 :             return rv;
     809                 :     } else {
     810             504 :         rv = GetNativeTargetPathName(workParent, newName, newPathName);
     811             504 :         if (NS_FAILED(rv)) 
     812               0 :             return rv;
     813                 : 
     814                 : #ifdef DEBUG_blizzard
     815                 :         printf("nsLocalFile::CopyTo() %s -> %s\n", mPath.get(), newPathName.get());
     816                 : #endif
     817                 : 
     818                 :         // actually create the file.
     819             504 :         nsLocalFile *newFile = new nsLocalFile();
     820             504 :         if (!newFile)
     821               0 :             return NS_ERROR_OUT_OF_MEMORY;
     822                 : 
     823            1008 :         nsCOMPtr<nsILocalFile> fileRef(newFile); // release on exit
     824                 : 
     825             504 :         rv = newFile->InitWithNativePath(newPathName);
     826             504 :         if (NS_FAILED(rv))
     827               0 :             return rv;
     828                 : 
     829                 :         // get the old permissions
     830                 :         PRUint32 myPerms;
     831             504 :         GetPermissions(&myPerms);
     832                 : 
     833                 :         // Create the new file with the old file's permissions, even if write
     834                 :         // permission is missing.  We can't create with write permission and
     835                 :         // then change back to myPerm on all filesystems (FAT on Linux, e.g.).
     836                 :         // But we can write to a read-only file on all Unix filesystems if we
     837                 :         // open it successfully for writing.
     838                 : 
     839                 :         PRFileDesc *newFD;
     840                 :         rv = newFile->CreateAndKeepOpen(NORMAL_FILE_TYPE,
     841                 :                                         PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,
     842                 :                                         myPerms,
     843             504 :                                         &newFD);
     844             504 :         if (NS_FAILED(rv))
     845               0 :             return rv;
     846                 : 
     847                 :         // open the old file, too
     848                 :         bool specialFile;
     849             504 :         if (NS_FAILED(rv = IsSpecial(&specialFile))) {
     850               0 :             PR_Close(newFD);
     851               0 :             return rv;
     852                 :         }
     853             504 :         if (specialFile) {
     854                 : #ifdef DEBUG
     855               0 :             printf("Operation not supported: %s\n", mPath.get());
     856                 : #endif
     857                 :             // make sure to clean up properly
     858               0 :             PR_Close(newFD);
     859               0 :             return NS_OK;
     860                 :         }
     861                 :                
     862                 :         PRFileDesc *oldFD;
     863             504 :         rv = OpenNSPRFileDesc(PR_RDONLY, myPerms, &oldFD);
     864             504 :         if (NS_FAILED(rv)) {
     865                 :             // make sure to clean up properly
     866               0 :             PR_Close(newFD);
     867               0 :             return rv;
     868                 :         }
     869                 : 
     870                 : #ifdef DEBUG_blizzard
     871                 :         PRInt32 totalRead = 0;
     872                 :         PRInt32 totalWritten = 0;
     873                 : #endif
     874                 :         char buf[BUFSIZ];
     875                 :         PRInt32 bytesRead;
     876                 :         
     877            2794 :         while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) {
     878                 : #ifdef DEBUG_blizzard
     879                 :             totalRead += bytesRead;
     880                 : #endif
     881                 : 
     882                 :             // PR_Write promises never to do a short write
     883            1786 :             PRInt32 bytesWritten = PR_Write(newFD, buf, bytesRead);
     884            1786 :             if (bytesWritten < 0) {
     885               0 :                 bytesRead = -1;
     886               0 :                 break;
     887                 :             }
     888            1786 :             NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?");
     889                 : 
     890                 : #ifdef DEBUG_blizzard
     891                 :             totalWritten += bytesWritten;
     892                 : #endif
     893                 :         }
     894                 : 
     895                 : #ifdef DEBUG_blizzard
     896                 :         printf("read %d bytes, wrote %d bytes\n",
     897                 :                  totalRead, totalWritten);
     898                 : #endif
     899                 : 
     900                 :         // close the files
     901             504 :         PR_Close(newFD);
     902             504 :         PR_Close(oldFD);
     903                 : 
     904                 :         // check for read (or write) error after cleaning up
     905             504 :         if (bytesRead < 0) 
     906               0 :             return NS_ERROR_OUT_OF_MEMORY;
     907                 :     }
     908             510 :     return rv;
     909                 : }
     910                 : 
     911                 : NS_IMETHODIMP
     912              30 : nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParent, const nsACString &newName)
     913                 : {
     914              30 :     return CopyToNative(newParent, newName);
     915                 : }
     916                 : 
     917                 : NS_IMETHODIMP
     918            2094 : nsLocalFile::MoveToNative(nsIFile *newParent, const nsACString &newName)
     919                 : {
     920                 :     nsresult rv;
     921                 : 
     922                 :     // check to make sure that this has been initialized properly
     923            2094 :     CHECK_mPath();
     924                 : 
     925                 :     // check to make sure that we have a new parent
     926            4188 :     nsCAutoString newPathName;
     927            2094 :     rv = GetNativeTargetPathName(newParent, newName, newPathName);
     928            2094 :     if (NS_FAILED(rv))
     929               0 :         return rv;
     930                 : 
     931                 :     // try for atomic rename, falling back to copy/delete
     932            2094 :     if (rename(mPath.get(), newPathName.get()) < 0) {
     933                 : #ifdef VMS
     934                 :         if (errno == EXDEV || errno == ENXIO) {
     935                 : #else
     936               0 :         if (errno == EXDEV) {
     937                 : #endif
     938               0 :             rv = CopyToNative(newParent, newName);
     939               0 :             if (NS_SUCCEEDED(rv))
     940               0 :                 rv = Remove(true);
     941                 :         } else {
     942               0 :             rv = NSRESULT_FOR_ERRNO();
     943                 :         }
     944                 :     }
     945                 : 
     946            2094 :     if (NS_SUCCEEDED(rv)) {
     947                 :         // Adjust this
     948            2094 :         mPath = newPathName;
     949                 :     }
     950            2094 :     return rv;
     951                 : }
     952                 : 
     953                 : NS_IMETHODIMP
     954            8211 : nsLocalFile::Remove(bool recursive)
     955                 : {
     956            8211 :     CHECK_mPath();
     957            8211 :     ENSURE_STAT_CACHE();
     958                 : 
     959                 :     bool isSymLink;
     960                 : 
     961            6704 :     nsresult rv = IsSymlink(&isSymLink);
     962            6704 :     if (NS_FAILED(rv))
     963               0 :         return rv;
     964                 : 
     965            6704 :     if (isSymLink || !S_ISDIR(mCachedStat.st_mode))
     966            3272 :         return NSRESULT_FOR_RETURN(unlink(mPath.get()));
     967                 : 
     968            3432 :     if (recursive) {
     969            1452 :         nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix();
     970            1452 :         if (!dir)
     971               0 :             return NS_ERROR_OUT_OF_MEMORY;
     972                 : 
     973            2904 :         nsCOMPtr<nsISimpleEnumerator> dirRef(dir); // release on exit
     974                 : 
     975            1452 :         rv = dir->Init(this, false);
     976            1452 :         if (NS_FAILED(rv))
     977               0 :             return rv;
     978                 : 
     979                 :         bool more;
     980            4150 :         while (dir->HasMoreElements(&more), more) {
     981            2492 :             nsCOMPtr<nsISupports> item;
     982            1246 :             rv = dir->GetNext(getter_AddRefs(item));
     983            1246 :             if (NS_FAILED(rv))
     984               0 :                 return NS_ERROR_FAILURE;
     985                 : 
     986            2492 :             nsCOMPtr<nsIFile> file = do_QueryInterface(item, &rv);
     987            1246 :             if (NS_FAILED(rv))
     988               0 :                 return NS_ERROR_FAILURE;
     989            1246 :             rv = file->Remove(recursive);
     990                 : 
     991                 : #ifdef ANDROID
     992                 :             // See bug 580434 - Bionic gives us just deleted files
     993                 :             if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
     994                 :                 continue;
     995                 : #endif
     996            1246 :             if (NS_FAILED(rv))
     997               0 :                 return rv;
     998                 :         }
     999                 :     }
    1000                 : 
    1001            3432 :     return NSRESULT_FOR_RETURN(rmdir(mPath.get()));
    1002                 : }
    1003                 : 
    1004                 : NS_IMETHODIMP
    1005           10585 : nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModTime)
    1006                 : {
    1007           10585 :     CHECK_mPath();
    1008           10585 :     NS_ENSURE_ARG(aLastModTime);
    1009                 : 
    1010                 :     PRFileInfo64 info;
    1011           10585 :     if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS)
    1012               0 :         return NSRESULT_FOR_ERRNO();
    1013           10585 :     PRInt64 modTime = PRInt64(info.modifyTime);
    1014           10585 :     if (modTime == 0)
    1015               0 :         *aLastModTime = 0;
    1016                 :     else
    1017           10585 :         *aLastModTime = modTime / PRInt64(PR_USEC_PER_MSEC);
    1018                 : 
    1019           10585 :     return NS_OK;
    1020                 : }
    1021                 : 
    1022                 : NS_IMETHODIMP
    1023            1348 : nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime)
    1024                 : {
    1025            1348 :     CHECK_mPath();
    1026                 : 
    1027                 :     int result;
    1028            1348 :     if (aLastModTime != 0) {
    1029            1348 :         ENSURE_STAT_CACHE();
    1030                 :         struct utimbuf ut;
    1031            1348 :         ut.actime = mCachedStat.st_atime;
    1032                 : 
    1033                 :         // convert milliseconds to seconds since the unix epoch
    1034            1348 :         ut.modtime = (time_t)(PRFloat64(aLastModTime) / PR_MSEC_PER_SEC);
    1035            1348 :         result = utime(mPath.get(), &ut);
    1036                 :     } else {
    1037               0 :         result = utime(mPath.get(), nsnull);
    1038                 :     }
    1039            1348 :     return NSRESULT_FOR_RETURN(result);
    1040                 : }
    1041                 : 
    1042                 : NS_IMETHODIMP
    1043               0 : nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModTimeOfLink)
    1044                 : {
    1045               0 :     CHECK_mPath();
    1046               0 :     NS_ENSURE_ARG(aLastModTimeOfLink);
    1047                 : 
    1048                 :     struct STAT sbuf;
    1049               0 :     if (LSTAT(mPath.get(), &sbuf) == -1)
    1050               0 :         return NSRESULT_FOR_ERRNO();
    1051               0 :     *aLastModTimeOfLink = PRInt64(sbuf.st_mtime) * PRInt64(PR_MSEC_PER_SEC);
    1052                 : 
    1053               0 :     return NS_OK;
    1054                 : }
    1055                 : 
    1056                 : /*
    1057                 :  * utime(2) may or may not dereference symlinks, joy.
    1058                 :  */
    1059                 : NS_IMETHODIMP
    1060               0 : nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink)
    1061                 : {
    1062               0 :     return SetLastModifiedTime(aLastModTimeOfLink);
    1063                 : }
    1064                 : 
    1065                 : /*
    1066                 :  * Only send back permissions bits: maybe we want to send back the whole
    1067                 :  * mode_t to permit checks against other file types?
    1068                 :  */
    1069                 : 
    1070                 : #define NORMALIZE_PERMS(mode)    ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO))
    1071                 : 
    1072                 : NS_IMETHODIMP
    1073            2561 : nsLocalFile::GetPermissions(PRUint32 *aPermissions)
    1074                 : {
    1075            2561 :     NS_ENSURE_ARG(aPermissions);
    1076            2561 :     ENSURE_STAT_CACHE();
    1077            2561 :     *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode);
    1078            2561 :     return NS_OK;
    1079                 : }
    1080                 : 
    1081                 : NS_IMETHODIMP
    1082               0 : nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
    1083                 : {
    1084               0 :     CHECK_mPath();
    1085               0 :     NS_ENSURE_ARG(aPermissionsOfLink);
    1086                 : 
    1087                 :     struct STAT sbuf;
    1088               0 :     if (LSTAT(mPath.get(), &sbuf) == -1)
    1089               0 :         return NSRESULT_FOR_ERRNO();
    1090               0 :     *aPermissionsOfLink = NORMALIZE_PERMS(sbuf.st_mode);
    1091               0 :     return NS_OK;
    1092                 : }
    1093                 : 
    1094                 : NS_IMETHODIMP
    1095            3196 : nsLocalFile::SetPermissions(PRUint32 aPermissions)
    1096                 : {
    1097            3196 :     CHECK_mPath();
    1098                 : 
    1099                 :     /*
    1100                 :      * Race condition here: we should use fchmod instead, there's no way to 
    1101                 :      * guarantee the name still refers to the same file.
    1102                 :      */
    1103            3196 :     if (chmod(mPath.get(), aPermissions) >= 0)
    1104            3196 :         return NS_OK;
    1105                 : #if defined(ANDROID) && defined(STATFS)
    1106                 :     // For the time being, this is restricted for use by Android, but we 
    1107                 :     // will figure out what to do for all platforms in bug 638503
    1108                 :     struct STATFS sfs;
    1109                 :     if (STATFS(mPath.get(), &sfs) < 0)
    1110                 :          return NSRESULT_FOR_ERRNO();
    1111                 : 
    1112                 :     // if this is a FAT file system we can't set file permissions
    1113                 :     if (sfs.f_type == MSDOS_SUPER_MAGIC )
    1114                 :         return NS_OK;
    1115                 : #endif
    1116               0 :     return NSRESULT_FOR_ERRNO();
    1117                 : }
    1118                 : 
    1119                 : NS_IMETHODIMP
    1120               0 : nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions)
    1121                 : {
    1122                 :     // There isn't a consistent mechanism for doing this on UNIX platforms. We
    1123                 :     // might want to carefully implement this in the future though.
    1124               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1125                 : }
    1126                 : 
    1127                 : NS_IMETHODIMP
    1128           83843 : nsLocalFile::GetFileSize(PRInt64 *aFileSize)
    1129                 : {
    1130           83843 :     NS_ENSURE_ARG_POINTER(aFileSize);
    1131           83843 :     *aFileSize = 0;
    1132           83843 :     ENSURE_STAT_CACHE();
    1133                 : 
    1134                 : #if defined(VMS)
    1135                 :     /* Only two record formats can report correct file content size */
    1136                 :     if ((mCachedStat.st_fab_rfm != FAB$C_STMLF) &&
    1137                 :         (mCachedStat.st_fab_rfm != FAB$C_STMCR)) {
    1138                 :         return NS_ERROR_FAILURE;
    1139                 :     }
    1140                 : #endif
    1141                 : 
    1142           83672 :     if (!S_ISDIR(mCachedStat.st_mode)) {
    1143           83616 :         *aFileSize = (PRInt64)mCachedStat.st_size;
    1144                 :     }
    1145           83672 :     return NS_OK;
    1146                 : }
    1147                 : 
    1148                 : NS_IMETHODIMP
    1149               0 : nsLocalFile::SetFileSize(PRInt64 aFileSize)
    1150                 : {
    1151               0 :     CHECK_mPath();
    1152                 : 
    1153                 : #if defined(ANDROID)
    1154                 :     /* no truncate on bionic */
    1155                 :     int fd = open(mPath.get(), O_WRONLY);
    1156                 :     if (fd == -1)
    1157                 :         return NSRESULT_FOR_ERRNO();
    1158                 : 
    1159                 :     int ret = ftruncate(fd, (off_t)aFileSize);
    1160                 :     close(fd);
    1161                 : 
    1162                 :     if (ret == -1)
    1163                 :         return NSRESULT_FOR_ERRNO();
    1164                 : #elif defined(HAVE_TRUNCATE64)
    1165               0 :     if (truncate64(mPath.get(), (off64_t)aFileSize) == -1)
    1166               0 :         return NSRESULT_FOR_ERRNO();
    1167                 : #else
    1168                 :     off_t size = (off_t)aFileSize;
    1169                 :     if (truncate(mPath.get(), size) == -1)
    1170                 :         return NSRESULT_FOR_ERRNO();
    1171                 : #endif
    1172               0 :     return NS_OK;
    1173                 : }
    1174                 : 
    1175                 : NS_IMETHODIMP
    1176               0 : nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize)
    1177                 : {
    1178               0 :     CHECK_mPath();
    1179               0 :     NS_ENSURE_ARG(aFileSize);
    1180                 : 
    1181                 :     struct STAT sbuf;
    1182               0 :     if (LSTAT(mPath.get(), &sbuf) == -1)
    1183               0 :         return NSRESULT_FOR_ERRNO();
    1184                 : 
    1185               0 :     *aFileSize = (PRInt64)sbuf.st_size;
    1186               0 :     return NS_OK;
    1187                 : }
    1188                 : 
    1189                 : #if defined(USE_LINUX_QUOTACTL)
    1190                 : /*
    1191                 :  * Searches /proc/self/mountinfo for given device (Major:Minor), 
    1192                 :  * returns exported name from /dev
    1193                 :  *
    1194                 :  * Fails when /proc/self/mountinfo or diven device don't exist.
    1195                 :  */
    1196                 : static bool
    1197                 : GetDeviceName(int deviceMajor, int deviceMinor, nsACString &deviceName)
    1198                 : {
    1199                 :     bool ret = false;
    1200                 :     
    1201                 :     const int kMountInfoLineLength = 200;
    1202                 :     const int kMountInfoDevPosition = 6;
    1203                 : 
    1204                 :     char mountinfo_line[kMountInfoLineLength];
    1205                 :     char device_num[kMountInfoLineLength];
    1206                 :     
    1207                 :     snprintf(device_num,kMountInfoLineLength,"%d:%d", deviceMajor, deviceMinor);
    1208                 :     
    1209                 :     FILE *f = fopen("/proc/self/mountinfo","rt");
    1210                 :     if(!f)
    1211                 :         return ret;
    1212                 : 
    1213                 :     // Expects /proc/self/mountinfo in format:
    1214                 :     // 'ID ID major:minor root mountpoint flags - type devicename flags'
    1215                 :     while(fgets(mountinfo_line,kMountInfoLineLength,f)) {
    1216                 :         char *p_dev = strstr(mountinfo_line,device_num);
    1217                 :     
    1218                 :         int i;
    1219                 :         for(i = 0; i < kMountInfoDevPosition && p_dev != NULL; i++) {
    1220                 :             p_dev = strchr(p_dev,' ');
    1221                 :             if(p_dev)
    1222                 :               p_dev++;
    1223                 :         }
    1224                 :     
    1225                 :         if(p_dev) {
    1226                 :             char *p_dev_end = strchr(p_dev,' ');
    1227                 :             if(p_dev_end) {
    1228                 :                 *p_dev_end = '\0';
    1229                 :                 deviceName.Assign(p_dev);
    1230                 :                 ret = true;
    1231                 :                 break;
    1232                 :             }
    1233                 :         }
    1234                 :     }
    1235                 :     
    1236                 :     fclose(f);
    1237                 :     return ret; 
    1238                 : }
    1239                 : #endif
    1240                 : 
    1241                 : NS_IMETHODIMP
    1242             840 : nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
    1243                 : {
    1244             840 :     NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
    1245                 : 
    1246                 :     // These systems have the operations necessary to check disk space.
    1247                 : 
    1248                 : #ifdef STATFS
    1249                 : 
    1250                 :     // check to make sure that mPath is properly initialized
    1251             840 :     CHECK_mPath();
    1252                 : 
    1253                 :     struct STATFS fs_buf;
    1254                 : 
    1255                 :     /* 
    1256                 :      * Members of the STATFS struct that you should know about:
    1257                 :      * f_bsize = block size on disk.
    1258                 :      * f_bavail = number of free blocks available to a non-superuser.
    1259                 :      * f_bfree = number of total free blocks in file system.
    1260                 :      */
    1261                 : 
    1262             840 :     if (STATFS(mPath.get(), &fs_buf) < 0) {
    1263                 :         // The call to STATFS failed.
    1264                 : #ifdef DEBUG
    1265               0 :         printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n");
    1266                 : #endif
    1267               0 :         return NS_ERROR_FAILURE;
    1268                 :     }
    1269                 : #ifdef DEBUG_DISK_SPACE
    1270                 :     printf("DiskSpaceAvailable: %d bytes\n",
    1271                 :          fs_buf.f_bsize * (fs_buf.f_bavail - 1));
    1272                 : #endif
    1273                 : 
    1274                 :     /* 
    1275                 :      * The number of bytes free == The number of free blocks available to
    1276                 :      * a non-superuser, minus one as a fudge factor, multiplied by the size
    1277                 :      * of the aforementioned blocks.
    1278                 :      */
    1279                 : #if defined(SOLARIS) || defined(XP_MACOSX)
    1280                 :     /* On Solaris and Mac, unit is f_frsize. */
    1281                 :     *aDiskSpaceAvailable = (PRInt64)fs_buf.f_frsize * (fs_buf.f_bavail - 1);
    1282                 : #else
    1283             840 :     *aDiskSpaceAvailable = (PRInt64)fs_buf.f_bsize * (fs_buf.f_bavail - 1);
    1284                 : #endif /* SOLARIS */
    1285                 : 
    1286                 : #if defined(USE_LINUX_QUOTACTL)
    1287                 : 
    1288                 :     if(!FillStatCache()) {
    1289                 :         // Return available size from statfs
    1290                 :         return NS_OK;
    1291                 :     }
    1292                 : 
    1293                 :     nsCString deviceName;
    1294                 :     if(!GetDeviceName(major(mCachedStat.st_dev), minor(mCachedStat.st_dev), deviceName)) {
    1295                 :         return NS_OK;
    1296                 :     }
    1297                 : 
    1298                 :     struct dqblk dq;
    1299                 :     if(!quotactl(QCMD(Q_GETQUOTA, USRQUOTA), deviceName.get(), getuid(), (caddr_t)&dq)) {
    1300                 :         PRInt64 QuotaSpaceAvailable = PRInt64(fs_buf.f_bsize * dq.dqb_bhardlimit);
    1301                 :         if(QuotaSpaceAvailable < *aDiskSpaceAvailable) {
    1302                 :             *aDiskSpaceAvailable = QuotaSpaceAvailable;
    1303                 :         }
    1304                 :     }
    1305                 : #endif
    1306                 : 
    1307             840 :     return NS_OK;
    1308                 : 
    1309                 : #else
    1310                 :     /*
    1311                 :      * This platform doesn't have statfs or statvfs.  I'm sure that there's
    1312                 :      * a way to check for free disk space on platforms that don't have statfs
    1313                 :      * (I'm SURE they have df, for example).
    1314                 :      *
    1315                 :      * Until we figure out how to do that, lets be honest and say that this
    1316                 :      * command isn't implemented properly for these platforms yet.
    1317                 :      */
    1318                 : #ifdef DEBUG
    1319                 :     printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n");
    1320                 : #endif
    1321                 :     return NS_ERROR_NOT_IMPLEMENTED;
    1322                 : 
    1323                 : #endif /* STATFS */
    1324                 : 
    1325                 : }
    1326                 : 
    1327                 : NS_IMETHODIMP
    1328          459870 : nsLocalFile::GetParent(nsIFile **aParent)
    1329                 : {
    1330          459870 :     CHECK_mPath();
    1331          459870 :     NS_ENSURE_ARG_POINTER(aParent);
    1332          459870 :     *aParent = nsnull;
    1333                 : 
    1334                 :     // if '/' we are at the top of the volume, return null
    1335          459870 :     if (mPath.Equals("/"))
    1336               1 :         return  NS_OK;
    1337                 :  
    1338                 :     // <brendan, after jband> I promise to play nice
    1339          459869 :     char *buffer   = mPath.BeginWriting(),
    1340          459869 :          *slashp   = buffer;
    1341                 : 
    1342                 :     // find the last significant slash in buffer
    1343          459869 :     slashp = strrchr(buffer, '/');
    1344          459869 :     NS_ASSERTION(slashp, "non-canonical path?");
    1345          459869 :     if (!slashp)
    1346               0 :         return NS_ERROR_FILE_INVALID_PATH;
    1347                 : 
    1348                 :     // for the case where we are at '/'
    1349          459869 :     if (slashp == buffer)
    1350               1 :         slashp++;
    1351                 : 
    1352                 :     // temporarily terminate buffer at the last significant slash
    1353          459869 :     char c = *slashp;
    1354          459869 :     *slashp = '\0';
    1355                 : 
    1356          919738 :     nsCOMPtr<nsILocalFile> localFile;
    1357          459869 :     nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buffer), true,
    1358          919738 :                                         getter_AddRefs(localFile));
    1359                 : 
    1360                 :     // make buffer whole again
    1361          459869 :     *slashp = c;
    1362                 : 
    1363          459869 :     if (NS_SUCCEEDED(rv) && localFile)
    1364          459869 :         rv = CallQueryInterface(localFile, aParent);
    1365          459869 :     return rv;
    1366                 : }
    1367                 : 
    1368                 : /*
    1369                 :  * The results of Exists, isWritable and isReadable are not cached.
    1370                 :  */
    1371                 : 
    1372                 : 
    1373                 : NS_IMETHODIMP
    1374           47794 : nsLocalFile::Exists(bool *_retval)
    1375                 : {
    1376           47794 :     CHECK_mPath();
    1377           47794 :     NS_ENSURE_ARG_POINTER(_retval);
    1378                 : 
    1379           47794 :     *_retval = (access(mPath.get(), F_OK) == 0);
    1380           47794 :     return NS_OK;
    1381                 : }
    1382                 : 
    1383                 : 
    1384                 : NS_IMETHODIMP
    1385              74 : nsLocalFile::IsWritable(bool *_retval)
    1386                 : {
    1387              74 :     CHECK_mPath();
    1388              74 :     NS_ENSURE_ARG_POINTER(_retval);
    1389                 : 
    1390              74 :     *_retval = (access(mPath.get(), W_OK) == 0);
    1391              74 :     if (*_retval || errno == EACCES)
    1392              74 :         return NS_OK;
    1393               0 :     return NSRESULT_FOR_ERRNO();
    1394                 : }
    1395                 : 
    1396                 : NS_IMETHODIMP
    1397               6 : nsLocalFile::IsReadable(bool *_retval)
    1398                 : {
    1399               6 :     CHECK_mPath();
    1400               6 :     NS_ENSURE_ARG_POINTER(_retval);
    1401                 : 
    1402               6 :     *_retval = (access(mPath.get(), R_OK) == 0);
    1403               6 :     if (*_retval || errno == EACCES)
    1404               6 :         return NS_OK;
    1405               0 :     return NSRESULT_FOR_ERRNO();
    1406                 : }
    1407                 : 
    1408                 : NS_IMETHODIMP
    1409               6 : nsLocalFile::IsExecutable(bool *_retval)
    1410                 : {
    1411               6 :     CHECK_mPath();
    1412               6 :     NS_ENSURE_ARG_POINTER(_retval);
    1413                 : 
    1414                 :     // Check extension (bug 663899). On certain platforms, the file
    1415                 :     // extension may cause the OS to treat it as executable regardless of
    1416                 :     // the execute bit, such as .jar on Mac OS X. We borrow the code from
    1417                 :     // nsLocalFileWin, slightly modified.
    1418                 : 
    1419                 :     // Don't be fooled by symlinks.
    1420                 :     bool symLink;
    1421               6 :     nsresult rv = IsSymlink(&symLink);
    1422               6 :     if (NS_FAILED(rv))
    1423               0 :         return rv;
    1424                 : 
    1425              12 :     nsAutoString path;
    1426               6 :     if (symLink)
    1427               0 :         GetTarget(path);
    1428                 :     else
    1429               6 :         GetPath(path);
    1430                 : 
    1431               6 :     PRInt32 dotIdx = path.RFindChar(PRUnichar('.'));
    1432               6 :     if (dotIdx != kNotFound) {
    1433                 :         // Convert extension to lower case.
    1434               6 :         PRUnichar *p = path.BeginWriting();
    1435              24 :         for(p += dotIdx + 1; *p; p++)
    1436              18 :             *p +=  (*p >= L'A' && *p <= L'Z') ? 'a' - 'A' : 0; 
    1437                 :         
    1438                 :         // Search for any of the set of executable extensions.
    1439                 :         static const char * const executableExts[] = {
    1440                 :             "air",         // Adobe AIR installer
    1441                 :             "jar"};        // java application bundle
    1442              12 :         nsDependentSubstring ext = Substring(path, dotIdx + 1);
    1443              18 :         for (size_t i = 0; i < ArrayLength(executableExts); i++) {
    1444              12 :             if (ext.EqualsASCII(executableExts[i])) {
    1445                 :                 // Found a match.  Set result and quit.
    1446               0 :                 *_retval = true;
    1447               0 :                 return NS_OK;
    1448                 :             }
    1449                 :         }
    1450                 :     }
    1451                 : 
    1452                 :     // On OS X, then query Launch Services.
    1453                 : #ifdef MOZ_WIDGET_COCOA
    1454                 :     // Certain Mac applications, such as Classic applications, which
    1455                 :     // run under Rosetta, might not have the +x mode bit but are still
    1456                 :     // considered to be executable by Launch Services (bug 646748).
    1457                 :     CFURLRef url;
    1458                 :     if (NS_FAILED(GetCFURL(&url))) {
    1459                 :         return NS_ERROR_FAILURE;
    1460                 :     }
    1461                 : 
    1462                 :     LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
    1463                 :     LSItemInfoRecord theInfo;
    1464                 :     OSStatus result = ::LSCopyItemInfoForURL(url, theInfoRequest, &theInfo);
    1465                 :     ::CFRelease(url);
    1466                 :     if (result == noErr) {
    1467                 :         if ((theInfo.flags & kLSItemInfoIsApplication) != 0) {
    1468                 :             *_retval = true;
    1469                 :             return NS_OK;
    1470                 :         }
    1471                 :     }
    1472                 : #endif
    1473                 : 
    1474                 :     // Then check the execute bit.
    1475               6 :     *_retval = (access(mPath.get(), X_OK) == 0);
    1476                 : #ifdef SOLARIS
    1477                 :     // On Solaris, access will always return 0 for root user, however
    1478                 :     // the file is only executable if S_IXUSR | S_IXGRP | S_IXOTH is set.
    1479                 :     // See bug 351950, https://bugzilla.mozilla.org/show_bug.cgi?id=351950
    1480                 :     if (*_retval) {
    1481                 :         struct STAT buf;
    1482                 : 
    1483                 :         *_retval = (STAT(mPath.get(), &buf) == 0);
    1484                 :         if (*_retval || errno == EACCES) {
    1485                 :             *_retval = *_retval &&
    1486                 :                        (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH ));
    1487                 :             return NS_OK;
    1488                 :         }
    1489                 : 
    1490                 :         return NSRESULT_FOR_ERRNO();
    1491                 :     }
    1492                 : #endif
    1493               6 :     if (*_retval || errno == EACCES)
    1494               6 :         return NS_OK;
    1495               0 :     return NSRESULT_FOR_ERRNO();
    1496                 : }
    1497                 : 
    1498                 : NS_IMETHODIMP
    1499           28199 : nsLocalFile::IsDirectory(bool *_retval)
    1500                 : {
    1501           28199 :     NS_ENSURE_ARG_POINTER(_retval);
    1502           28199 :     *_retval = false;
    1503           28199 :     ENSURE_STAT_CACHE();
    1504           27035 :     *_retval = S_ISDIR(mCachedStat.st_mode);
    1505           27035 :     return NS_OK;
    1506                 : }
    1507                 : 
    1508                 : NS_IMETHODIMP
    1509           20806 : nsLocalFile::IsFile(bool *_retval)
    1510                 : {
    1511           20806 :     NS_ENSURE_ARG_POINTER(_retval);
    1512           20806 :     *_retval = false;
    1513           20806 :     ENSURE_STAT_CACHE();
    1514           17968 :     *_retval = S_ISREG(mCachedStat.st_mode);
    1515           17968 :     return NS_OK;
    1516                 : }
    1517                 : 
    1518                 : NS_IMETHODIMP
    1519              73 : nsLocalFile::IsHidden(bool *_retval)
    1520                 : {
    1521              73 :     NS_ENSURE_ARG_POINTER(_retval);
    1522              73 :     nsACString::const_iterator begin, end;
    1523              73 :     LocateNativeLeafName(begin, end);
    1524              73 :     *_retval = (*begin == '.');
    1525              73 :     return NS_OK;
    1526                 : }
    1527                 : 
    1528                 : NS_IMETHODIMP
    1529           59476 : nsLocalFile::IsSymlink(bool *_retval)
    1530                 : {
    1531           59476 :     NS_ENSURE_ARG_POINTER(_retval);
    1532           59476 :     CHECK_mPath();
    1533                 : 
    1534                 :     struct STAT symStat;
    1535           59476 :     if (LSTAT(mPath.get(), &symStat) == -1)
    1536              54 :         return NSRESULT_FOR_ERRNO();
    1537           59422 :     *_retval=S_ISLNK(symStat.st_mode);
    1538           59422 :     return NS_OK;
    1539                 : }
    1540                 : 
    1541                 : NS_IMETHODIMP
    1542             504 : nsLocalFile::IsSpecial(bool *_retval)
    1543                 : {
    1544             504 :     NS_ENSURE_ARG_POINTER(_retval);
    1545             504 :     ENSURE_STAT_CACHE();
    1546                 :     *_retval = S_ISCHR(mCachedStat.st_mode)      ||
    1547                 :                  S_ISBLK(mCachedStat.st_mode)    ||
    1548                 : #ifdef S_ISSOCK
    1549                 :                  S_ISSOCK(mCachedStat.st_mode)   ||
    1550                 : #endif
    1551             504 :                  S_ISFIFO(mCachedStat.st_mode);
    1552                 : 
    1553             504 :     return NS_OK;
    1554                 : }
    1555                 : 
    1556                 : NS_IMETHODIMP
    1557            5476 : nsLocalFile::Equals(nsIFile *inFile, bool *_retval)
    1558                 : {
    1559            5476 :     NS_ENSURE_ARG(inFile);
    1560            5476 :     NS_ENSURE_ARG_POINTER(_retval);
    1561            5476 :     *_retval = false;
    1562                 : 
    1563           10952 :     nsCAutoString inPath;
    1564            5476 :     nsresult rv = inFile->GetNativePath(inPath);
    1565            5476 :     if (NS_FAILED(rv))
    1566               0 :         return rv;
    1567                 : 
    1568                 :     // We don't need to worry about "/foo/" vs. "/foo" here
    1569                 :     // because trailing slashes are stripped on init.
    1570            5476 :     *_retval = !strcmp(inPath.get(), mPath.get());
    1571            5476 :     return NS_OK;
    1572                 : }
    1573                 : 
    1574                 : NS_IMETHODIMP
    1575               0 : nsLocalFile::Contains(nsIFile *inFile, bool recur, bool *_retval)
    1576                 : {
    1577               0 :     CHECK_mPath();
    1578               0 :     NS_ENSURE_ARG(inFile);
    1579               0 :     NS_ENSURE_ARG_POINTER(_retval);
    1580                 : 
    1581               0 :     nsCAutoString inPath;
    1582                 :     nsresult rv;
    1583                 : 
    1584               0 :     if (NS_FAILED(rv = inFile->GetNativePath(inPath)))
    1585               0 :         return rv;
    1586                 : 
    1587               0 :     *_retval = false;
    1588                 : 
    1589               0 :     ssize_t len = mPath.Length();
    1590               0 :     if (strncmp(mPath.get(), inPath.get(), len) == 0) {
    1591                 :         // Now make sure that the |inFile|'s path has a separator at len,
    1592                 :         // which implies that it has more components after len.
    1593               0 :         if (inPath[len] == '/')
    1594               0 :             *_retval = true;
    1595                 :     }
    1596                 : 
    1597               0 :     return NS_OK;
    1598                 : }
    1599                 : 
    1600                 : NS_IMETHODIMP
    1601             332 : nsLocalFile::GetNativeTarget(nsACString &_retval)
    1602                 : {
    1603             332 :     CHECK_mPath();
    1604             332 :     _retval.Truncate();
    1605                 : 
    1606                 :     struct STAT symStat;
    1607             332 :     if (LSTAT(mPath.get(), &symStat) == -1)
    1608               0 :         return NSRESULT_FOR_ERRNO();
    1609                 : 
    1610             332 :     if (!S_ISLNK(symStat.st_mode))
    1611               0 :         return NS_ERROR_FILE_INVALID_PATH;
    1612                 : 
    1613             332 :     PRInt32 size = (PRInt32)symStat.st_size;
    1614             332 :     char *target = (char *)nsMemory::Alloc(size + 1);
    1615             332 :     if (!target)
    1616               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1617                 : 
    1618             332 :     if (readlink(mPath.get(), target, (size_t)size) < 0) {
    1619               0 :         nsMemory::Free(target);
    1620               0 :         return NSRESULT_FOR_ERRNO();
    1621                 :     }
    1622             332 :     target[size] = '\0';
    1623                 : 
    1624             332 :     nsresult rv = NS_OK;
    1625             664 :     nsCOMPtr<nsIFile> self(this);
    1626             332 :     PRInt32 maxLinks = 40;
    1627              88 :     while (true) {
    1628             420 :         if (maxLinks-- == 0) {
    1629               2 :             rv = NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
    1630               2 :             break;
    1631                 :         }
    1632                 : 
    1633             418 :         if (target[0] != '/') {
    1634             112 :             nsCOMPtr<nsIFile> parent;
    1635              56 :             if (NS_FAILED(rv = self->GetParent(getter_AddRefs(parent))))
    1636                 :                 break;
    1637             112 :             nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(parent, &rv));
    1638              56 :             if (NS_FAILED(rv))
    1639                 :                 break;
    1640              56 :             if (NS_FAILED(rv = localFile->AppendRelativeNativePath(nsDependentCString(target))))
    1641                 :                 break;
    1642              56 :             if (NS_FAILED(rv = localFile->GetNativePath(_retval)))
    1643                 :                 break;
    1644             112 :             self = parent;
    1645                 :         } else {
    1646             362 :             _retval = target;
    1647                 :         }
    1648                 : 
    1649             836 :         const nsPromiseFlatCString &flatRetval = PromiseFlatCString(_retval);
    1650                 : 
    1651                 :         // Any failure in testing the current target we'll just interpret
    1652                 :         // as having reached our destiny.
    1653             418 :         if (LSTAT(flatRetval.get(), &symStat) == -1)
    1654                 :             break;
    1655                 : 
    1656                 :         // And of course we're done if it isn't a symlink.
    1657             414 :         if (!S_ISLNK(symStat.st_mode))
    1658                 :             break;
    1659                 : 
    1660              88 :         PRInt32 newSize = (PRInt32)symStat.st_size;
    1661              88 :         if (newSize > size) {
    1662               8 :             char *newTarget = (char *)nsMemory::Realloc(target, newSize + 1);
    1663               8 :             if (!newTarget) {
    1664               0 :                 rv = NS_ERROR_OUT_OF_MEMORY;
    1665                 :                 break;
    1666                 :             }
    1667               8 :             target = newTarget;
    1668               8 :             size = newSize;
    1669                 :         }
    1670                 : 
    1671              88 :         PRInt32 linkLen = readlink(flatRetval.get(), target, size);
    1672              88 :         if (linkLen == -1) {
    1673               0 :             rv = NSRESULT_FOR_ERRNO();
    1674                 :             break;
    1675                 :         }
    1676             506 :         target[linkLen] = '\0';
    1677                 :     }
    1678                 : 
    1679             332 :     nsMemory::Free(target);
    1680                 : 
    1681             332 :     if (NS_FAILED(rv))
    1682               2 :         _retval.Truncate();
    1683             332 :     return rv;
    1684                 : }
    1685                 : 
    1686                 : NS_IMETHODIMP
    1687               0 : nsLocalFile::GetFollowLinks(bool *aFollowLinks)
    1688                 : {
    1689               0 :     *aFollowLinks = true;
    1690               0 :     return NS_OK;
    1691                 : }
    1692                 : 
    1693                 : NS_IMETHODIMP
    1694          533185 : nsLocalFile::SetFollowLinks(bool aFollowLinks)
    1695                 : {
    1696          533185 :     return NS_OK;
    1697                 : }
    1698                 : 
    1699                 : NS_IMETHODIMP
    1700           11020 : nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries)
    1701                 : {
    1702           11020 :     nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix();
    1703           11020 :     if (!dir)
    1704               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1705                 : 
    1706           11020 :     NS_ADDREF(dir);
    1707           11020 :     nsresult rv = dir->Init(this, false);
    1708           11020 :     if (NS_FAILED(rv)) {
    1709            1412 :         *entries = nsnull;
    1710            1412 :         NS_RELEASE(dir);
    1711                 :     } else {
    1712            9608 :         *entries = dir; // transfer reference
    1713                 :     }
    1714                 : 
    1715           11020 :     return rv;
    1716                 : }
    1717                 : 
    1718                 : NS_IMETHODIMP
    1719            5680 : nsLocalFile::Load(PRLibrary **_retval)
    1720                 : {
    1721            5680 :     CHECK_mPath();
    1722            5680 :     NS_ENSURE_ARG_POINTER(_retval);
    1723                 : 
    1724                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1725            5680 :     nsTraceRefcntImpl::SetActivityIsLegal(false);
    1726                 : #endif
    1727                 : 
    1728            5680 :     *_retval = PR_LoadLibrary(mPath.get());
    1729                 : 
    1730                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1731            5680 :     nsTraceRefcntImpl::SetActivityIsLegal(true);
    1732                 : #endif
    1733                 : 
    1734            5680 :     if (!*_retval)
    1735               0 :         return NS_ERROR_FAILURE;
    1736            5680 :     return NS_OK;
    1737                 : }
    1738                 : 
    1739                 : NS_IMETHODIMP
    1740            4939 : nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor)
    1741                 : {
    1742            4939 :     return GetNativePath(aPersistentDescriptor);
    1743                 : }
    1744                 : 
    1745                 : NS_IMETHODIMP
    1746            3131 : nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor)
    1747                 : {
    1748                 : #ifdef MOZ_WIDGET_COCOA
    1749                 :     if (aPersistentDescriptor.IsEmpty())
    1750                 :         return NS_ERROR_INVALID_ARG;
    1751                 : 
    1752                 :     // Support pathnames as user-supplied descriptors if they begin with '/'
    1753                 :     // or '~'.  These characters do not collide with the base64 set used for
    1754                 :     // encoding alias records.
    1755                 :     char first = aPersistentDescriptor.First();
    1756                 :     if (first == '/' || first == '~')
    1757                 :         return InitWithNativePath(aPersistentDescriptor);
    1758                 : 
    1759                 :     PRUint32 dataSize = aPersistentDescriptor.Length();    
    1760                 :     char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
    1761                 :     if (!decodedData) {
    1762                 :         NS_ERROR("SetPersistentDescriptor was given bad data");
    1763                 :         return NS_ERROR_FAILURE;
    1764                 :     }
    1765                 : 
    1766                 :     // Cast to an alias record and resolve.
    1767                 :     AliasRecord aliasHeader = *(AliasPtr)decodedData;
    1768                 :     PRInt32 aliasSize = ::GetAliasSizeFromPtr(&aliasHeader);
    1769                 :     if (aliasSize > ((PRInt32)dataSize * 3) / 4) { // be paranoid about having too few data
    1770                 :         PR_Free(decodedData);
    1771                 :         return NS_ERROR_FAILURE;
    1772                 :     }
    1773                 : 
    1774                 :     nsresult rv = NS_OK;
    1775                 : 
    1776                 :     // Move the now-decoded data into the Handle.
    1777                 :     // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
    1778                 :     Handle  newHandle = nsnull;
    1779                 :     if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
    1780                 :         rv = NS_ERROR_OUT_OF_MEMORY;
    1781                 :     PR_Free(decodedData);
    1782                 :     if (NS_FAILED(rv))
    1783                 :         return rv;
    1784                 : 
    1785                 :     Boolean changed;
    1786                 :     FSRef resolvedFSRef;
    1787                 :     OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
    1788                 : 
    1789                 :     rv = MacErrorMapper(err);
    1790                 :     DisposeHandle(newHandle);
    1791                 :     if (NS_FAILED(rv))
    1792                 :         return rv;
    1793                 : 
    1794                 :     return InitWithFSRef(&resolvedFSRef);  
    1795                 : #else
    1796            3131 :     return InitWithNativePath(aPersistentDescriptor);
    1797                 : #endif
    1798                 : }
    1799                 : 
    1800                 : NS_IMETHODIMP
    1801               0 : nsLocalFile::Reveal()
    1802                 : {
    1803                 : #ifdef MOZ_WIDGET_GTK2
    1804               0 :     nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
    1805               0 :     nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
    1806               0 :     if (!giovfs && !gnomevfs)
    1807               0 :         return NS_ERROR_FAILURE;
    1808                 : 
    1809                 :     bool isDirectory;
    1810               0 :     if (NS_FAILED(IsDirectory(&isDirectory)))
    1811               0 :         return NS_ERROR_FAILURE;
    1812                 : 
    1813               0 :     if (isDirectory) {
    1814               0 :         if (giovfs)
    1815               0 :             return giovfs->ShowURIForInput(mPath);
    1816                 :         else 
    1817                 :             /* Fallback to GnomeVFS */
    1818               0 :             return gnomevfs->ShowURIForInput(mPath);
    1819                 :     } else {
    1820               0 :         nsCOMPtr<nsIFile> parentDir;
    1821               0 :         nsCAutoString dirPath;
    1822               0 :         if (NS_FAILED(GetParent(getter_AddRefs(parentDir))))
    1823               0 :             return NS_ERROR_FAILURE;
    1824               0 :         if (NS_FAILED(parentDir->GetNativePath(dirPath)))
    1825               0 :             return NS_ERROR_FAILURE;
    1826                 : 
    1827               0 :         if (giovfs)
    1828               0 :             return giovfs->ShowURIForInput(dirPath);
    1829                 :         else 
    1830               0 :             return gnomevfs->ShowURIForInput(dirPath);        
    1831                 :     }
    1832                 : #elif defined(MOZ_WIDGET_COCOA)
    1833                 :     CFURLRef url;
    1834                 :     if (NS_SUCCEEDED(GetCFURL(&url))) {
    1835                 :       nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
    1836                 :       ::CFRelease(url);
    1837                 :       return rv;
    1838                 :     }
    1839                 :     return NS_ERROR_FAILURE;
    1840                 : #else
    1841                 :     return NS_ERROR_FAILURE;
    1842                 : #endif
    1843                 : }
    1844                 : 
    1845                 : NS_IMETHODIMP
    1846               0 : nsLocalFile::Launch()
    1847                 : {
    1848                 : #ifdef MOZ_WIDGET_GTK2
    1849                 : #if (MOZ_PLATFORM_MAEMO==5)
    1850                 :     const PRInt32 kHILDON_SUCCESS = 1;
    1851                 :     DBusError err;
    1852                 :     dbus_error_init(&err);
    1853                 : 
    1854                 :     DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
    1855                 :     if (dbus_error_is_set(&err)) {
    1856                 :       dbus_error_free(&err);
    1857                 :       return NS_ERROR_FAILURE;
    1858                 :     }
    1859                 : 
    1860                 :     if (nsnull == connection)
    1861                 :       return NS_ERROR_FAILURE;
    1862                 : 
    1863                 :     if (hildon_mime_open_file(connection, mPath.get()) != kHILDON_SUCCESS)
    1864                 :       return NS_ERROR_FAILURE;
    1865                 :     return NS_OK;
    1866                 : #else
    1867               0 :     nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
    1868               0 :     nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
    1869               0 :     if (giovfs) {
    1870               0 :       return giovfs->ShowURIForInput(mPath);
    1871               0 :     } else if (gnomevfs) {
    1872                 :       /* GnomeVFS fallback */
    1873               0 :       return gnomevfs->ShowURIForInput(mPath);
    1874                 :     }
    1875                 :     
    1876               0 :     return NS_ERROR_FAILURE;
    1877                 : #endif
    1878                 : #elif defined(MOZ_ENABLE_CONTENTACTION)
    1879                 :     QUrl uri = QUrl::fromLocalFile(QString::fromUtf8(mPath.get()));
    1880                 :     ContentAction::Action action =
    1881                 :       ContentAction::Action::defaultActionForFile(uri);
    1882                 : 
    1883                 :     if (action.isValid()) {
    1884                 :       action.trigger();
    1885                 :       return NS_OK;
    1886                 :     }
    1887                 : 
    1888                 :     return NS_ERROR_FAILURE;
    1889                 : #elif defined(MOZ_WIDGET_ANDROID)
    1890                 :     // Try to get a mimetype, if this fails just use the file uri alone
    1891                 :     nsresult rv;
    1892                 :     nsCAutoString type;
    1893                 :     nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
    1894                 :     if (NS_SUCCEEDED(rv))
    1895                 :         rv = mimeService->GetTypeFromFile(this, type);
    1896                 : 
    1897                 :     nsDependentCString fileUri = NS_LITERAL_CSTRING("file://");
    1898                 :     fileUri.Append(mPath);
    1899                 :     mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
    1900                 :     return bridge->OpenUriExternal(fileUri, type) ? NS_OK : NS_ERROR_FAILURE;
    1901                 : #elif defined(MOZ_WIDGET_COCOA)
    1902                 :     CFURLRef url;
    1903                 :     if (NS_SUCCEEDED(GetCFURL(&url))) {
    1904                 :         nsresult rv = CocoaFileUtils::OpenURL(url);
    1905                 :         ::CFRelease(url);
    1906                 :         return rv;
    1907                 :     }
    1908                 :     return NS_ERROR_FAILURE;
    1909                 : #else
    1910                 :     return NS_ERROR_FAILURE;
    1911                 : #endif
    1912                 : }
    1913                 : 
    1914                 : nsresult
    1915          529439 : NS_NewNativeLocalFile(const nsACString &path, bool followSymlinks, nsILocalFile **result)
    1916                 : {
    1917          529439 :     nsLocalFile *file = new nsLocalFile();
    1918          529439 :     if (!file)
    1919               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1920          529439 :     NS_ADDREF(file);
    1921                 : 
    1922          529439 :     file->SetFollowLinks(followSymlinks);
    1923                 : 
    1924          529439 :     if (!path.IsEmpty()) {
    1925          467630 :         nsresult rv = file->InitWithNativePath(path);
    1926          467630 :         if (NS_FAILED(rv)) {
    1927               2 :             NS_RELEASE(file);
    1928               2 :             return rv;
    1929                 :         }
    1930                 :     }
    1931          529437 :     *result = file;
    1932          529437 :     return NS_OK;
    1933                 : }
    1934                 : 
    1935                 : //-----------------------------------------------------------------------------
    1936                 : // unicode support
    1937                 : //-----------------------------------------------------------------------------
    1938                 : 
    1939                 : #define SET_UCS(func, ucsArg) \
    1940                 :     { \
    1941                 :         nsCAutoString buf; \
    1942                 :         nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
    1943                 :         if (NS_FAILED(rv)) \
    1944                 :             return rv; \
    1945                 :         return (func)(buf); \
    1946                 :     }
    1947                 : 
    1948                 : #define GET_UCS(func, ucsArg) \
    1949                 :     { \
    1950                 :         nsCAutoString buf; \
    1951                 :         nsresult rv = (func)(buf); \
    1952                 :         if (NS_FAILED(rv)) return rv; \
    1953                 :         return NS_CopyNativeToUnicode(buf, ucsArg); \
    1954                 :     }
    1955                 : 
    1956                 : #define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \
    1957                 :     { \
    1958                 :         nsCAutoString buf; \
    1959                 :         nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \
    1960                 :         if (NS_FAILED(rv)) \
    1961                 :             return rv; \
    1962                 :         return (func)(opaqueArg, buf); \
    1963                 :     }
    1964                 : 
    1965                 : // Unicode interface Wrapper
    1966                 : nsresult  
    1967            3829 : nsLocalFile::InitWithPath(const nsAString &filePath)
    1968                 : {
    1969            3829 :     SET_UCS(InitWithNativePath, filePath);
    1970                 : }
    1971                 : nsresult  
    1972           37189 : nsLocalFile::Append(const nsAString &node)
    1973                 : {
    1974           37189 :     SET_UCS(AppendNative, node);
    1975                 : }
    1976                 : nsresult  
    1977            2631 : nsLocalFile::AppendRelativePath(const nsAString &node)
    1978                 : {
    1979            2631 :     SET_UCS(AppendRelativeNativePath, node);
    1980                 : }
    1981                 : nsresult  
    1982           12091 : nsLocalFile::GetLeafName(nsAString &aLeafName)
    1983                 : {
    1984           12091 :     GET_UCS(GetNativeLeafName, aLeafName);
    1985                 : }
    1986                 : nsresult  
    1987            1135 : nsLocalFile::SetLeafName(const nsAString &aLeafName)
    1988                 : {
    1989            1135 :     SET_UCS(SetNativeLeafName, aLeafName);
    1990                 : }
    1991                 : nsresult  
    1992           22723 : nsLocalFile::GetPath(nsAString &_retval)
    1993                 : {
    1994           22723 :     return NS_CopyNativeToUnicode(mPath, _retval);
    1995                 : }
    1996                 : nsresult  
    1997             466 : nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName)
    1998                 : {
    1999             466 :     SET_UCS_2ARGS_2(CopyToNative , newParentDir, newName);
    2000                 : }
    2001                 : nsresult  
    2002              30 : nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName)
    2003                 : {
    2004              30 :     SET_UCS_2ARGS_2(CopyToFollowingLinksNative , newParentDir, newName);
    2005                 : }
    2006                 : nsresult  
    2007            1855 : nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName)
    2008                 : {
    2009            1855 :     SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName);
    2010                 : }
    2011                 : nsresult
    2012              26 : nsLocalFile::GetTarget(nsAString &_retval)
    2013                 : {   
    2014              26 :     GET_UCS(GetNativeTarget, _retval);
    2015                 : }
    2016                 : 
    2017                 : // nsIHashable
    2018                 : 
    2019                 : NS_IMETHODIMP
    2020               0 : nsLocalFile::Equals(nsIHashable* aOther, bool *aResult)
    2021                 : {
    2022               0 :     nsCOMPtr<nsIFile> otherFile(do_QueryInterface(aOther));
    2023               0 :     if (!otherFile) {
    2024               0 :         *aResult = false;
    2025               0 :         return NS_OK;
    2026                 :     }
    2027                 : 
    2028               0 :     return Equals(otherFile, aResult);
    2029                 : }
    2030                 : 
    2031                 : NS_IMETHODIMP
    2032           11359 : nsLocalFile::GetHashCode(PRUint32 *aResult)
    2033                 : {
    2034           11359 :     *aResult = HashString(mPath);
    2035           11359 :     return NS_OK;
    2036                 : }
    2037                 : 
    2038                 : nsresult 
    2039               8 : NS_NewLocalFile(const nsAString &path, bool followLinks, nsILocalFile* *result)
    2040                 : {
    2041              16 :     nsCAutoString buf;
    2042               8 :     nsresult rv = NS_CopyUnicodeToNative(path, buf);
    2043               8 :     if (NS_FAILED(rv))
    2044               0 :         return rv;
    2045               8 :     return NS_NewNativeLocalFile(buf, followLinks, result);
    2046                 : }
    2047                 : 
    2048                 : //-----------------------------------------------------------------------------
    2049                 : // global init/shutdown
    2050                 : //-----------------------------------------------------------------------------
    2051                 : 
    2052                 : void
    2053            1419 : nsLocalFile::GlobalInit()
    2054                 : {
    2055            1419 : }
    2056                 : 
    2057                 : void
    2058            1419 : nsLocalFile::GlobalShutdown()
    2059                 : {
    2060            1419 : }
    2061                 : 
    2062                 : // nsILocalFileMac
    2063                 : 
    2064                 : #ifdef MOZ_WIDGET_COCOA
    2065                 : 
    2066                 : static nsresult MacErrorMapper(OSErr inErr)
    2067                 : {
    2068                 :   nsresult outErr;
    2069                 : 
    2070                 :   switch (inErr)
    2071                 :   {
    2072                 :     case noErr:
    2073                 :       outErr = NS_OK;
    2074                 :       break;
    2075                 : 
    2076                 :     case fnfErr:
    2077                 :     case afpObjectNotFound:
    2078                 :     case afpDirNotFound:
    2079                 :       outErr = NS_ERROR_FILE_NOT_FOUND;
    2080                 :       break;
    2081                 : 
    2082                 :     case dupFNErr:
    2083                 :     case afpObjectExists:
    2084                 :       outErr = NS_ERROR_FILE_ALREADY_EXISTS;
    2085                 :       break;
    2086                 : 
    2087                 :     case dskFulErr:
    2088                 :     case afpDiskFull:
    2089                 :       outErr = NS_ERROR_FILE_DISK_FULL;
    2090                 :       break;
    2091                 : 
    2092                 :     case fLckdErr:
    2093                 :     case afpVolLocked:
    2094                 :       outErr = NS_ERROR_FILE_IS_LOCKED;
    2095                 :       break;
    2096                 : 
    2097                 :     case afpAccessDenied:
    2098                 :       outErr = NS_ERROR_FILE_ACCESS_DENIED;
    2099                 :       break;
    2100                 : 
    2101                 :     case afpDirNotEmpty:
    2102                 :       outErr = NS_ERROR_FILE_DIR_NOT_EMPTY;
    2103                 :       break;
    2104                 : 
    2105                 :     // Can't find good map for some
    2106                 :     case bdNamErr:
    2107                 :       outErr = NS_ERROR_FAILURE;
    2108                 :       break;
    2109                 : 
    2110                 :     default:
    2111                 :       outErr = NS_ERROR_FAILURE;
    2112                 :       break;
    2113                 :   }
    2114                 : 
    2115                 :   return outErr;
    2116                 : }
    2117                 : 
    2118                 : static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
    2119                 : {
    2120                 :   // first see if the conversion would succeed and find the length of the result
    2121                 :   CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
    2122                 :   CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
    2123                 :                                               kCFStringEncodingUTF8, 0, false,
    2124                 :                                               NULL, 0, &usedBufLen);
    2125                 :   if (charsConverted == inStrLen) {
    2126                 :     // all characters converted, do the actual conversion
    2127                 :     aOutStr.SetLength(usedBufLen);
    2128                 :     if (aOutStr.Length() != (unsigned int)usedBufLen)
    2129                 :       return NS_ERROR_OUT_OF_MEMORY;
    2130                 :     UInt8 *buffer = (UInt8*)aOutStr.BeginWriting();
    2131                 :     ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), kCFStringEncodingUTF8,
    2132                 :                        0, false, buffer, usedBufLen, &usedBufLen);
    2133                 :     return NS_OK;
    2134                 :   }
    2135                 : 
    2136                 :   return NS_ERROR_FAILURE;
    2137                 : }
    2138                 : 
    2139                 : NS_IMETHODIMP
    2140                 : nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
    2141                 : {
    2142                 :   UInt8 path[PATH_MAX];
    2143                 :   if (::CFURLGetFileSystemRepresentation(aCFURL, false, path, PATH_MAX)) {
    2144                 :     nsDependentCString nativePath((char*)path);
    2145                 :     return InitWithNativePath(nativePath);
    2146                 :   }
    2147                 : 
    2148                 :   return NS_ERROR_FAILURE;
    2149                 : }
    2150                 : 
    2151                 : NS_IMETHODIMP
    2152                 : nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
    2153                 : {
    2154                 :   NS_ENSURE_ARG(aFSRef);
    2155                 : 
    2156                 :   CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
    2157                 :   if (newURLRef) {
    2158                 :     nsresult rv = InitWithCFURL(newURLRef);
    2159                 :     ::CFRelease(newURLRef);
    2160                 :     return rv;
    2161                 :   }
    2162                 : 
    2163                 :   return NS_ERROR_FAILURE;
    2164                 : }
    2165                 : 
    2166                 : NS_IMETHODIMP
    2167                 : nsLocalFile::GetCFURL(CFURLRef *_retval)
    2168                 : {
    2169                 :   CHECK_mPath();
    2170                 : 
    2171                 :   bool isDir;
    2172                 :   IsDirectory(&isDir);
    2173                 :   *_retval = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
    2174                 :                                                        (UInt8*)mPath.get(),
    2175                 :                                                        mPath.Length(),
    2176                 :                                                        isDir);
    2177                 : 
    2178                 :   return (*_retval ? NS_OK : NS_ERROR_FAILURE);
    2179                 : }
    2180                 : 
    2181                 : NS_IMETHODIMP
    2182                 : nsLocalFile::GetFSRef(FSRef *_retval)
    2183                 : {
    2184                 :   NS_ENSURE_ARG_POINTER(_retval);
    2185                 : 
    2186                 :   nsresult rv = NS_ERROR_FAILURE;
    2187                 : 
    2188                 :   CFURLRef url = NULL;
    2189                 :   if (NS_SUCCEEDED(GetCFURL(&url))) {
    2190                 :     if (::CFURLGetFSRef(url, _retval)) {
    2191                 :       rv = NS_OK;
    2192                 :     }
    2193                 :     ::CFRelease(url);
    2194                 :   }
    2195                 : 
    2196                 :   return rv;
    2197                 : }
    2198                 : 
    2199                 : NS_IMETHODIMP
    2200                 : nsLocalFile::GetFSSpec(FSSpec *_retval)
    2201                 : {
    2202                 :   NS_ENSURE_ARG_POINTER(_retval);
    2203                 : 
    2204                 :   FSRef fsRef;
    2205                 :   nsresult rv = GetFSRef(&fsRef);
    2206                 :   if (NS_SUCCEEDED(rv)) {
    2207                 :     OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, nsnull, nsnull, _retval, nsnull);
    2208                 :     return MacErrorMapper(err);
    2209                 :   }
    2210                 : 
    2211                 :   return rv;
    2212                 : }
    2213                 : 
    2214                 : NS_IMETHODIMP
    2215                 : nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
    2216                 : {
    2217                 :   NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
    2218                 : 
    2219                 :   FSRef fsRef;
    2220                 :   nsresult rv = GetFSRef(&fsRef);
    2221                 :   if (NS_FAILED(rv))
    2222                 :     return rv;
    2223                 : 
    2224                 :   FSCatalogInfo catalogInfo;
    2225                 :   OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
    2226                 :                                  &catalogInfo, nsnull, nsnull, nsnull);
    2227                 :   if (err != noErr)
    2228                 :     return MacErrorMapper(err);
    2229                 : 
    2230                 :   *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
    2231                 :   return NS_OK;
    2232                 : }
    2233                 : 
    2234                 : NS_IMETHODIMP
    2235                 : nsLocalFile::GetFileType(OSType *aFileType)
    2236                 : {
    2237                 :   CFURLRef url;
    2238                 :   if (NS_SUCCEEDED(GetCFURL(&url))) {
    2239                 :     nsresult rv = CocoaFileUtils::GetFileTypeCode(url, aFileType);
    2240                 :     ::CFRelease(url);
    2241                 :     return rv;
    2242                 :   }
    2243                 :   return NS_ERROR_FAILURE;
    2244                 : }
    2245                 :   
    2246                 : NS_IMETHODIMP
    2247                 : nsLocalFile::SetFileType(OSType aFileType)
    2248                 : {
    2249                 :   CFURLRef url;
    2250                 :   if (NS_SUCCEEDED(GetCFURL(&url))) {
    2251                 :     nsresult rv = CocoaFileUtils::SetFileTypeCode(url, aFileType);
    2252                 :     ::CFRelease(url);
    2253                 :     return rv;
    2254                 :   }
    2255                 :   return NS_ERROR_FAILURE;
    2256                 : }
    2257                 :   
    2258                 : NS_IMETHODIMP
    2259                 : nsLocalFile::GetFileCreator(OSType *aFileCreator)
    2260                 : {
    2261                 :   CFURLRef url;
    2262                 :   if (NS_SUCCEEDED(GetCFURL(&url))) {
    2263                 :     nsresult rv = CocoaFileUtils::GetFileCreatorCode(url, aFileCreator);
    2264                 :     ::CFRelease(url);
    2265                 :     return rv;
    2266                 :   }
    2267                 :   return NS_ERROR_FAILURE;
    2268                 : }
    2269                 : 
    2270                 : NS_IMETHODIMP
    2271                 : nsLocalFile::SetFileCreator(OSType aFileCreator)
    2272                 : {
    2273                 :   CFURLRef url;
    2274                 :   if (NS_SUCCEEDED(GetCFURL(&url))) {
    2275                 :     nsresult rv = CocoaFileUtils::SetFileCreatorCode(url, aFileCreator);
    2276                 :     ::CFRelease(url);
    2277                 :     return rv;
    2278                 :   }
    2279                 :   return NS_ERROR_FAILURE;
    2280                 : }
    2281                 :   
    2282                 : NS_IMETHODIMP
    2283                 : nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, bool aLaunchInBackground)
    2284                 : {    
    2285                 :   bool isExecutable;
    2286                 :   nsresult rv = IsExecutable(&isExecutable);
    2287                 :   if (NS_FAILED(rv))
    2288                 :     return rv;
    2289                 :   if (!isExecutable)
    2290                 :     return NS_ERROR_FILE_EXECUTION_FAILED;
    2291                 : 
    2292                 :   FSRef appFSRef, docFSRef;
    2293                 :   rv = GetFSRef(&appFSRef);
    2294                 :   if (NS_FAILED(rv))
    2295                 :     return rv;
    2296                 : 
    2297                 :   if (aDocToLoad) {
    2298                 :     nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
    2299                 :     rv = macDoc->GetFSRef(&docFSRef);
    2300                 :     if (NS_FAILED(rv))
    2301                 :       return rv;
    2302                 :   }
    2303                 : 
    2304                 :   LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
    2305                 :   LSLaunchFSRefSpec thelaunchSpec;
    2306                 : 
    2307                 :   if (aLaunchInBackground)
    2308                 :     theLaunchFlags |= kLSLaunchDontSwitch;
    2309                 :   memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
    2310                 : 
    2311                 :   thelaunchSpec.appRef = &appFSRef;
    2312                 :   if (aDocToLoad) {
    2313                 :     thelaunchSpec.numDocs = 1;
    2314                 :     thelaunchSpec.itemRefs = &docFSRef;
    2315                 :   }
    2316                 :   thelaunchSpec.launchFlags = theLaunchFlags;
    2317                 : 
    2318                 :   OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
    2319                 :   if (err != noErr)
    2320                 :     return MacErrorMapper(err);
    2321                 : 
    2322                 :   return NS_OK;
    2323                 : }
    2324                 : 
    2325                 : NS_IMETHODIMP
    2326                 : nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, bool aLaunchInBackground)
    2327                 : {
    2328                 :   FSRef docFSRef;
    2329                 :   nsresult rv = GetFSRef(&docFSRef);
    2330                 :   if (NS_FAILED(rv))
    2331                 :     return rv;
    2332                 : 
    2333                 :   if (!aAppToOpenWith) {
    2334                 :     OSErr err = ::LSOpenFSRef(&docFSRef, NULL);
    2335                 :     return MacErrorMapper(err);
    2336                 :   }
    2337                 : 
    2338                 :   nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
    2339                 :   if (!appFileMac)
    2340                 :     return rv;
    2341                 : 
    2342                 :   bool isExecutable;
    2343                 :   rv = appFileMac->IsExecutable(&isExecutable);
    2344                 :   if (NS_FAILED(rv))
    2345                 :     return rv;
    2346                 :   if (!isExecutable)
    2347                 :     return NS_ERROR_FILE_EXECUTION_FAILED;
    2348                 : 
    2349                 :   FSRef appFSRef;
    2350                 :   rv = appFileMac->GetFSRef(&appFSRef);
    2351                 :   if (NS_FAILED(rv))
    2352                 :     return rv;
    2353                 : 
    2354                 :   LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
    2355                 :   LSLaunchFSRefSpec thelaunchSpec;
    2356                 : 
    2357                 :   if (aLaunchInBackground)
    2358                 :     theLaunchFlags |= kLSLaunchDontSwitch;
    2359                 :   memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
    2360                 : 
    2361                 :   thelaunchSpec.appRef = &appFSRef;
    2362                 :   thelaunchSpec.numDocs = 1;
    2363                 :   thelaunchSpec.itemRefs = &docFSRef;
    2364                 :   thelaunchSpec.launchFlags = theLaunchFlags;
    2365                 : 
    2366                 :   OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
    2367                 :   if (err != noErr)
    2368                 :     return MacErrorMapper(err);
    2369                 : 
    2370                 :   return NS_OK;
    2371                 : }
    2372                 : 
    2373                 : NS_IMETHODIMP
    2374                 : nsLocalFile::IsPackage(bool *_retval)
    2375                 : {
    2376                 :   NS_ENSURE_ARG(_retval);
    2377                 :   *_retval = false;
    2378                 : 
    2379                 :   CFURLRef url;
    2380                 :   nsresult rv = GetCFURL(&url);
    2381                 :   if (NS_FAILED(rv))
    2382                 :     return rv;
    2383                 : 
    2384                 :   LSItemInfoRecord info;
    2385                 :   OSStatus status = ::LSCopyItemInfoForURL(url, kLSRequestBasicFlagsOnly, &info);
    2386                 : 
    2387                 :   ::CFRelease(url);
    2388                 : 
    2389                 :   if (status != noErr) {
    2390                 :     return NS_ERROR_FAILURE;
    2391                 :   }
    2392                 : 
    2393                 :   *_retval = !!(info.flags & kLSItemInfoIsPackage);
    2394                 : 
    2395                 :   return NS_OK;
    2396                 : }
    2397                 : 
    2398                 : NS_IMETHODIMP
    2399                 : nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
    2400                 : {
    2401                 :   bool isPackage = false;
    2402                 :   nsresult rv = IsPackage(&isPackage);
    2403                 :   if (NS_FAILED(rv) || !isPackage)
    2404                 :     return NS_ERROR_FAILURE;
    2405                 : 
    2406                 :   nsAutoString name;
    2407                 :   rv = GetLeafName(name);
    2408                 :   if (NS_FAILED(rv))
    2409                 :     return rv;
    2410                 : 
    2411                 :   PRInt32 length = name.Length();
    2412                 :   if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
    2413                 :     // 4 characters in ".app"
    2414                 :     outBundleName = Substring(name, 0, length - 4);
    2415                 :   }
    2416                 :   else {
    2417                 :     outBundleName = name;
    2418                 :   }
    2419                 : 
    2420                 :   return NS_OK;
    2421                 : }
    2422                 : 
    2423                 : NS_IMETHODIMP
    2424                 : nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
    2425                 : {
    2426                 :   nsresult rv = NS_ERROR_FAILURE;
    2427                 : 
    2428                 :   CFURLRef urlRef;
    2429                 :   if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
    2430                 :     CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
    2431                 :     if (bundle) {
    2432                 :       CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
    2433                 :       if (bundleIdentifier)
    2434                 :         rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
    2435                 :       ::CFRelease(bundle);
    2436                 :     }
    2437                 :     ::CFRelease(urlRef);
    2438                 :   }
    2439                 : 
    2440                 :   return rv;
    2441                 : }
    2442                 : 
    2443                 : NS_IMETHODIMP
    2444                 : nsLocalFile::GetBundleContentsLastModifiedTime(PRInt64 *aLastModTime)
    2445                 : {
    2446                 :   CHECK_mPath();
    2447                 :   NS_ENSURE_ARG_POINTER(aLastModTime);
    2448                 : 
    2449                 :   bool isPackage = false;
    2450                 :   nsresult rv = IsPackage(&isPackage);
    2451                 :   if (NS_FAILED(rv) || !isPackage) {
    2452                 :     return GetLastModifiedTime(aLastModTime);
    2453                 :   }
    2454                 : 
    2455                 :   nsCAutoString infoPlistPath(mPath);
    2456                 :   infoPlistPath.AppendLiteral("/Contents/Info.plist");
    2457                 :   PRFileInfo64 info;
    2458                 :   if (PR_GetFileInfo64(infoPlistPath.get(), &info) != PR_SUCCESS) {
    2459                 :     return GetLastModifiedTime(aLastModTime);
    2460                 :   }
    2461                 :   PRInt64 modTime = PRInt64(info.modifyTime);
    2462                 :   if (modTime == 0) {
    2463                 :     *aLastModTime = 0;
    2464                 :   } else {
    2465                 :     *aLastModTime = modTime / PRInt64(PR_USEC_PER_MSEC);
    2466                 :   }
    2467                 : 
    2468                 :   return NS_OK;
    2469                 : }
    2470                 : 
    2471                 : NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
    2472                 : {
    2473                 :   NS_ENSURE_ARG(aFile);
    2474                 : 
    2475                 :   nsCAutoString nativePath;
    2476                 :   nsresult rv = aFile->GetNativePath(nativePath);
    2477                 :   if (NS_FAILED(rv))
    2478                 :     return rv;
    2479                 : 
    2480                 :   return InitWithNativePath(nativePath);
    2481                 : }
    2482                 : 
    2483                 : nsresult
    2484                 : NS_NewLocalFileWithFSRef(const FSRef* aFSRef, bool aFollowLinks, nsILocalFileMac** result)
    2485                 : {
    2486                 :   nsLocalFile* file = new nsLocalFile();
    2487                 :   if (file == nsnull)
    2488                 :     return NS_ERROR_OUT_OF_MEMORY;
    2489                 :   NS_ADDREF(file);
    2490                 : 
    2491                 :   file->SetFollowLinks(aFollowLinks);
    2492                 : 
    2493                 :   nsresult rv = file->InitWithFSRef(aFSRef);
    2494                 :   if (NS_FAILED(rv)) {
    2495                 :     NS_RELEASE(file);
    2496                 :     return rv;
    2497                 :   }
    2498                 :   *result = file;
    2499                 :   return NS_OK;
    2500                 : }
    2501                 : 
    2502                 : nsresult
    2503                 : NS_NewLocalFileWithCFURL(const CFURLRef aURL, bool aFollowLinks, nsILocalFileMac** result)
    2504                 : {
    2505                 :   nsLocalFile* file = new nsLocalFile();
    2506                 :   if (!file)
    2507                 :     return NS_ERROR_OUT_OF_MEMORY;
    2508                 :   NS_ADDREF(file);
    2509                 : 
    2510                 :   file->SetFollowLinks(aFollowLinks);
    2511                 : 
    2512                 :   nsresult rv = file->InitWithCFURL(aURL);
    2513                 :   if (NS_FAILED(rv)) {
    2514                 :     NS_RELEASE(file);
    2515                 :     return rv;
    2516                 :   }
    2517                 :   *result = file;
    2518                 :   return NS_OK;
    2519                 : }
    2520                 : 
    2521                 : #endif

Generated by: LCOV version 1.7