1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/io/nsLocalFileUnix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2555 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/** 1.10 + * Implementation of nsIFile for "unixy" systems. 1.11 + */ 1.12 + 1.13 +#include "mozilla/ArrayUtils.h" 1.14 +#include "mozilla/Attributes.h" 1.15 + 1.16 +#include <sys/types.h> 1.17 +#include <sys/stat.h> 1.18 +#include <unistd.h> 1.19 +#include <fcntl.h> 1.20 +#include <errno.h> 1.21 +#include <utime.h> 1.22 +#include <dirent.h> 1.23 +#include <ctype.h> 1.24 +#include <locale.h> 1.25 +#if defined(VMS) 1.26 + #include <fabdef.h> 1.27 +#endif 1.28 + 1.29 +#if defined(HAVE_SYS_QUOTA_H) && defined(HAVE_LINUX_QUOTA_H) 1.30 +#define USE_LINUX_QUOTACTL 1.31 +#include <sys/quota.h> 1.32 +#endif 1.33 + 1.34 +#include "xpcom-private.h" 1.35 +#include "nsDirectoryServiceDefs.h" 1.36 +#include "nsCRT.h" 1.37 +#include "nsCOMPtr.h" 1.38 +#include "nsMemory.h" 1.39 +#include "nsIFile.h" 1.40 +#include "nsString.h" 1.41 +#include "nsReadableUtils.h" 1.42 +#include "nsLocalFile.h" 1.43 +#include "nsIComponentManager.h" 1.44 +#include "nsXPIDLString.h" 1.45 +#include "prproces.h" 1.46 +#include "nsIDirectoryEnumerator.h" 1.47 +#include "nsISimpleEnumerator.h" 1.48 +#include "private/pprio.h" 1.49 +#include "prlink.h" 1.50 + 1.51 +#ifdef MOZ_WIDGET_GTK 1.52 +#include "nsIGIOService.h" 1.53 +#include "nsIGnomeVFSService.h" 1.54 +#endif 1.55 + 1.56 +#ifdef MOZ_WIDGET_COCOA 1.57 +#include <Carbon/Carbon.h> 1.58 +#include "CocoaFileUtils.h" 1.59 +#include "prmem.h" 1.60 +#include "plbase64.h" 1.61 + 1.62 +static nsresult MacErrorMapper(OSErr inErr); 1.63 +#endif 1.64 + 1.65 +#ifdef MOZ_WIDGET_ANDROID 1.66 +#include "AndroidBridge.h" 1.67 +#include "nsIMIMEService.h" 1.68 +#include <linux/magic.h> 1.69 +#endif 1.70 + 1.71 +#ifdef MOZ_ENABLE_CONTENTACTION 1.72 +#include <contentaction/contentaction.h> 1.73 +#endif 1.74 + 1.75 +#include "nsNativeCharsetUtils.h" 1.76 +#include "nsTraceRefcnt.h" 1.77 +#include "nsHashKeys.h" 1.78 + 1.79 +using namespace mozilla; 1.80 + 1.81 +#define ENSURE_STAT_CACHE() \ 1.82 + PR_BEGIN_MACRO \ 1.83 + if (!FillStatCache()) \ 1.84 + return NSRESULT_FOR_ERRNO(); \ 1.85 + PR_END_MACRO 1.86 + 1.87 +#define CHECK_mPath() \ 1.88 + PR_BEGIN_MACRO \ 1.89 + if (mPath.IsEmpty()) \ 1.90 + return NS_ERROR_NOT_INITIALIZED; \ 1.91 + PR_END_MACRO 1.92 + 1.93 +/* directory enumerator */ 1.94 +class 1.95 +nsDirEnumeratorUnix MOZ_FINAL : public nsISimpleEnumerator, 1.96 + public nsIDirectoryEnumerator 1.97 +{ 1.98 + public: 1.99 + nsDirEnumeratorUnix(); 1.100 + 1.101 + // nsISupports interface 1.102 + NS_DECL_ISUPPORTS 1.103 + 1.104 + // nsISimpleEnumerator interface 1.105 + NS_DECL_NSISIMPLEENUMERATOR 1.106 + 1.107 + // nsIDirectoryEnumerator interface 1.108 + NS_DECL_NSIDIRECTORYENUMERATOR 1.109 + 1.110 + NS_IMETHOD Init(nsLocalFile *parent, bool ignored); 1.111 + 1.112 + private: 1.113 + ~nsDirEnumeratorUnix(); 1.114 + 1.115 + protected: 1.116 + NS_IMETHOD GetNextEntry(); 1.117 + 1.118 + DIR *mDir; 1.119 + struct dirent *mEntry; 1.120 + nsCString mParentPath; 1.121 +}; 1.122 + 1.123 +nsDirEnumeratorUnix::nsDirEnumeratorUnix() : 1.124 + mDir(nullptr), 1.125 + mEntry(nullptr) 1.126 +{ 1.127 +} 1.128 + 1.129 +nsDirEnumeratorUnix::~nsDirEnumeratorUnix() 1.130 +{ 1.131 + Close(); 1.132 +} 1.133 + 1.134 +NS_IMPL_ISUPPORTS(nsDirEnumeratorUnix, nsISimpleEnumerator, nsIDirectoryEnumerator) 1.135 + 1.136 +NS_IMETHODIMP 1.137 +nsDirEnumeratorUnix::Init(nsLocalFile *parent, bool resolveSymlinks /*ignored*/) 1.138 +{ 1.139 + nsAutoCString dirPath; 1.140 + if (NS_FAILED(parent->GetNativePath(dirPath)) || 1.141 + dirPath.IsEmpty()) { 1.142 + return NS_ERROR_FILE_INVALID_PATH; 1.143 + } 1.144 + 1.145 + if (NS_FAILED(parent->GetNativePath(mParentPath))) 1.146 + return NS_ERROR_FAILURE; 1.147 + 1.148 + mDir = opendir(dirPath.get()); 1.149 + if (!mDir) 1.150 + return NSRESULT_FOR_ERRNO(); 1.151 + return GetNextEntry(); 1.152 +} 1.153 + 1.154 +NS_IMETHODIMP 1.155 +nsDirEnumeratorUnix::HasMoreElements(bool *result) 1.156 +{ 1.157 + *result = mDir && mEntry; 1.158 + if (!*result) 1.159 + Close(); 1.160 + return NS_OK; 1.161 +} 1.162 + 1.163 +NS_IMETHODIMP 1.164 +nsDirEnumeratorUnix::GetNext(nsISupports **_retval) 1.165 +{ 1.166 + nsCOMPtr<nsIFile> file; 1.167 + nsresult rv = GetNextFile(getter_AddRefs(file)); 1.168 + if (NS_FAILED(rv)) 1.169 + return rv; 1.170 + NS_IF_ADDREF(*_retval = file); 1.171 + return NS_OK; 1.172 +} 1.173 + 1.174 +NS_IMETHODIMP 1.175 +nsDirEnumeratorUnix::GetNextEntry() 1.176 +{ 1.177 + do { 1.178 + errno = 0; 1.179 + mEntry = readdir(mDir); 1.180 + 1.181 + // end of dir or error 1.182 + if (!mEntry) 1.183 + return NSRESULT_FOR_ERRNO(); 1.184 + 1.185 + // keep going past "." and ".." 1.186 + } while (mEntry->d_name[0] == '.' && 1.187 + (mEntry->d_name[1] == '\0' || // .\0 1.188 + (mEntry->d_name[1] == '.' && 1.189 + mEntry->d_name[2] == '\0'))); // ..\0 1.190 + return NS_OK; 1.191 +} 1.192 + 1.193 +NS_IMETHODIMP 1.194 +nsDirEnumeratorUnix::GetNextFile(nsIFile **_retval) 1.195 +{ 1.196 + nsresult rv; 1.197 + if (!mDir || !mEntry) { 1.198 + *_retval = nullptr; 1.199 + return NS_OK; 1.200 + } 1.201 + 1.202 + nsCOMPtr<nsIFile> file = new nsLocalFile(); 1.203 + 1.204 + if (NS_FAILED(rv = file->InitWithNativePath(mParentPath)) || 1.205 + NS_FAILED(rv = file->AppendNative(nsDependentCString(mEntry->d_name)))) 1.206 + return rv; 1.207 + 1.208 + file.forget(_retval); 1.209 + return GetNextEntry(); 1.210 +} 1.211 + 1.212 +NS_IMETHODIMP 1.213 +nsDirEnumeratorUnix::Close() 1.214 +{ 1.215 + if (mDir) { 1.216 + closedir(mDir); 1.217 + mDir = nullptr; 1.218 + } 1.219 + return NS_OK; 1.220 +} 1.221 + 1.222 +nsLocalFile::nsLocalFile() 1.223 +{ 1.224 +} 1.225 + 1.226 +nsLocalFile::nsLocalFile(const nsLocalFile& other) 1.227 + : mPath(other.mPath) 1.228 +{ 1.229 +} 1.230 + 1.231 +#ifdef MOZ_WIDGET_COCOA 1.232 +NS_IMPL_ISUPPORTS(nsLocalFile, 1.233 + nsILocalFileMac, 1.234 + nsILocalFile, 1.235 + nsIFile, 1.236 + nsIHashable) 1.237 +#else 1.238 +NS_IMPL_ISUPPORTS(nsLocalFile, 1.239 + nsILocalFile, 1.240 + nsIFile, 1.241 + nsIHashable) 1.242 +#endif 1.243 + 1.244 +nsresult 1.245 +nsLocalFile::nsLocalFileConstructor(nsISupports *outer, 1.246 + const nsIID &aIID, 1.247 + void **aInstancePtr) 1.248 +{ 1.249 + if (NS_WARN_IF(!aInstancePtr)) 1.250 + return NS_ERROR_INVALID_ARG; 1.251 + if (NS_WARN_IF(outer)) 1.252 + return NS_ERROR_NO_AGGREGATION; 1.253 + 1.254 + *aInstancePtr = nullptr; 1.255 + 1.256 + nsCOMPtr<nsIFile> inst = new nsLocalFile(); 1.257 + return inst->QueryInterface(aIID, aInstancePtr); 1.258 +} 1.259 + 1.260 +bool 1.261 +nsLocalFile::FillStatCache() { 1.262 + if (STAT(mPath.get(), &mCachedStat) == -1) { 1.263 + // try lstat it may be a symlink 1.264 + if (LSTAT(mPath.get(), &mCachedStat) == -1) { 1.265 + return false; 1.266 + } 1.267 + } 1.268 + return true; 1.269 +} 1.270 + 1.271 +NS_IMETHODIMP 1.272 +nsLocalFile::Clone(nsIFile **file) 1.273 +{ 1.274 + // Just copy-construct ourselves 1.275 + nsRefPtr<nsLocalFile> copy = new nsLocalFile(*this); 1.276 + copy.forget(file); 1.277 + return NS_OK; 1.278 +} 1.279 + 1.280 +NS_IMETHODIMP 1.281 +nsLocalFile::InitWithNativePath(const nsACString &filePath) 1.282 +{ 1.283 + if (filePath.Equals("~") || Substring(filePath, 0, 2).EqualsLiteral("~/")) { 1.284 + nsCOMPtr<nsIFile> homeDir; 1.285 + nsAutoCString homePath; 1.286 + if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR, 1.287 + getter_AddRefs(homeDir))) || 1.288 + NS_FAILED(homeDir->GetNativePath(homePath))) { 1.289 + return NS_ERROR_FAILURE; 1.290 + } 1.291 + 1.292 + mPath = homePath; 1.293 + if (filePath.Length() > 2) 1.294 + mPath.Append(Substring(filePath, 1, filePath.Length() - 1)); 1.295 + } else { 1.296 + if (filePath.IsEmpty() || filePath.First() != '/') 1.297 + return NS_ERROR_FILE_UNRECOGNIZED_PATH; 1.298 + mPath = filePath; 1.299 + } 1.300 + 1.301 + // trim off trailing slashes 1.302 + ssize_t len = mPath.Length(); 1.303 + while ((len > 1) && (mPath[len - 1] == '/')) 1.304 + --len; 1.305 + mPath.SetLength(len); 1.306 + 1.307 + return NS_OK; 1.308 +} 1.309 + 1.310 +NS_IMETHODIMP 1.311 +nsLocalFile::CreateAllAncestors(uint32_t permissions) 1.312 +{ 1.313 + // <jband> I promise to play nice 1.314 + char *buffer = mPath.BeginWriting(), 1.315 + *slashp = buffer; 1.316 + 1.317 +#ifdef DEBUG_NSIFILE 1.318 + fprintf(stderr, "nsIFile: before: %s\n", buffer); 1.319 +#endif 1.320 + 1.321 + while ((slashp = strchr(slashp + 1, '/'))) { 1.322 + /* 1.323 + * Sequences of '/' are equivalent to a single '/'. 1.324 + */ 1.325 + if (slashp[1] == '/') 1.326 + continue; 1.327 + 1.328 + /* 1.329 + * If the path has a trailing slash, don't make the last component, 1.330 + * because we'll get EEXIST in Create when we try to build the final 1.331 + * component again, and it's easier to condition the logic here than 1.332 + * there. 1.333 + */ 1.334 + if (slashp[1] == '\0') 1.335 + break; 1.336 + 1.337 + /* Temporarily NUL-terminate here */ 1.338 + *slashp = '\0'; 1.339 +#ifdef DEBUG_NSIFILE 1.340 + fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer); 1.341 +#endif 1.342 + int mkdir_result = mkdir(buffer, permissions); 1.343 + int mkdir_errno = errno; 1.344 + if (mkdir_result == -1) { 1.345 + /* 1.346 + * Always set |errno| to EEXIST if the dir already exists 1.347 + * (we have to do this here since the errno value is not consistent 1.348 + * in all cases - various reasons like different platform, 1.349 + * automounter-controlled dir, etc. can affect it (see bug 125489 1.350 + * for details)). 1.351 + */ 1.352 + if (access(buffer, F_OK) == 0) { 1.353 + mkdir_errno = EEXIST; 1.354 + } 1.355 + } 1.356 + 1.357 + /* Put the / back before we (maybe) return */ 1.358 + *slashp = '/'; 1.359 + 1.360 + /* 1.361 + * We could get EEXIST for an existing file -- not directory -- 1.362 + * with the name of one of our ancestors, but that's OK: we'll get 1.363 + * ENOTDIR when we try to make the next component in the path, 1.364 + * either here on back in Create, and error out appropriately. 1.365 + */ 1.366 + if (mkdir_result == -1 && mkdir_errno != EEXIST) 1.367 + return nsresultForErrno(mkdir_errno); 1.368 + } 1.369 + 1.370 +#ifdef DEBUG_NSIFILE 1.371 + fprintf(stderr, "nsIFile: after: %s\n", buffer); 1.372 +#endif 1.373 + 1.374 + return NS_OK; 1.375 +} 1.376 + 1.377 +NS_IMETHODIMP 1.378 +nsLocalFile::OpenNSPRFileDesc(int32_t flags, int32_t mode, PRFileDesc **_retval) 1.379 +{ 1.380 + *_retval = PR_Open(mPath.get(), flags, mode); 1.381 + if (! *_retval) 1.382 + return NS_ErrorAccordingToNSPR(); 1.383 + 1.384 + if (flags & DELETE_ON_CLOSE) { 1.385 + PR_Delete(mPath.get()); 1.386 + } 1.387 + 1.388 +#if defined(HAVE_POSIX_FADVISE) 1.389 + if (flags & OS_READAHEAD) { 1.390 + posix_fadvise(PR_FileDesc2NativeHandle(*_retval), 0, 0, 1.391 + POSIX_FADV_SEQUENTIAL); 1.392 + } 1.393 +#endif 1.394 + return NS_OK; 1.395 +} 1.396 + 1.397 +NS_IMETHODIMP 1.398 +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) 1.399 +{ 1.400 + *_retval = fopen(mPath.get(), mode); 1.401 + if (! *_retval) 1.402 + return NS_ERROR_FAILURE; 1.403 + 1.404 + return NS_OK; 1.405 +} 1.406 + 1.407 +static int 1.408 +do_create(const char *path, int flags, mode_t mode, PRFileDesc **_retval) 1.409 +{ 1.410 + *_retval = PR_Open(path, flags, mode); 1.411 + return *_retval ? 0 : -1; 1.412 +} 1.413 + 1.414 +static int 1.415 +do_mkdir(const char *path, int flags, mode_t mode, PRFileDesc **_retval) 1.416 +{ 1.417 + *_retval = nullptr; 1.418 + return mkdir(path, mode); 1.419 +} 1.420 + 1.421 +nsresult 1.422 +nsLocalFile::CreateAndKeepOpen(uint32_t type, int flags, 1.423 + uint32_t permissions, PRFileDesc **_retval) 1.424 +{ 1.425 + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) 1.426 + return NS_ERROR_FILE_UNKNOWN_TYPE; 1.427 + 1.428 + int result; 1.429 + int (*createFunc)(const char *, int, mode_t, PRFileDesc **) = 1.430 + (type == NORMAL_FILE_TYPE) ? do_create : do_mkdir; 1.431 + 1.432 + result = createFunc(mPath.get(), flags, permissions, _retval); 1.433 + if (result == -1 && errno == ENOENT) { 1.434 + /* 1.435 + * If we failed because of missing ancestor components, try to create 1.436 + * them and then retry the original creation. 1.437 + * 1.438 + * Ancestor directories get the same permissions as the file we're 1.439 + * creating, with the X bit set for each of (user,group,other) with 1.440 + * an R bit in the original permissions. If you want to do anything 1.441 + * fancy like setgid or sticky bits, do it by hand. 1.442 + */ 1.443 + int dirperm = permissions; 1.444 + if (permissions & S_IRUSR) 1.445 + dirperm |= S_IXUSR; 1.446 + if (permissions & S_IRGRP) 1.447 + dirperm |= S_IXGRP; 1.448 + if (permissions & S_IROTH) 1.449 + dirperm |= S_IXOTH; 1.450 + 1.451 +#ifdef DEBUG_NSIFILE 1.452 + fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, 1.453 + dirperm); 1.454 +#endif 1.455 + 1.456 + if (NS_FAILED(CreateAllAncestors(dirperm))) 1.457 + return NS_ERROR_FAILURE; 1.458 + 1.459 +#ifdef DEBUG_NSIFILE 1.460 + fprintf(stderr, "nsIFile: Create(\"%s\") again\n", mPath.get()); 1.461 +#endif 1.462 + result = createFunc(mPath.get(), flags, permissions, _retval); 1.463 + } 1.464 + return NSRESULT_FOR_RETURN(result); 1.465 +} 1.466 + 1.467 +NS_IMETHODIMP 1.468 +nsLocalFile::Create(uint32_t type, uint32_t permissions) 1.469 +{ 1.470 + PRFileDesc *junk = nullptr; 1.471 + nsresult rv = CreateAndKeepOpen(type, 1.472 + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE | 1.473 + PR_EXCL, 1.474 + permissions, 1.475 + &junk); 1.476 + if (junk) 1.477 + PR_Close(junk); 1.478 + return rv; 1.479 +} 1.480 + 1.481 +NS_IMETHODIMP 1.482 +nsLocalFile::AppendNative(const nsACString &fragment) 1.483 +{ 1.484 + if (fragment.IsEmpty()) 1.485 + return NS_OK; 1.486 + 1.487 + // only one component of path can be appended 1.488 + nsACString::const_iterator begin, end; 1.489 + if (FindCharInReadable('/', fragment.BeginReading(begin), 1.490 + fragment.EndReading(end))) 1.491 + return NS_ERROR_FILE_UNRECOGNIZED_PATH; 1.492 + 1.493 + return AppendRelativeNativePath(fragment); 1.494 +} 1.495 + 1.496 +NS_IMETHODIMP 1.497 +nsLocalFile::AppendRelativeNativePath(const nsACString &fragment) 1.498 +{ 1.499 + if (fragment.IsEmpty()) 1.500 + return NS_OK; 1.501 + 1.502 + // No leading '/' 1.503 + if (fragment.First() == '/') 1.504 + return NS_ERROR_FILE_UNRECOGNIZED_PATH; 1.505 + 1.506 + if (mPath.EqualsLiteral("/")) 1.507 + mPath.Append(fragment); 1.508 + else 1.509 + mPath.Append(NS_LITERAL_CSTRING("/") + fragment); 1.510 + 1.511 + return NS_OK; 1.512 +} 1.513 + 1.514 +NS_IMETHODIMP 1.515 +nsLocalFile::Normalize() 1.516 +{ 1.517 + char resolved_path[PATH_MAX] = ""; 1.518 + char *resolved_path_ptr = nullptr; 1.519 + 1.520 + resolved_path_ptr = realpath(mPath.get(), resolved_path); 1.521 + 1.522 + // if there is an error, the return is null. 1.523 + if (!resolved_path_ptr) 1.524 + return NSRESULT_FOR_ERRNO(); 1.525 + 1.526 + mPath = resolved_path; 1.527 + return NS_OK; 1.528 +} 1.529 + 1.530 +void 1.531 +nsLocalFile::LocateNativeLeafName(nsACString::const_iterator &begin, 1.532 + nsACString::const_iterator &end) 1.533 +{ 1.534 + // XXX perhaps we should cache this?? 1.535 + 1.536 + mPath.BeginReading(begin); 1.537 + mPath.EndReading(end); 1.538 + 1.539 + nsACString::const_iterator it = end; 1.540 + nsACString::const_iterator stop = begin; 1.541 + --stop; 1.542 + while (--it != stop) { 1.543 + if (*it == '/') { 1.544 + begin = ++it; 1.545 + return; 1.546 + } 1.547 + } 1.548 + // else, the entire path is the leaf name (which means this 1.549 + // isn't an absolute path... unexpected??) 1.550 +} 1.551 + 1.552 +NS_IMETHODIMP 1.553 +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) 1.554 +{ 1.555 + nsACString::const_iterator begin, end; 1.556 + LocateNativeLeafName(begin, end); 1.557 + aLeafName = Substring(begin, end); 1.558 + return NS_OK; 1.559 +} 1.560 + 1.561 +NS_IMETHODIMP 1.562 +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) 1.563 +{ 1.564 + nsACString::const_iterator begin, end; 1.565 + LocateNativeLeafName(begin, end); 1.566 + mPath.Replace(begin.get() - mPath.get(), Distance(begin, end), aLeafName); 1.567 + return NS_OK; 1.568 +} 1.569 + 1.570 +NS_IMETHODIMP 1.571 +nsLocalFile::GetNativePath(nsACString &_retval) 1.572 +{ 1.573 + _retval = mPath; 1.574 + return NS_OK; 1.575 +} 1.576 + 1.577 +nsresult 1.578 +nsLocalFile::GetNativeTargetPathName(nsIFile *newParent, 1.579 + const nsACString &newName, 1.580 + nsACString &_retval) 1.581 +{ 1.582 + nsresult rv; 1.583 + nsCOMPtr<nsIFile> oldParent; 1.584 + 1.585 + if (!newParent) { 1.586 + if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent)))) 1.587 + return rv; 1.588 + newParent = oldParent.get(); 1.589 + } else { 1.590 + // check to see if our target directory exists 1.591 + bool targetExists; 1.592 + if (NS_FAILED(rv = newParent->Exists(&targetExists))) 1.593 + return rv; 1.594 + 1.595 + if (!targetExists) { 1.596 + // XXX create the new directory with some permissions 1.597 + rv = newParent->Create(DIRECTORY_TYPE, 0755); 1.598 + if (NS_FAILED(rv)) 1.599 + return rv; 1.600 + } else { 1.601 + // make sure that the target is actually a directory 1.602 + bool targetIsDirectory; 1.603 + if (NS_FAILED(rv = newParent->IsDirectory(&targetIsDirectory))) 1.604 + return rv; 1.605 + if (!targetIsDirectory) 1.606 + return NS_ERROR_FILE_DESTINATION_NOT_DIR; 1.607 + } 1.608 + } 1.609 + 1.610 + nsACString::const_iterator nameBegin, nameEnd; 1.611 + if (!newName.IsEmpty()) { 1.612 + newName.BeginReading(nameBegin); 1.613 + newName.EndReading(nameEnd); 1.614 + } 1.615 + else 1.616 + LocateNativeLeafName(nameBegin, nameEnd); 1.617 + 1.618 + nsAutoCString dirName; 1.619 + if (NS_FAILED(rv = newParent->GetNativePath(dirName))) 1.620 + return rv; 1.621 + 1.622 + _retval = dirName 1.623 + + NS_LITERAL_CSTRING("/") 1.624 + + Substring(nameBegin, nameEnd); 1.625 + return NS_OK; 1.626 +} 1.627 + 1.628 +nsresult 1.629 +nsLocalFile::CopyDirectoryTo(nsIFile *newParent) 1.630 +{ 1.631 + nsresult rv; 1.632 + /* 1.633 + * dirCheck is used for various boolean test results such as from Equals, 1.634 + * Exists, isDir, etc. 1.635 + */ 1.636 + bool dirCheck, isSymlink; 1.637 + uint32_t oldPerms; 1.638 + 1.639 + if (NS_FAILED(rv = IsDirectory(&dirCheck))) 1.640 + return rv; 1.641 + if (!dirCheck) 1.642 + return CopyToNative(newParent, EmptyCString()); 1.643 + 1.644 + if (NS_FAILED(rv = Equals(newParent, &dirCheck))) 1.645 + return rv; 1.646 + if (dirCheck) { 1.647 + // can't copy dir to itself 1.648 + return NS_ERROR_INVALID_ARG; 1.649 + } 1.650 + 1.651 + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) 1.652 + return rv; 1.653 + // get the dirs old permissions 1.654 + if (NS_FAILED(rv = GetPermissions(&oldPerms))) 1.655 + return rv; 1.656 + if (!dirCheck) { 1.657 + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) 1.658 + return rv; 1.659 + } else { // dir exists lets try to use leaf 1.660 + nsAutoCString leafName; 1.661 + if (NS_FAILED(rv = GetNativeLeafName(leafName))) 1.662 + return rv; 1.663 + if (NS_FAILED(rv = newParent->AppendNative(leafName))) 1.664 + return rv; 1.665 + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) 1.666 + return rv; 1.667 + if (dirCheck) 1.668 + return NS_ERROR_FILE_ALREADY_EXISTS; // dest exists 1.669 + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) 1.670 + return rv; 1.671 + } 1.672 + 1.673 + nsCOMPtr<nsISimpleEnumerator> dirIterator; 1.674 + if (NS_FAILED(rv = GetDirectoryEntries(getter_AddRefs(dirIterator)))) 1.675 + return rv; 1.676 + 1.677 + bool hasMore = false; 1.678 + while (dirIterator->HasMoreElements(&hasMore), hasMore) { 1.679 + nsCOMPtr<nsISupports> supports; 1.680 + nsCOMPtr<nsIFile> entry; 1.681 + rv = dirIterator->GetNext(getter_AddRefs(supports)); 1.682 + entry = do_QueryInterface(supports); 1.683 + if (NS_FAILED(rv) || !entry) 1.684 + continue; 1.685 + if (NS_FAILED(rv = entry->IsSymlink(&isSymlink))) 1.686 + return rv; 1.687 + if (NS_FAILED(rv = entry->IsDirectory(&dirCheck))) 1.688 + return rv; 1.689 + if (dirCheck && !isSymlink) { 1.690 + nsCOMPtr<nsIFile> destClone; 1.691 + rv = newParent->Clone(getter_AddRefs(destClone)); 1.692 + if (NS_SUCCEEDED(rv)) { 1.693 + if (NS_FAILED(rv = entry->CopyToNative(destClone, EmptyCString()))) { 1.694 +#ifdef DEBUG 1.695 + nsresult rv2; 1.696 + nsAutoCString pathName; 1.697 + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) 1.698 + return rv2; 1.699 + printf("Operation not supported: %s\n", pathName.get()); 1.700 +#endif 1.701 + if (rv == NS_ERROR_OUT_OF_MEMORY) 1.702 + return rv; 1.703 + continue; 1.704 + } 1.705 + } 1.706 + } else { 1.707 + if (NS_FAILED(rv = entry->CopyToNative(newParent, EmptyCString()))) { 1.708 +#ifdef DEBUG 1.709 + nsresult rv2; 1.710 + nsAutoCString pathName; 1.711 + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) 1.712 + return rv2; 1.713 + printf("Operation not supported: %s\n", pathName.get()); 1.714 +#endif 1.715 + if (rv == NS_ERROR_OUT_OF_MEMORY) 1.716 + return rv; 1.717 + continue; 1.718 + } 1.719 + } 1.720 + } 1.721 + return NS_OK; 1.722 +} 1.723 + 1.724 +NS_IMETHODIMP 1.725 +nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName) 1.726 +{ 1.727 + nsresult rv; 1.728 + // check to make sure that this has been initialized properly 1.729 + CHECK_mPath(); 1.730 + 1.731 + // we copy the parent here so 'newParent' remains immutable 1.732 + nsCOMPtr <nsIFile> workParent; 1.733 + if (newParent) { 1.734 + if (NS_FAILED(rv = newParent->Clone(getter_AddRefs(workParent)))) 1.735 + return rv; 1.736 + } else { 1.737 + if (NS_FAILED(rv = GetParent(getter_AddRefs(workParent)))) 1.738 + return rv; 1.739 + } 1.740 + 1.741 + // check to see if we are a directory or if we are a file 1.742 + bool isDirectory; 1.743 + if (NS_FAILED(rv = IsDirectory(&isDirectory))) 1.744 + return rv; 1.745 + 1.746 + nsAutoCString newPathName; 1.747 + if (isDirectory) { 1.748 + if (!newName.IsEmpty()) { 1.749 + if (NS_FAILED(rv = workParent->AppendNative(newName))) 1.750 + return rv; 1.751 + } else { 1.752 + if (NS_FAILED(rv = GetNativeLeafName(newPathName))) 1.753 + return rv; 1.754 + if (NS_FAILED(rv = workParent->AppendNative(newPathName))) 1.755 + return rv; 1.756 + } 1.757 + if (NS_FAILED(rv = CopyDirectoryTo(workParent))) 1.758 + return rv; 1.759 + } else { 1.760 + rv = GetNativeTargetPathName(workParent, newName, newPathName); 1.761 + if (NS_FAILED(rv)) 1.762 + return rv; 1.763 + 1.764 +#ifdef DEBUG_blizzard 1.765 + printf("nsLocalFile::CopyTo() %s -> %s\n", mPath.get(), newPathName.get()); 1.766 +#endif 1.767 + 1.768 + // actually create the file. 1.769 + nsLocalFile *newFile = new nsLocalFile(); 1.770 + if (!newFile) 1.771 + return NS_ERROR_OUT_OF_MEMORY; 1.772 + 1.773 + nsCOMPtr<nsIFile> fileRef(newFile); // release on exit 1.774 + 1.775 + rv = newFile->InitWithNativePath(newPathName); 1.776 + if (NS_FAILED(rv)) 1.777 + return rv; 1.778 + 1.779 + // get the old permissions 1.780 + uint32_t myPerms; 1.781 + GetPermissions(&myPerms); 1.782 + 1.783 + // Create the new file with the old file's permissions, even if write 1.784 + // permission is missing. We can't create with write permission and 1.785 + // then change back to myPerm on all filesystems (FAT on Linux, e.g.). 1.786 + // But we can write to a read-only file on all Unix filesystems if we 1.787 + // open it successfully for writing. 1.788 + 1.789 + PRFileDesc *newFD; 1.790 + rv = newFile->CreateAndKeepOpen(NORMAL_FILE_TYPE, 1.791 + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 1.792 + myPerms, 1.793 + &newFD); 1.794 + if (NS_FAILED(rv)) 1.795 + return rv; 1.796 + 1.797 + // open the old file, too 1.798 + bool specialFile; 1.799 + if (NS_FAILED(rv = IsSpecial(&specialFile))) { 1.800 + PR_Close(newFD); 1.801 + return rv; 1.802 + } 1.803 + if (specialFile) { 1.804 +#ifdef DEBUG 1.805 + printf("Operation not supported: %s\n", mPath.get()); 1.806 +#endif 1.807 + // make sure to clean up properly 1.808 + PR_Close(newFD); 1.809 + return NS_OK; 1.810 + } 1.811 + 1.812 + PRFileDesc *oldFD; 1.813 + rv = OpenNSPRFileDesc(PR_RDONLY, myPerms, &oldFD); 1.814 + if (NS_FAILED(rv)) { 1.815 + // make sure to clean up properly 1.816 + PR_Close(newFD); 1.817 + return rv; 1.818 + } 1.819 + 1.820 +#ifdef DEBUG_blizzard 1.821 + int32_t totalRead = 0; 1.822 + int32_t totalWritten = 0; 1.823 +#endif 1.824 + char buf[BUFSIZ]; 1.825 + int32_t bytesRead; 1.826 + 1.827 + // record PR_Write() error for better error message later. 1.828 + nsresult saved_write_error = NS_OK; 1.829 + nsresult saved_read_error = NS_OK; 1.830 + nsresult saved_read_close_error = NS_OK; 1.831 + nsresult saved_write_close_error = NS_OK; 1.832 + 1.833 + // DONE: Does PR_Read() return bytesRead < 0 for error? 1.834 + // Yes., The errors from PR_Read are not so common and 1.835 + // the value may not have correspondence in NS_ERROR_*, but 1.836 + // we do catch it still, immediately after while() loop. 1.837 + // We can differentiate errors pf PR_Read and PR_Write by 1.838 + // looking at saved_write_error value. If PR_Write error occurs (and not 1.839 + // PR_Read() error), save_write_error is not NS_OK. 1.840 + 1.841 + while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) { 1.842 +#ifdef DEBUG_blizzard 1.843 + totalRead += bytesRead; 1.844 +#endif 1.845 + 1.846 + // PR_Write promises never to do a short write 1.847 + int32_t bytesWritten = PR_Write(newFD, buf, bytesRead); 1.848 + if (bytesWritten < 0) { 1.849 + saved_write_error = NSRESULT_FOR_ERRNO(); 1.850 + bytesRead = -1; 1.851 + break; 1.852 + } 1.853 + NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?"); 1.854 + 1.855 +#ifdef DEBUG_blizzard 1.856 + totalWritten += bytesWritten; 1.857 +#endif 1.858 + } 1.859 + 1.860 + // TODO/FIXME: If CIFS (and NFS?) may force read/write to return EINTR, 1.861 + // we are better off to prepare for retrying. But we need confirmation if 1.862 + // EINTR is returned. 1.863 + 1.864 + // Record error if PR_Read() failed. 1.865 + // Must be done before any other I/O which may reset errno. 1.866 + if ( (bytesRead < 0) && (saved_write_error == NS_OK)) { 1.867 + saved_read_error = NSRESULT_FOR_ERRNO(); 1.868 + } 1.869 + 1.870 +#ifdef DEBUG_blizzard 1.871 + printf("read %d bytes, wrote %d bytes\n", 1.872 + totalRead, totalWritten); 1.873 +#endif 1.874 + 1.875 + // DONE: Errors of close can occur. Read man page of 1.876 + // close(2); 1.877 + // This is likely to happen if the file system is remote file 1.878 + // system (NFS, CIFS, etc.) and network outage occurs. 1.879 + // At least, we should tell the user that filesystem/disk is 1.880 + // hosed (possibly due to network error, hard disk failure, 1.881 + // etc.) so that users can take remedial action. 1.882 + 1.883 + // close the files 1.884 + if (PR_Close(newFD) < 0) { 1.885 + saved_write_close_error = NSRESULT_FOR_ERRNO(); 1.886 +#if DEBUG 1.887 + // This error merits printing. 1.888 + fprintf(stderr, "ERROR: PR_Close(newFD) returned error. errno = %d\n", errno); 1.889 +#endif 1.890 + } 1.891 + 1.892 + if (PR_Close(oldFD) < 0) { 1.893 + saved_read_close_error = NSRESULT_FOR_ERRNO(); 1.894 +#if DEBUG 1.895 + fprintf(stderr, "ERROR: PR_Close(oldFD) returned error. errno = %d\n", errno); 1.896 +#endif 1.897 + } 1.898 + 1.899 + // Let us report the failure to write and read. 1.900 + // check for write/read error after cleaning up 1.901 + if (bytesRead < 0) { 1.902 + if (saved_write_error != NS_OK) 1.903 + return saved_write_error; 1.904 + else if (saved_read_error != NS_OK) 1.905 + return saved_read_error; 1.906 +#if DEBUG 1.907 + else // sanity check. Die and debug. 1.908 + MOZ_ASSERT(0); 1.909 +#endif 1.910 + } 1.911 + 1.912 + if (saved_write_close_error != NS_OK) 1.913 + return saved_write_close_error; 1.914 + if (saved_read_close_error != NS_OK) 1.915 + return saved_read_close_error; 1.916 + } 1.917 + return rv; 1.918 +} 1.919 + 1.920 +NS_IMETHODIMP 1.921 +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParent, const nsACString &newName) 1.922 +{ 1.923 + return CopyToNative(newParent, newName); 1.924 +} 1.925 + 1.926 +NS_IMETHODIMP 1.927 +nsLocalFile::MoveToNative(nsIFile *newParent, const nsACString &newName) 1.928 +{ 1.929 + nsresult rv; 1.930 + 1.931 + // check to make sure that this has been initialized properly 1.932 + CHECK_mPath(); 1.933 + 1.934 + // check to make sure that we have a new parent 1.935 + nsAutoCString newPathName; 1.936 + rv = GetNativeTargetPathName(newParent, newName, newPathName); 1.937 + if (NS_FAILED(rv)) 1.938 + return rv; 1.939 + 1.940 + // try for atomic rename, falling back to copy/delete 1.941 + if (rename(mPath.get(), newPathName.get()) < 0) { 1.942 +#ifdef VMS 1.943 + if (errno == EXDEV || errno == ENXIO) { 1.944 +#else 1.945 + if (errno == EXDEV) { 1.946 +#endif 1.947 + rv = CopyToNative(newParent, newName); 1.948 + if (NS_SUCCEEDED(rv)) 1.949 + rv = Remove(true); 1.950 + } else { 1.951 + rv = NSRESULT_FOR_ERRNO(); 1.952 + } 1.953 + } 1.954 + 1.955 + if (NS_SUCCEEDED(rv)) { 1.956 + // Adjust this 1.957 + mPath = newPathName; 1.958 + } 1.959 + return rv; 1.960 +} 1.961 + 1.962 +NS_IMETHODIMP 1.963 +nsLocalFile::Remove(bool recursive) 1.964 +{ 1.965 + CHECK_mPath(); 1.966 + ENSURE_STAT_CACHE(); 1.967 + 1.968 + bool isSymLink; 1.969 + 1.970 + nsresult rv = IsSymlink(&isSymLink); 1.971 + if (NS_FAILED(rv)) 1.972 + return rv; 1.973 + 1.974 + if (isSymLink || !S_ISDIR(mCachedStat.st_mode)) 1.975 + return NSRESULT_FOR_RETURN(unlink(mPath.get())); 1.976 + 1.977 + if (recursive) { 1.978 + nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); 1.979 + 1.980 + nsCOMPtr<nsISimpleEnumerator> dirRef(dir); // release on exit 1.981 + 1.982 + rv = dir->Init(this, false); 1.983 + if (NS_FAILED(rv)) 1.984 + return rv; 1.985 + 1.986 + bool more; 1.987 + while (dir->HasMoreElements(&more), more) { 1.988 + nsCOMPtr<nsISupports> item; 1.989 + rv = dir->GetNext(getter_AddRefs(item)); 1.990 + if (NS_FAILED(rv)) 1.991 + return NS_ERROR_FAILURE; 1.992 + 1.993 + nsCOMPtr<nsIFile> file = do_QueryInterface(item, &rv); 1.994 + if (NS_FAILED(rv)) 1.995 + return NS_ERROR_FAILURE; 1.996 + rv = file->Remove(recursive); 1.997 + 1.998 +#ifdef ANDROID 1.999 + // See bug 580434 - Bionic gives us just deleted files 1.1000 + if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) 1.1001 + continue; 1.1002 +#endif 1.1003 + if (NS_FAILED(rv)) 1.1004 + return rv; 1.1005 + } 1.1006 + } 1.1007 + 1.1008 + return NSRESULT_FOR_RETURN(rmdir(mPath.get())); 1.1009 +} 1.1010 + 1.1011 +NS_IMETHODIMP 1.1012 +nsLocalFile::GetLastModifiedTime(PRTime *aLastModTime) 1.1013 +{ 1.1014 + CHECK_mPath(); 1.1015 + if (NS_WARN_IF(!aLastModTime)) 1.1016 + return NS_ERROR_INVALID_ARG; 1.1017 + 1.1018 + PRFileInfo64 info; 1.1019 + if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) 1.1020 + return NSRESULT_FOR_ERRNO(); 1.1021 + PRTime modTime = info.modifyTime; 1.1022 + if (modTime == 0) 1.1023 + *aLastModTime = 0; 1.1024 + else 1.1025 + *aLastModTime = modTime / PR_USEC_PER_MSEC; 1.1026 + 1.1027 + return NS_OK; 1.1028 +} 1.1029 + 1.1030 +NS_IMETHODIMP 1.1031 +nsLocalFile::SetLastModifiedTime(PRTime aLastModTime) 1.1032 +{ 1.1033 + CHECK_mPath(); 1.1034 + 1.1035 + int result; 1.1036 + if (aLastModTime != 0) { 1.1037 + ENSURE_STAT_CACHE(); 1.1038 + struct utimbuf ut; 1.1039 + ut.actime = mCachedStat.st_atime; 1.1040 + 1.1041 + // convert milliseconds to seconds since the unix epoch 1.1042 + ut.modtime = (time_t)(aLastModTime / PR_MSEC_PER_SEC); 1.1043 + result = utime(mPath.get(), &ut); 1.1044 + } else { 1.1045 + result = utime(mPath.get(), nullptr); 1.1046 + } 1.1047 + return NSRESULT_FOR_RETURN(result); 1.1048 +} 1.1049 + 1.1050 +NS_IMETHODIMP 1.1051 +nsLocalFile::GetLastModifiedTimeOfLink(PRTime *aLastModTimeOfLink) 1.1052 +{ 1.1053 + CHECK_mPath(); 1.1054 + if (NS_WARN_IF(!aLastModTimeOfLink)) 1.1055 + return NS_ERROR_INVALID_ARG; 1.1056 + 1.1057 + struct STAT sbuf; 1.1058 + if (LSTAT(mPath.get(), &sbuf) == -1) 1.1059 + return NSRESULT_FOR_ERRNO(); 1.1060 + *aLastModTimeOfLink = PRTime(sbuf.st_mtime) * PR_MSEC_PER_SEC; 1.1061 + 1.1062 + return NS_OK; 1.1063 +} 1.1064 + 1.1065 +/* 1.1066 + * utime(2) may or may not dereference symlinks, joy. 1.1067 + */ 1.1068 +NS_IMETHODIMP 1.1069 +nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) 1.1070 +{ 1.1071 + return SetLastModifiedTime(aLastModTimeOfLink); 1.1072 +} 1.1073 + 1.1074 +/* 1.1075 + * Only send back permissions bits: maybe we want to send back the whole 1.1076 + * mode_t to permit checks against other file types? 1.1077 + */ 1.1078 + 1.1079 +#define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO)) 1.1080 + 1.1081 +NS_IMETHODIMP 1.1082 +nsLocalFile::GetPermissions(uint32_t *aPermissions) 1.1083 +{ 1.1084 + if (NS_WARN_IF(!aPermissions)) 1.1085 + return NS_ERROR_INVALID_ARG; 1.1086 + ENSURE_STAT_CACHE(); 1.1087 + *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); 1.1088 + return NS_OK; 1.1089 +} 1.1090 + 1.1091 +NS_IMETHODIMP 1.1092 +nsLocalFile::GetPermissionsOfLink(uint32_t *aPermissionsOfLink) 1.1093 +{ 1.1094 + CHECK_mPath(); 1.1095 + if (NS_WARN_IF(!aPermissionsOfLink)) 1.1096 + return NS_ERROR_INVALID_ARG; 1.1097 + 1.1098 + struct STAT sbuf; 1.1099 + if (LSTAT(mPath.get(), &sbuf) == -1) 1.1100 + return NSRESULT_FOR_ERRNO(); 1.1101 + *aPermissionsOfLink = NORMALIZE_PERMS(sbuf.st_mode); 1.1102 + return NS_OK; 1.1103 +} 1.1104 + 1.1105 +NS_IMETHODIMP 1.1106 +nsLocalFile::SetPermissions(uint32_t aPermissions) 1.1107 +{ 1.1108 + CHECK_mPath(); 1.1109 + 1.1110 + /* 1.1111 + * Race condition here: we should use fchmod instead, there's no way to 1.1112 + * guarantee the name still refers to the same file. 1.1113 + */ 1.1114 + if (chmod(mPath.get(), aPermissions) >= 0) 1.1115 + return NS_OK; 1.1116 +#if defined(ANDROID) && defined(STATFS) 1.1117 + // For the time being, this is restricted for use by Android, but we 1.1118 + // will figure out what to do for all platforms in bug 638503 1.1119 + struct STATFS sfs; 1.1120 + if (STATFS(mPath.get(), &sfs) < 0) 1.1121 + return NSRESULT_FOR_ERRNO(); 1.1122 + 1.1123 + // if this is a FAT file system we can't set file permissions 1.1124 + if (sfs.f_type == MSDOS_SUPER_MAGIC ) 1.1125 + return NS_OK; 1.1126 +#endif 1.1127 + return NSRESULT_FOR_ERRNO(); 1.1128 +} 1.1129 + 1.1130 +NS_IMETHODIMP 1.1131 +nsLocalFile::SetPermissionsOfLink(uint32_t aPermissions) 1.1132 +{ 1.1133 + // There isn't a consistent mechanism for doing this on UNIX platforms. We 1.1134 + // might want to carefully implement this in the future though. 1.1135 + return NS_ERROR_NOT_IMPLEMENTED; 1.1136 +} 1.1137 + 1.1138 +NS_IMETHODIMP 1.1139 +nsLocalFile::GetFileSize(int64_t *aFileSize) 1.1140 +{ 1.1141 + if (NS_WARN_IF(!aFileSize)) 1.1142 + return NS_ERROR_INVALID_ARG; 1.1143 + *aFileSize = 0; 1.1144 + ENSURE_STAT_CACHE(); 1.1145 + 1.1146 +#if defined(VMS) 1.1147 + /* Only two record formats can report correct file content size */ 1.1148 + if ((mCachedStat.st_fab_rfm != FAB$C_STMLF) && 1.1149 + (mCachedStat.st_fab_rfm != FAB$C_STMCR)) { 1.1150 + return NS_ERROR_FAILURE; 1.1151 + } 1.1152 +#endif 1.1153 + 1.1154 + if (!S_ISDIR(mCachedStat.st_mode)) { 1.1155 + *aFileSize = (int64_t)mCachedStat.st_size; 1.1156 + } 1.1157 + return NS_OK; 1.1158 +} 1.1159 + 1.1160 +NS_IMETHODIMP 1.1161 +nsLocalFile::SetFileSize(int64_t aFileSize) 1.1162 +{ 1.1163 + CHECK_mPath(); 1.1164 + 1.1165 +#if defined(ANDROID) 1.1166 + /* no truncate on bionic */ 1.1167 + int fd = open(mPath.get(), O_WRONLY); 1.1168 + if (fd == -1) 1.1169 + return NSRESULT_FOR_ERRNO(); 1.1170 + 1.1171 + int ret = ftruncate(fd, (off_t)aFileSize); 1.1172 + close(fd); 1.1173 + 1.1174 + if (ret == -1) 1.1175 + return NSRESULT_FOR_ERRNO(); 1.1176 +#elif defined(HAVE_TRUNCATE64) 1.1177 + if (truncate64(mPath.get(), (off64_t)aFileSize) == -1) 1.1178 + return NSRESULT_FOR_ERRNO(); 1.1179 +#else 1.1180 + off_t size = (off_t)aFileSize; 1.1181 + if (truncate(mPath.get(), size) == -1) 1.1182 + return NSRESULT_FOR_ERRNO(); 1.1183 +#endif 1.1184 + return NS_OK; 1.1185 +} 1.1186 + 1.1187 +NS_IMETHODIMP 1.1188 +nsLocalFile::GetFileSizeOfLink(int64_t *aFileSize) 1.1189 +{ 1.1190 + CHECK_mPath(); 1.1191 + if (NS_WARN_IF(!aFileSize)) 1.1192 + return NS_ERROR_INVALID_ARG; 1.1193 + 1.1194 + struct STAT sbuf; 1.1195 + if (LSTAT(mPath.get(), &sbuf) == -1) 1.1196 + return NSRESULT_FOR_ERRNO(); 1.1197 + 1.1198 + *aFileSize = (int64_t)sbuf.st_size; 1.1199 + return NS_OK; 1.1200 +} 1.1201 + 1.1202 +#if defined(USE_LINUX_QUOTACTL) 1.1203 +/* 1.1204 + * Searches /proc/self/mountinfo for given device (Major:Minor), 1.1205 + * returns exported name from /dev 1.1206 + * 1.1207 + * Fails when /proc/self/mountinfo or diven device don't exist. 1.1208 + */ 1.1209 +static bool 1.1210 +GetDeviceName(int deviceMajor, int deviceMinor, nsACString &deviceName) 1.1211 +{ 1.1212 + bool ret = false; 1.1213 + 1.1214 + const int kMountInfoLineLength = 200; 1.1215 + const int kMountInfoDevPosition = 6; 1.1216 + 1.1217 + char mountinfo_line[kMountInfoLineLength]; 1.1218 + char device_num[kMountInfoLineLength]; 1.1219 + 1.1220 + snprintf(device_num,kMountInfoLineLength,"%d:%d", deviceMajor, deviceMinor); 1.1221 + 1.1222 + FILE *f = fopen("/proc/self/mountinfo","rt"); 1.1223 + if(!f) 1.1224 + return ret; 1.1225 + 1.1226 + // Expects /proc/self/mountinfo in format: 1.1227 + // 'ID ID major:minor root mountpoint flags - type devicename flags' 1.1228 + while(fgets(mountinfo_line,kMountInfoLineLength,f)) { 1.1229 + char *p_dev = strstr(mountinfo_line,device_num); 1.1230 + 1.1231 + int i; 1.1232 + for(i = 0; i < kMountInfoDevPosition && p_dev != nullptr; i++) { 1.1233 + p_dev = strchr(p_dev,' '); 1.1234 + if(p_dev) 1.1235 + p_dev++; 1.1236 + } 1.1237 + 1.1238 + if(p_dev) { 1.1239 + char *p_dev_end = strchr(p_dev,' '); 1.1240 + if(p_dev_end) { 1.1241 + *p_dev_end = '\0'; 1.1242 + deviceName.Assign(p_dev); 1.1243 + ret = true; 1.1244 + break; 1.1245 + } 1.1246 + } 1.1247 + } 1.1248 + 1.1249 + fclose(f); 1.1250 + return ret; 1.1251 +} 1.1252 +#endif 1.1253 + 1.1254 +NS_IMETHODIMP 1.1255 +nsLocalFile::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) 1.1256 +{ 1.1257 + if (NS_WARN_IF(!aDiskSpaceAvailable)) 1.1258 + return NS_ERROR_INVALID_ARG; 1.1259 + 1.1260 + // These systems have the operations necessary to check disk space. 1.1261 + 1.1262 +#ifdef STATFS 1.1263 + 1.1264 + // check to make sure that mPath is properly initialized 1.1265 + CHECK_mPath(); 1.1266 + 1.1267 + struct STATFS fs_buf; 1.1268 + 1.1269 + /* 1.1270 + * Members of the STATFS struct that you should know about: 1.1271 + * F_BSIZE = block size on disk. 1.1272 + * f_bavail = number of free blocks available to a non-superuser. 1.1273 + * f_bfree = number of total free blocks in file system. 1.1274 + */ 1.1275 + 1.1276 + if (STATFS(mPath.get(), &fs_buf) < 0) { 1.1277 + // The call to STATFS failed. 1.1278 +#ifdef DEBUG 1.1279 + printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n"); 1.1280 +#endif 1.1281 + return NS_ERROR_FAILURE; 1.1282 + } 1.1283 + 1.1284 + *aDiskSpaceAvailable = (int64_t) fs_buf.F_BSIZE * fs_buf.f_bavail; 1.1285 + 1.1286 +#ifdef DEBUG_DISK_SPACE 1.1287 + printf("DiskSpaceAvailable: %lu bytes\n", 1.1288 + *aDiskSpaceAvailable); 1.1289 +#endif 1.1290 + 1.1291 +#if defined(USE_LINUX_QUOTACTL) 1.1292 + 1.1293 + if(!FillStatCache()) { 1.1294 + // Return available size from statfs 1.1295 + return NS_OK; 1.1296 + } 1.1297 + 1.1298 + nsCString deviceName; 1.1299 + if(!GetDeviceName(major(mCachedStat.st_dev), minor(mCachedStat.st_dev), deviceName)) { 1.1300 + return NS_OK; 1.1301 + } 1.1302 + 1.1303 + struct dqblk dq; 1.1304 + if(!quotactl(QCMD(Q_GETQUOTA, USRQUOTA), deviceName.get(), getuid(), (caddr_t)&dq) 1.1305 +#ifdef QIF_BLIMITS 1.1306 + && dq.dqb_valid & QIF_BLIMITS 1.1307 +#endif 1.1308 + && dq.dqb_bhardlimit) 1.1309 + { 1.1310 + int64_t QuotaSpaceAvailable = 0; 1.1311 + if (dq.dqb_bhardlimit > dq.dqb_curspace) 1.1312 + QuotaSpaceAvailable = int64_t(fs_buf.F_BSIZE * (dq.dqb_bhardlimit - dq.dqb_curspace)); 1.1313 + if(QuotaSpaceAvailable < *aDiskSpaceAvailable) { 1.1314 + *aDiskSpaceAvailable = QuotaSpaceAvailable; 1.1315 + } 1.1316 + } 1.1317 +#endif 1.1318 + 1.1319 + return NS_OK; 1.1320 + 1.1321 +#else 1.1322 + /* 1.1323 + * This platform doesn't have statfs or statvfs. I'm sure that there's 1.1324 + * a way to check for free disk space on platforms that don't have statfs 1.1325 + * (I'm SURE they have df, for example). 1.1326 + * 1.1327 + * Until we figure out how to do that, lets be honest and say that this 1.1328 + * command isn't implemented properly for these platforms yet. 1.1329 + */ 1.1330 +#ifdef DEBUG 1.1331 + printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n"); 1.1332 +#endif 1.1333 + return NS_ERROR_NOT_IMPLEMENTED; 1.1334 + 1.1335 +#endif /* STATFS */ 1.1336 + 1.1337 +} 1.1338 + 1.1339 +NS_IMETHODIMP 1.1340 +nsLocalFile::GetParent(nsIFile **aParent) 1.1341 +{ 1.1342 + CHECK_mPath(); 1.1343 + if (NS_WARN_IF(!aParent)) 1.1344 + return NS_ERROR_INVALID_ARG; 1.1345 + *aParent = nullptr; 1.1346 + 1.1347 + // if '/' we are at the top of the volume, return null 1.1348 + if (mPath.Equals("/")) 1.1349 + return NS_OK; 1.1350 + 1.1351 + // <brendan, after jband> I promise to play nice 1.1352 + char *buffer = mPath.BeginWriting(), 1.1353 + *slashp = buffer; 1.1354 + 1.1355 + // find the last significant slash in buffer 1.1356 + slashp = strrchr(buffer, '/'); 1.1357 + NS_ASSERTION(slashp, "non-canonical path?"); 1.1358 + if (!slashp) 1.1359 + return NS_ERROR_FILE_INVALID_PATH; 1.1360 + 1.1361 + // for the case where we are at '/' 1.1362 + if (slashp == buffer) 1.1363 + slashp++; 1.1364 + 1.1365 + // temporarily terminate buffer at the last significant slash 1.1366 + char c = *slashp; 1.1367 + *slashp = '\0'; 1.1368 + 1.1369 + nsCOMPtr<nsIFile> localFile; 1.1370 + nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buffer), true, 1.1371 + getter_AddRefs(localFile)); 1.1372 + 1.1373 + // make buffer whole again 1.1374 + *slashp = c; 1.1375 + 1.1376 + if (NS_FAILED(rv)) { 1.1377 + return rv; 1.1378 + } 1.1379 + 1.1380 + localFile.forget(aParent); 1.1381 + return NS_OK; 1.1382 +} 1.1383 + 1.1384 +/* 1.1385 + * The results of Exists, isWritable and isReadable are not cached. 1.1386 + */ 1.1387 + 1.1388 + 1.1389 +NS_IMETHODIMP 1.1390 +nsLocalFile::Exists(bool *_retval) 1.1391 +{ 1.1392 + CHECK_mPath(); 1.1393 + if (NS_WARN_IF(!_retval)) 1.1394 + return NS_ERROR_INVALID_ARG; 1.1395 + 1.1396 + *_retval = (access(mPath.get(), F_OK) == 0); 1.1397 + return NS_OK; 1.1398 +} 1.1399 + 1.1400 + 1.1401 +NS_IMETHODIMP 1.1402 +nsLocalFile::IsWritable(bool *_retval) 1.1403 +{ 1.1404 + CHECK_mPath(); 1.1405 + if (NS_WARN_IF(!_retval)) 1.1406 + return NS_ERROR_INVALID_ARG; 1.1407 + 1.1408 + *_retval = (access(mPath.get(), W_OK) == 0); 1.1409 + if (*_retval || errno == EACCES) 1.1410 + return NS_OK; 1.1411 + return NSRESULT_FOR_ERRNO(); 1.1412 +} 1.1413 + 1.1414 +NS_IMETHODIMP 1.1415 +nsLocalFile::IsReadable(bool *_retval) 1.1416 +{ 1.1417 + CHECK_mPath(); 1.1418 + if (NS_WARN_IF(!_retval)) 1.1419 + return NS_ERROR_INVALID_ARG; 1.1420 + 1.1421 + *_retval = (access(mPath.get(), R_OK) == 0); 1.1422 + if (*_retval || errno == EACCES) 1.1423 + return NS_OK; 1.1424 + return NSRESULT_FOR_ERRNO(); 1.1425 +} 1.1426 + 1.1427 +NS_IMETHODIMP 1.1428 +nsLocalFile::IsExecutable(bool *_retval) 1.1429 +{ 1.1430 + CHECK_mPath(); 1.1431 + if (NS_WARN_IF(!_retval)) 1.1432 + return NS_ERROR_INVALID_ARG; 1.1433 + 1.1434 + // Check extension (bug 663899). On certain platforms, the file 1.1435 + // extension may cause the OS to treat it as executable regardless of 1.1436 + // the execute bit, such as .jar on Mac OS X. We borrow the code from 1.1437 + // nsLocalFileWin, slightly modified. 1.1438 + 1.1439 + // Don't be fooled by symlinks. 1.1440 + bool symLink; 1.1441 + nsresult rv = IsSymlink(&symLink); 1.1442 + if (NS_FAILED(rv)) 1.1443 + return rv; 1.1444 + 1.1445 + nsAutoString path; 1.1446 + if (symLink) 1.1447 + GetTarget(path); 1.1448 + else 1.1449 + GetPath(path); 1.1450 + 1.1451 + int32_t dotIdx = path.RFindChar(char16_t('.')); 1.1452 + if (dotIdx != kNotFound) { 1.1453 + // Convert extension to lower case. 1.1454 + char16_t *p = path.BeginWriting(); 1.1455 + for(p += dotIdx + 1; *p; p++) 1.1456 + *p += (*p >= L'A' && *p <= L'Z') ? 'a' - 'A' : 0; 1.1457 + 1.1458 + // Search for any of the set of executable extensions. 1.1459 + static const char * const executableExts[] = { 1.1460 + "air", // Adobe AIR installer 1.1461 + "jar"}; // java application bundle 1.1462 + nsDependentSubstring ext = Substring(path, dotIdx + 1); 1.1463 + for (size_t i = 0; i < ArrayLength(executableExts); i++) { 1.1464 + if (ext.EqualsASCII(executableExts[i])) { 1.1465 + // Found a match. Set result and quit. 1.1466 + *_retval = true; 1.1467 + return NS_OK; 1.1468 + } 1.1469 + } 1.1470 + } 1.1471 + 1.1472 + // On OS X, then query Launch Services. 1.1473 +#ifdef MOZ_WIDGET_COCOA 1.1474 + // Certain Mac applications, such as Classic applications, which 1.1475 + // run under Rosetta, might not have the +x mode bit but are still 1.1476 + // considered to be executable by Launch Services (bug 646748). 1.1477 + CFURLRef url; 1.1478 + if (NS_FAILED(GetCFURL(&url))) { 1.1479 + return NS_ERROR_FAILURE; 1.1480 + } 1.1481 + 1.1482 + LSRequestedInfo theInfoRequest = kLSRequestAllInfo; 1.1483 + LSItemInfoRecord theInfo; 1.1484 + OSStatus result = ::LSCopyItemInfoForURL(url, theInfoRequest, &theInfo); 1.1485 + ::CFRelease(url); 1.1486 + if (result == noErr) { 1.1487 + if ((theInfo.flags & kLSItemInfoIsApplication) != 0) { 1.1488 + *_retval = true; 1.1489 + return NS_OK; 1.1490 + } 1.1491 + } 1.1492 +#endif 1.1493 + 1.1494 + // Then check the execute bit. 1.1495 + *_retval = (access(mPath.get(), X_OK) == 0); 1.1496 +#ifdef SOLARIS 1.1497 + // On Solaris, access will always return 0 for root user, however 1.1498 + // the file is only executable if S_IXUSR | S_IXGRP | S_IXOTH is set. 1.1499 + // See bug 351950, https://bugzilla.mozilla.org/show_bug.cgi?id=351950 1.1500 + if (*_retval) { 1.1501 + struct STAT buf; 1.1502 + 1.1503 + *_retval = (STAT(mPath.get(), &buf) == 0); 1.1504 + if (*_retval || errno == EACCES) { 1.1505 + *_retval = *_retval && 1.1506 + (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH )); 1.1507 + return NS_OK; 1.1508 + } 1.1509 + 1.1510 + return NSRESULT_FOR_ERRNO(); 1.1511 + } 1.1512 +#endif 1.1513 + if (*_retval || errno == EACCES) 1.1514 + return NS_OK; 1.1515 + return NSRESULT_FOR_ERRNO(); 1.1516 +} 1.1517 + 1.1518 +NS_IMETHODIMP 1.1519 +nsLocalFile::IsDirectory(bool *_retval) 1.1520 +{ 1.1521 + if (NS_WARN_IF(!_retval)) 1.1522 + return NS_ERROR_INVALID_ARG; 1.1523 + *_retval = false; 1.1524 + ENSURE_STAT_CACHE(); 1.1525 + *_retval = S_ISDIR(mCachedStat.st_mode); 1.1526 + return NS_OK; 1.1527 +} 1.1528 + 1.1529 +NS_IMETHODIMP 1.1530 +nsLocalFile::IsFile(bool *_retval) 1.1531 +{ 1.1532 + if (NS_WARN_IF(!_retval)) 1.1533 + return NS_ERROR_INVALID_ARG; 1.1534 + *_retval = false; 1.1535 + ENSURE_STAT_CACHE(); 1.1536 + *_retval = S_ISREG(mCachedStat.st_mode); 1.1537 + return NS_OK; 1.1538 +} 1.1539 + 1.1540 +NS_IMETHODIMP 1.1541 +nsLocalFile::IsHidden(bool *_retval) 1.1542 +{ 1.1543 + if (NS_WARN_IF(!_retval)) 1.1544 + return NS_ERROR_INVALID_ARG; 1.1545 + nsACString::const_iterator begin, end; 1.1546 + LocateNativeLeafName(begin, end); 1.1547 + *_retval = (*begin == '.'); 1.1548 + return NS_OK; 1.1549 +} 1.1550 + 1.1551 +NS_IMETHODIMP 1.1552 +nsLocalFile::IsSymlink(bool *_retval) 1.1553 +{ 1.1554 + if (NS_WARN_IF(!_retval)) 1.1555 + return NS_ERROR_INVALID_ARG; 1.1556 + CHECK_mPath(); 1.1557 + 1.1558 + struct STAT symStat; 1.1559 + if (LSTAT(mPath.get(), &symStat) == -1) 1.1560 + return NSRESULT_FOR_ERRNO(); 1.1561 + *_retval=S_ISLNK(symStat.st_mode); 1.1562 + return NS_OK; 1.1563 +} 1.1564 + 1.1565 +NS_IMETHODIMP 1.1566 +nsLocalFile::IsSpecial(bool *_retval) 1.1567 +{ 1.1568 + if (NS_WARN_IF(!_retval)) 1.1569 + return NS_ERROR_INVALID_ARG; 1.1570 + ENSURE_STAT_CACHE(); 1.1571 + *_retval = S_ISCHR(mCachedStat.st_mode) || 1.1572 + S_ISBLK(mCachedStat.st_mode) || 1.1573 +#ifdef S_ISSOCK 1.1574 + S_ISSOCK(mCachedStat.st_mode) || 1.1575 +#endif 1.1576 + S_ISFIFO(mCachedStat.st_mode); 1.1577 + 1.1578 + return NS_OK; 1.1579 +} 1.1580 + 1.1581 +NS_IMETHODIMP 1.1582 +nsLocalFile::Equals(nsIFile *inFile, bool *_retval) 1.1583 +{ 1.1584 + if (NS_WARN_IF(!inFile)) 1.1585 + return NS_ERROR_INVALID_ARG; 1.1586 + if (NS_WARN_IF(!_retval)) 1.1587 + return NS_ERROR_INVALID_ARG; 1.1588 + *_retval = false; 1.1589 + 1.1590 + nsAutoCString inPath; 1.1591 + nsresult rv = inFile->GetNativePath(inPath); 1.1592 + if (NS_FAILED(rv)) 1.1593 + return rv; 1.1594 + 1.1595 + // We don't need to worry about "/foo/" vs. "/foo" here 1.1596 + // because trailing slashes are stripped on init. 1.1597 + *_retval = !strcmp(inPath.get(), mPath.get()); 1.1598 + return NS_OK; 1.1599 +} 1.1600 + 1.1601 +NS_IMETHODIMP 1.1602 +nsLocalFile::Contains(nsIFile *inFile, bool recur, bool *_retval) 1.1603 +{ 1.1604 + CHECK_mPath(); 1.1605 + if (NS_WARN_IF(!inFile)) 1.1606 + return NS_ERROR_INVALID_ARG; 1.1607 + if (NS_WARN_IF(!_retval)) 1.1608 + return NS_ERROR_INVALID_ARG; 1.1609 + 1.1610 + nsAutoCString inPath; 1.1611 + nsresult rv; 1.1612 + 1.1613 + if (NS_FAILED(rv = inFile->GetNativePath(inPath))) 1.1614 + return rv; 1.1615 + 1.1616 + *_retval = false; 1.1617 + 1.1618 + ssize_t len = mPath.Length(); 1.1619 + if (strncmp(mPath.get(), inPath.get(), len) == 0) { 1.1620 + // Now make sure that the |inFile|'s path has a separator at len, 1.1621 + // which implies that it has more components after len. 1.1622 + if (inPath[len] == '/') 1.1623 + *_retval = true; 1.1624 + } 1.1625 + 1.1626 + return NS_OK; 1.1627 +} 1.1628 + 1.1629 +NS_IMETHODIMP 1.1630 +nsLocalFile::GetNativeTarget(nsACString &_retval) 1.1631 +{ 1.1632 + CHECK_mPath(); 1.1633 + _retval.Truncate(); 1.1634 + 1.1635 + struct STAT symStat; 1.1636 + if (LSTAT(mPath.get(), &symStat) == -1) 1.1637 + return NSRESULT_FOR_ERRNO(); 1.1638 + 1.1639 + if (!S_ISLNK(symStat.st_mode)) 1.1640 + return NS_ERROR_FILE_INVALID_PATH; 1.1641 + 1.1642 + int32_t size = (int32_t)symStat.st_size; 1.1643 + char *target = (char *)nsMemory::Alloc(size + 1); 1.1644 + if (!target) 1.1645 + return NS_ERROR_OUT_OF_MEMORY; 1.1646 + 1.1647 + if (readlink(mPath.get(), target, (size_t)size) < 0) { 1.1648 + nsMemory::Free(target); 1.1649 + return NSRESULT_FOR_ERRNO(); 1.1650 + } 1.1651 + target[size] = '\0'; 1.1652 + 1.1653 + nsresult rv = NS_OK; 1.1654 + nsCOMPtr<nsIFile> self(this); 1.1655 + int32_t maxLinks = 40; 1.1656 + while (true) { 1.1657 + if (maxLinks-- == 0) { 1.1658 + rv = NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; 1.1659 + break; 1.1660 + } 1.1661 + 1.1662 + if (target[0] != '/') { 1.1663 + nsCOMPtr<nsIFile> parent; 1.1664 + if (NS_FAILED(rv = self->GetParent(getter_AddRefs(parent)))) 1.1665 + break; 1.1666 + if (NS_FAILED(rv = parent->AppendRelativeNativePath(nsDependentCString(target)))) 1.1667 + break; 1.1668 + if (NS_FAILED(rv = parent->GetNativePath(_retval))) 1.1669 + break; 1.1670 + self = parent; 1.1671 + } else { 1.1672 + _retval = target; 1.1673 + } 1.1674 + 1.1675 + const nsPromiseFlatCString &flatRetval = PromiseFlatCString(_retval); 1.1676 + 1.1677 + // Any failure in testing the current target we'll just interpret 1.1678 + // as having reached our destiny. 1.1679 + if (LSTAT(flatRetval.get(), &symStat) == -1) 1.1680 + break; 1.1681 + 1.1682 + // And of course we're done if it isn't a symlink. 1.1683 + if (!S_ISLNK(symStat.st_mode)) 1.1684 + break; 1.1685 + 1.1686 + int32_t newSize = (int32_t)symStat.st_size; 1.1687 + if (newSize > size) { 1.1688 + char *newTarget = (char *)nsMemory::Realloc(target, newSize + 1); 1.1689 + if (!newTarget) { 1.1690 + rv = NS_ERROR_OUT_OF_MEMORY; 1.1691 + break; 1.1692 + } 1.1693 + target = newTarget; 1.1694 + size = newSize; 1.1695 + } 1.1696 + 1.1697 + int32_t linkLen = readlink(flatRetval.get(), target, size); 1.1698 + if (linkLen == -1) { 1.1699 + rv = NSRESULT_FOR_ERRNO(); 1.1700 + break; 1.1701 + } 1.1702 + target[linkLen] = '\0'; 1.1703 + } 1.1704 + 1.1705 + nsMemory::Free(target); 1.1706 + 1.1707 + if (NS_FAILED(rv)) 1.1708 + _retval.Truncate(); 1.1709 + return rv; 1.1710 +} 1.1711 + 1.1712 +NS_IMETHODIMP 1.1713 +nsLocalFile::GetFollowLinks(bool *aFollowLinks) 1.1714 +{ 1.1715 + *aFollowLinks = true; 1.1716 + return NS_OK; 1.1717 +} 1.1718 + 1.1719 +NS_IMETHODIMP 1.1720 +nsLocalFile::SetFollowLinks(bool aFollowLinks) 1.1721 +{ 1.1722 + return NS_OK; 1.1723 +} 1.1724 + 1.1725 +NS_IMETHODIMP 1.1726 +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries) 1.1727 +{ 1.1728 + nsRefPtr<nsDirEnumeratorUnix> dir = new nsDirEnumeratorUnix(); 1.1729 + 1.1730 + nsresult rv = dir->Init(this, false); 1.1731 + if (NS_FAILED(rv)) { 1.1732 + *entries = nullptr; 1.1733 + } else { 1.1734 + dir.forget(entries); 1.1735 + } 1.1736 + 1.1737 + return rv; 1.1738 +} 1.1739 + 1.1740 +NS_IMETHODIMP 1.1741 +nsLocalFile::Load(PRLibrary **_retval) 1.1742 +{ 1.1743 + CHECK_mPath(); 1.1744 + if (NS_WARN_IF(!_retval)) 1.1745 + return NS_ERROR_INVALID_ARG; 1.1746 + 1.1747 +#ifdef NS_BUILD_REFCNT_LOGGING 1.1748 + nsTraceRefcnt::SetActivityIsLegal(false); 1.1749 +#endif 1.1750 + 1.1751 + *_retval = PR_LoadLibrary(mPath.get()); 1.1752 + 1.1753 +#ifdef NS_BUILD_REFCNT_LOGGING 1.1754 + nsTraceRefcnt::SetActivityIsLegal(true); 1.1755 +#endif 1.1756 + 1.1757 + if (!*_retval) 1.1758 + return NS_ERROR_FAILURE; 1.1759 + return NS_OK; 1.1760 +} 1.1761 + 1.1762 +NS_IMETHODIMP 1.1763 +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) 1.1764 +{ 1.1765 + return GetNativePath(aPersistentDescriptor); 1.1766 +} 1.1767 + 1.1768 +NS_IMETHODIMP 1.1769 +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) 1.1770 +{ 1.1771 +#ifdef MOZ_WIDGET_COCOA 1.1772 + if (aPersistentDescriptor.IsEmpty()) 1.1773 + return NS_ERROR_INVALID_ARG; 1.1774 + 1.1775 + // Support pathnames as user-supplied descriptors if they begin with '/' 1.1776 + // or '~'. These characters do not collide with the base64 set used for 1.1777 + // encoding alias records. 1.1778 + char first = aPersistentDescriptor.First(); 1.1779 + if (first == '/' || first == '~') 1.1780 + return InitWithNativePath(aPersistentDescriptor); 1.1781 + 1.1782 + uint32_t dataSize = aPersistentDescriptor.Length(); 1.1783 + char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nullptr); 1.1784 + if (!decodedData) { 1.1785 + NS_ERROR("SetPersistentDescriptor was given bad data"); 1.1786 + return NS_ERROR_FAILURE; 1.1787 + } 1.1788 + 1.1789 + // Cast to an alias record and resolve. 1.1790 + AliasRecord aliasHeader = *(AliasPtr)decodedData; 1.1791 + int32_t aliasSize = ::GetAliasSizeFromPtr(&aliasHeader); 1.1792 + if (aliasSize > ((int32_t)dataSize * 3) / 4) { // be paranoid about having too few data 1.1793 + PR_Free(decodedData); 1.1794 + return NS_ERROR_FAILURE; 1.1795 + } 1.1796 + 1.1797 + nsresult rv = NS_OK; 1.1798 + 1.1799 + // Move the now-decoded data into the Handle. 1.1800 + // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h 1.1801 + Handle newHandle = nullptr; 1.1802 + if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr) 1.1803 + rv = NS_ERROR_OUT_OF_MEMORY; 1.1804 + PR_Free(decodedData); 1.1805 + if (NS_FAILED(rv)) 1.1806 + return rv; 1.1807 + 1.1808 + Boolean changed; 1.1809 + FSRef resolvedFSRef; 1.1810 + OSErr err = ::FSResolveAlias(nullptr, (AliasHandle)newHandle, &resolvedFSRef, &changed); 1.1811 + 1.1812 + rv = MacErrorMapper(err); 1.1813 + DisposeHandle(newHandle); 1.1814 + if (NS_FAILED(rv)) 1.1815 + return rv; 1.1816 + 1.1817 + return InitWithFSRef(&resolvedFSRef); 1.1818 +#else 1.1819 + return InitWithNativePath(aPersistentDescriptor); 1.1820 +#endif 1.1821 +} 1.1822 + 1.1823 +NS_IMETHODIMP 1.1824 +nsLocalFile::Reveal() 1.1825 +{ 1.1826 +#ifdef MOZ_WIDGET_GTK 1.1827 + nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); 1.1828 + nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID); 1.1829 + if (!giovfs && !gnomevfs) 1.1830 + return NS_ERROR_FAILURE; 1.1831 + 1.1832 + bool isDirectory; 1.1833 + if (NS_FAILED(IsDirectory(&isDirectory))) 1.1834 + return NS_ERROR_FAILURE; 1.1835 + 1.1836 + if (isDirectory) { 1.1837 + if (giovfs) 1.1838 + return giovfs->ShowURIForInput(mPath); 1.1839 + else 1.1840 + /* Fallback to GnomeVFS */ 1.1841 + return gnomevfs->ShowURIForInput(mPath); 1.1842 + } else if (giovfs && NS_SUCCEEDED(giovfs->OrgFreedesktopFileManager1ShowItems(mPath))) { 1.1843 + return NS_OK; 1.1844 + } else { 1.1845 + nsCOMPtr<nsIFile> parentDir; 1.1846 + nsAutoCString dirPath; 1.1847 + if (NS_FAILED(GetParent(getter_AddRefs(parentDir)))) 1.1848 + return NS_ERROR_FAILURE; 1.1849 + if (NS_FAILED(parentDir->GetNativePath(dirPath))) 1.1850 + return NS_ERROR_FAILURE; 1.1851 + 1.1852 + if (giovfs) 1.1853 + return giovfs->ShowURIForInput(dirPath); 1.1854 + else 1.1855 + return gnomevfs->ShowURIForInput(dirPath); 1.1856 + } 1.1857 +#elif defined(MOZ_WIDGET_COCOA) 1.1858 + CFURLRef url; 1.1859 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.1860 + nsresult rv = CocoaFileUtils::RevealFileInFinder(url); 1.1861 + ::CFRelease(url); 1.1862 + return rv; 1.1863 + } 1.1864 + return NS_ERROR_FAILURE; 1.1865 +#else 1.1866 + return NS_ERROR_FAILURE; 1.1867 +#endif 1.1868 +} 1.1869 + 1.1870 +NS_IMETHODIMP 1.1871 +nsLocalFile::Launch() 1.1872 +{ 1.1873 +#ifdef MOZ_WIDGET_GTK 1.1874 + nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); 1.1875 + nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID); 1.1876 + if (giovfs) { 1.1877 + return giovfs->ShowURIForInput(mPath); 1.1878 + } else if (gnomevfs) { 1.1879 + /* GnomeVFS fallback */ 1.1880 + return gnomevfs->ShowURIForInput(mPath); 1.1881 + } 1.1882 + 1.1883 + return NS_ERROR_FAILURE; 1.1884 +#elif defined(MOZ_ENABLE_CONTENTACTION) 1.1885 + QUrl uri = QUrl::fromLocalFile(QString::fromUtf8(mPath.get())); 1.1886 + ContentAction::Action action = 1.1887 + ContentAction::Action::defaultActionForFile(uri); 1.1888 + 1.1889 + if (action.isValid()) { 1.1890 + action.trigger(); 1.1891 + return NS_OK; 1.1892 + } 1.1893 + 1.1894 + return NS_ERROR_FAILURE; 1.1895 +#elif defined(MOZ_WIDGET_ANDROID) 1.1896 + // Try to get a mimetype, if this fails just use the file uri alone 1.1897 + nsresult rv; 1.1898 + nsAutoCString type; 1.1899 + nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv)); 1.1900 + if (NS_SUCCEEDED(rv)) 1.1901 + rv = mimeService->GetTypeFromFile(this, type); 1.1902 + 1.1903 + nsAutoCString fileUri = NS_LITERAL_CSTRING("file://") + mPath; 1.1904 + return mozilla::widget::android::GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(fileUri), 1.1905 + NS_ConvertUTF8toUTF16(type)) ? NS_OK : NS_ERROR_FAILURE; 1.1906 +#elif defined(MOZ_WIDGET_COCOA) 1.1907 + CFURLRef url; 1.1908 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.1909 + nsresult rv = CocoaFileUtils::OpenURL(url); 1.1910 + ::CFRelease(url); 1.1911 + return rv; 1.1912 + } 1.1913 + return NS_ERROR_FAILURE; 1.1914 +#else 1.1915 + return NS_ERROR_FAILURE; 1.1916 +#endif 1.1917 +} 1.1918 + 1.1919 +nsresult 1.1920 +NS_NewNativeLocalFile(const nsACString &path, bool followSymlinks, nsIFile **result) 1.1921 +{ 1.1922 + nsRefPtr<nsLocalFile> file = new nsLocalFile(); 1.1923 + 1.1924 + file->SetFollowLinks(followSymlinks); 1.1925 + 1.1926 + if (!path.IsEmpty()) { 1.1927 + nsresult rv = file->InitWithNativePath(path); 1.1928 + if (NS_FAILED(rv)) { 1.1929 + return rv; 1.1930 + } 1.1931 + } 1.1932 + file.forget(result); 1.1933 + return NS_OK; 1.1934 +} 1.1935 + 1.1936 +//----------------------------------------------------------------------------- 1.1937 +// unicode support 1.1938 +//----------------------------------------------------------------------------- 1.1939 + 1.1940 +#define SET_UCS(func, ucsArg) \ 1.1941 + { \ 1.1942 + nsAutoCString buf; \ 1.1943 + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ 1.1944 + if (NS_FAILED(rv)) \ 1.1945 + return rv; \ 1.1946 + return (func)(buf); \ 1.1947 + } 1.1948 + 1.1949 +#define GET_UCS(func, ucsArg) \ 1.1950 + { \ 1.1951 + nsAutoCString buf; \ 1.1952 + nsresult rv = (func)(buf); \ 1.1953 + if (NS_FAILED(rv)) return rv; \ 1.1954 + return NS_CopyNativeToUnicode(buf, ucsArg); \ 1.1955 + } 1.1956 + 1.1957 +#define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \ 1.1958 + { \ 1.1959 + nsAutoCString buf; \ 1.1960 + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ 1.1961 + if (NS_FAILED(rv)) \ 1.1962 + return rv; \ 1.1963 + return (func)(opaqueArg, buf); \ 1.1964 + } 1.1965 + 1.1966 +// Unicode interface Wrapper 1.1967 +nsresult 1.1968 +nsLocalFile::InitWithPath(const nsAString &filePath) 1.1969 +{ 1.1970 + SET_UCS(InitWithNativePath, filePath); 1.1971 +} 1.1972 +nsresult 1.1973 +nsLocalFile::Append(const nsAString &node) 1.1974 +{ 1.1975 + SET_UCS(AppendNative, node); 1.1976 +} 1.1977 +nsresult 1.1978 +nsLocalFile::AppendRelativePath(const nsAString &node) 1.1979 +{ 1.1980 + SET_UCS(AppendRelativeNativePath, node); 1.1981 +} 1.1982 +nsresult 1.1983 +nsLocalFile::GetLeafName(nsAString &aLeafName) 1.1984 +{ 1.1985 + GET_UCS(GetNativeLeafName, aLeafName); 1.1986 +} 1.1987 +nsresult 1.1988 +nsLocalFile::SetLeafName(const nsAString &aLeafName) 1.1989 +{ 1.1990 + SET_UCS(SetNativeLeafName, aLeafName); 1.1991 +} 1.1992 +nsresult 1.1993 +nsLocalFile::GetPath(nsAString &_retval) 1.1994 +{ 1.1995 + return NS_CopyNativeToUnicode(mPath, _retval); 1.1996 +} 1.1997 +nsresult 1.1998 +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) 1.1999 +{ 1.2000 + SET_UCS_2ARGS_2(CopyToNative , newParentDir, newName); 1.2001 +} 1.2002 +nsresult 1.2003 +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) 1.2004 +{ 1.2005 + SET_UCS_2ARGS_2(CopyToFollowingLinksNative , newParentDir, newName); 1.2006 +} 1.2007 +nsresult 1.2008 +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) 1.2009 +{ 1.2010 + SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName); 1.2011 +} 1.2012 + 1.2013 +NS_IMETHODIMP 1.2014 +nsLocalFile::RenameTo(nsIFile *newParentDir, const nsAString &newName) 1.2015 +{ 1.2016 + nsresult rv; 1.2017 + 1.2018 + // check to make sure that this has been initialized properly 1.2019 + CHECK_mPath(); 1.2020 + 1.2021 + // check to make sure that we have a new parent 1.2022 + nsAutoCString newPathName; 1.2023 + nsAutoCString newNativeName; 1.2024 + rv = NS_CopyUnicodeToNative(newName, newNativeName); 1.2025 + if (NS_FAILED(rv)) { 1.2026 + return rv; 1.2027 + } 1.2028 + rv = GetNativeTargetPathName(newParentDir, newNativeName, newPathName); 1.2029 + if (NS_FAILED(rv)) { 1.2030 + return rv; 1.2031 + } 1.2032 + 1.2033 + // try for atomic rename 1.2034 + if (rename(mPath.get(), newPathName.get()) < 0) { 1.2035 +#ifdef VMS 1.2036 + if (errno == EXDEV || errno == ENXIO) { 1.2037 +#else 1.2038 + if (errno == EXDEV) { 1.2039 +#endif 1.2040 + rv = NS_ERROR_FILE_ACCESS_DENIED; 1.2041 + } else { 1.2042 + rv = NSRESULT_FOR_ERRNO(); 1.2043 + } 1.2044 + } 1.2045 + 1.2046 + return rv; 1.2047 +} 1.2048 + 1.2049 +nsresult 1.2050 +nsLocalFile::GetTarget(nsAString &_retval) 1.2051 +{ 1.2052 + GET_UCS(GetNativeTarget, _retval); 1.2053 +} 1.2054 + 1.2055 +// nsIHashable 1.2056 + 1.2057 +NS_IMETHODIMP 1.2058 +nsLocalFile::Equals(nsIHashable* aOther, bool *aResult) 1.2059 +{ 1.2060 + nsCOMPtr<nsIFile> otherFile(do_QueryInterface(aOther)); 1.2061 + if (!otherFile) { 1.2062 + *aResult = false; 1.2063 + return NS_OK; 1.2064 + } 1.2065 + 1.2066 + return Equals(otherFile, aResult); 1.2067 +} 1.2068 + 1.2069 +NS_IMETHODIMP 1.2070 +nsLocalFile::GetHashCode(uint32_t *aResult) 1.2071 +{ 1.2072 + *aResult = HashString(mPath); 1.2073 + return NS_OK; 1.2074 +} 1.2075 + 1.2076 +nsresult 1.2077 +NS_NewLocalFile(const nsAString &path, bool followLinks, nsIFile* *result) 1.2078 +{ 1.2079 + nsAutoCString buf; 1.2080 + nsresult rv = NS_CopyUnicodeToNative(path, buf); 1.2081 + if (NS_FAILED(rv)) 1.2082 + return rv; 1.2083 + return NS_NewNativeLocalFile(buf, followLinks, result); 1.2084 +} 1.2085 + 1.2086 +//----------------------------------------------------------------------------- 1.2087 +// global init/shutdown 1.2088 +//----------------------------------------------------------------------------- 1.2089 + 1.2090 +void 1.2091 +nsLocalFile::GlobalInit() 1.2092 +{ 1.2093 +} 1.2094 + 1.2095 +void 1.2096 +nsLocalFile::GlobalShutdown() 1.2097 +{ 1.2098 +} 1.2099 + 1.2100 +// nsILocalFileMac 1.2101 + 1.2102 +#ifdef MOZ_WIDGET_COCOA 1.2103 + 1.2104 +static nsresult MacErrorMapper(OSErr inErr) 1.2105 +{ 1.2106 + nsresult outErr; 1.2107 + 1.2108 + switch (inErr) 1.2109 + { 1.2110 + case noErr: 1.2111 + outErr = NS_OK; 1.2112 + break; 1.2113 + 1.2114 + case fnfErr: 1.2115 + case afpObjectNotFound: 1.2116 + case afpDirNotFound: 1.2117 + outErr = NS_ERROR_FILE_NOT_FOUND; 1.2118 + break; 1.2119 + 1.2120 + case dupFNErr: 1.2121 + case afpObjectExists: 1.2122 + outErr = NS_ERROR_FILE_ALREADY_EXISTS; 1.2123 + break; 1.2124 + 1.2125 + case dskFulErr: 1.2126 + case afpDiskFull: 1.2127 + outErr = NS_ERROR_FILE_DISK_FULL; 1.2128 + break; 1.2129 + 1.2130 + case fLckdErr: 1.2131 + case afpVolLocked: 1.2132 + outErr = NS_ERROR_FILE_IS_LOCKED; 1.2133 + break; 1.2134 + 1.2135 + case afpAccessDenied: 1.2136 + outErr = NS_ERROR_FILE_ACCESS_DENIED; 1.2137 + break; 1.2138 + 1.2139 + case afpDirNotEmpty: 1.2140 + outErr = NS_ERROR_FILE_DIR_NOT_EMPTY; 1.2141 + break; 1.2142 + 1.2143 + // Can't find good map for some 1.2144 + case bdNamErr: 1.2145 + outErr = NS_ERROR_FAILURE; 1.2146 + break; 1.2147 + 1.2148 + default: 1.2149 + outErr = NS_ERROR_FAILURE; 1.2150 + break; 1.2151 + } 1.2152 + 1.2153 + return outErr; 1.2154 +} 1.2155 + 1.2156 +static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) 1.2157 +{ 1.2158 + // first see if the conversion would succeed and find the length of the result 1.2159 + CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef); 1.2160 + CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), 1.2161 + kCFStringEncodingUTF8, 0, false, 1.2162 + nullptr, 0, &usedBufLen); 1.2163 + if (charsConverted == inStrLen) { 1.2164 + // all characters converted, do the actual conversion 1.2165 + aOutStr.SetLength(usedBufLen); 1.2166 + if (aOutStr.Length() != (unsigned int)usedBufLen) 1.2167 + return NS_ERROR_OUT_OF_MEMORY; 1.2168 + UInt8 *buffer = (UInt8*)aOutStr.BeginWriting(); 1.2169 + ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), kCFStringEncodingUTF8, 1.2170 + 0, false, buffer, usedBufLen, &usedBufLen); 1.2171 + return NS_OK; 1.2172 + } 1.2173 + 1.2174 + return NS_ERROR_FAILURE; 1.2175 +} 1.2176 + 1.2177 +NS_IMETHODIMP 1.2178 +nsLocalFile::InitWithCFURL(CFURLRef aCFURL) 1.2179 +{ 1.2180 + UInt8 path[PATH_MAX]; 1.2181 + if (::CFURLGetFileSystemRepresentation(aCFURL, false, path, PATH_MAX)) { 1.2182 + nsDependentCString nativePath((char*)path); 1.2183 + return InitWithNativePath(nativePath); 1.2184 + } 1.2185 + 1.2186 + return NS_ERROR_FAILURE; 1.2187 +} 1.2188 + 1.2189 +NS_IMETHODIMP 1.2190 +nsLocalFile::InitWithFSRef(const FSRef *aFSRef) 1.2191 +{ 1.2192 + if (NS_WARN_IF(!aFSRef)) 1.2193 + return NS_ERROR_INVALID_ARG; 1.2194 + 1.2195 + CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); 1.2196 + if (newURLRef) { 1.2197 + nsresult rv = InitWithCFURL(newURLRef); 1.2198 + ::CFRelease(newURLRef); 1.2199 + return rv; 1.2200 + } 1.2201 + 1.2202 + return NS_ERROR_FAILURE; 1.2203 +} 1.2204 + 1.2205 +NS_IMETHODIMP 1.2206 +nsLocalFile::GetCFURL(CFURLRef *_retval) 1.2207 +{ 1.2208 + CHECK_mPath(); 1.2209 + 1.2210 + bool isDir; 1.2211 + IsDirectory(&isDir); 1.2212 + *_retval = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 1.2213 + (UInt8*)mPath.get(), 1.2214 + mPath.Length(), 1.2215 + isDir); 1.2216 + 1.2217 + return (*_retval ? NS_OK : NS_ERROR_FAILURE); 1.2218 +} 1.2219 + 1.2220 +NS_IMETHODIMP 1.2221 +nsLocalFile::GetFSRef(FSRef *_retval) 1.2222 +{ 1.2223 + if (NS_WARN_IF(!_retval)) 1.2224 + return NS_ERROR_INVALID_ARG; 1.2225 + 1.2226 + nsresult rv = NS_ERROR_FAILURE; 1.2227 + 1.2228 + CFURLRef url = nullptr; 1.2229 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.2230 + if (::CFURLGetFSRef(url, _retval)) { 1.2231 + rv = NS_OK; 1.2232 + } 1.2233 + ::CFRelease(url); 1.2234 + } 1.2235 + 1.2236 + return rv; 1.2237 +} 1.2238 + 1.2239 +NS_IMETHODIMP 1.2240 +nsLocalFile::GetFSSpec(FSSpec *_retval) 1.2241 +{ 1.2242 + if (NS_WARN_IF(!_retval)) 1.2243 + return NS_ERROR_INVALID_ARG; 1.2244 + 1.2245 + FSRef fsRef; 1.2246 + nsresult rv = GetFSRef(&fsRef); 1.2247 + if (NS_SUCCEEDED(rv)) { 1.2248 + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, nullptr, nullptr, _retval, nullptr); 1.2249 + return MacErrorMapper(err); 1.2250 + } 1.2251 + 1.2252 + return rv; 1.2253 +} 1.2254 + 1.2255 +NS_IMETHODIMP 1.2256 +nsLocalFile::GetFileSizeWithResFork(int64_t *aFileSizeWithResFork) 1.2257 +{ 1.2258 + if (NS_WARN_IF(!aFileSizeWithResFork)) 1.2259 + return NS_ERROR_INVALID_ARG; 1.2260 + 1.2261 + FSRef fsRef; 1.2262 + nsresult rv = GetFSRef(&fsRef); 1.2263 + if (NS_FAILED(rv)) 1.2264 + return rv; 1.2265 + 1.2266 + FSCatalogInfo catalogInfo; 1.2267 + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, 1.2268 + &catalogInfo, nullptr, nullptr, nullptr); 1.2269 + if (err != noErr) 1.2270 + return MacErrorMapper(err); 1.2271 + 1.2272 + *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize; 1.2273 + return NS_OK; 1.2274 +} 1.2275 + 1.2276 +NS_IMETHODIMP 1.2277 +nsLocalFile::GetFileType(OSType *aFileType) 1.2278 +{ 1.2279 + CFURLRef url; 1.2280 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.2281 + nsresult rv = CocoaFileUtils::GetFileTypeCode(url, aFileType); 1.2282 + ::CFRelease(url); 1.2283 + return rv; 1.2284 + } 1.2285 + return NS_ERROR_FAILURE; 1.2286 +} 1.2287 + 1.2288 +NS_IMETHODIMP 1.2289 +nsLocalFile::SetFileType(OSType aFileType) 1.2290 +{ 1.2291 + CFURLRef url; 1.2292 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.2293 + nsresult rv = CocoaFileUtils::SetFileTypeCode(url, aFileType); 1.2294 + ::CFRelease(url); 1.2295 + return rv; 1.2296 + } 1.2297 + return NS_ERROR_FAILURE; 1.2298 +} 1.2299 + 1.2300 +NS_IMETHODIMP 1.2301 +nsLocalFile::GetFileCreator(OSType *aFileCreator) 1.2302 +{ 1.2303 + CFURLRef url; 1.2304 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.2305 + nsresult rv = CocoaFileUtils::GetFileCreatorCode(url, aFileCreator); 1.2306 + ::CFRelease(url); 1.2307 + return rv; 1.2308 + } 1.2309 + return NS_ERROR_FAILURE; 1.2310 +} 1.2311 + 1.2312 +NS_IMETHODIMP 1.2313 +nsLocalFile::SetFileCreator(OSType aFileCreator) 1.2314 +{ 1.2315 + CFURLRef url; 1.2316 + if (NS_SUCCEEDED(GetCFURL(&url))) { 1.2317 + nsresult rv = CocoaFileUtils::SetFileCreatorCode(url, aFileCreator); 1.2318 + ::CFRelease(url); 1.2319 + return rv; 1.2320 + } 1.2321 + return NS_ERROR_FAILURE; 1.2322 +} 1.2323 + 1.2324 +NS_IMETHODIMP 1.2325 +nsLocalFile::LaunchWithDoc(nsIFile *aDocToLoad, bool aLaunchInBackground) 1.2326 +{ 1.2327 + bool isExecutable; 1.2328 + nsresult rv = IsExecutable(&isExecutable); 1.2329 + if (NS_FAILED(rv)) 1.2330 + return rv; 1.2331 + if (!isExecutable) 1.2332 + return NS_ERROR_FILE_EXECUTION_FAILED; 1.2333 + 1.2334 + FSRef appFSRef, docFSRef; 1.2335 + rv = GetFSRef(&appFSRef); 1.2336 + if (NS_FAILED(rv)) 1.2337 + return rv; 1.2338 + 1.2339 + if (aDocToLoad) { 1.2340 + nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad); 1.2341 + rv = macDoc->GetFSRef(&docFSRef); 1.2342 + if (NS_FAILED(rv)) 1.2343 + return rv; 1.2344 + } 1.2345 + 1.2346 + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; 1.2347 + LSLaunchFSRefSpec thelaunchSpec; 1.2348 + 1.2349 + if (aLaunchInBackground) 1.2350 + theLaunchFlags |= kLSLaunchDontSwitch; 1.2351 + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); 1.2352 + 1.2353 + thelaunchSpec.appRef = &appFSRef; 1.2354 + if (aDocToLoad) { 1.2355 + thelaunchSpec.numDocs = 1; 1.2356 + thelaunchSpec.itemRefs = &docFSRef; 1.2357 + } 1.2358 + thelaunchSpec.launchFlags = theLaunchFlags; 1.2359 + 1.2360 + OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, nullptr); 1.2361 + if (err != noErr) 1.2362 + return MacErrorMapper(err); 1.2363 + 1.2364 + return NS_OK; 1.2365 +} 1.2366 + 1.2367 +NS_IMETHODIMP 1.2368 +nsLocalFile::OpenDocWithApp(nsIFile *aAppToOpenWith, bool aLaunchInBackground) 1.2369 +{ 1.2370 + FSRef docFSRef; 1.2371 + nsresult rv = GetFSRef(&docFSRef); 1.2372 + if (NS_FAILED(rv)) 1.2373 + return rv; 1.2374 + 1.2375 + if (!aAppToOpenWith) { 1.2376 + OSErr err = ::LSOpenFSRef(&docFSRef, nullptr); 1.2377 + return MacErrorMapper(err); 1.2378 + } 1.2379 + 1.2380 + nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv); 1.2381 + if (!appFileMac) 1.2382 + return rv; 1.2383 + 1.2384 + bool isExecutable; 1.2385 + rv = appFileMac->IsExecutable(&isExecutable); 1.2386 + if (NS_FAILED(rv)) 1.2387 + return rv; 1.2388 + if (!isExecutable) 1.2389 + return NS_ERROR_FILE_EXECUTION_FAILED; 1.2390 + 1.2391 + FSRef appFSRef; 1.2392 + rv = appFileMac->GetFSRef(&appFSRef); 1.2393 + if (NS_FAILED(rv)) 1.2394 + return rv; 1.2395 + 1.2396 + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; 1.2397 + LSLaunchFSRefSpec thelaunchSpec; 1.2398 + 1.2399 + if (aLaunchInBackground) 1.2400 + theLaunchFlags |= kLSLaunchDontSwitch; 1.2401 + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); 1.2402 + 1.2403 + thelaunchSpec.appRef = &appFSRef; 1.2404 + thelaunchSpec.numDocs = 1; 1.2405 + thelaunchSpec.itemRefs = &docFSRef; 1.2406 + thelaunchSpec.launchFlags = theLaunchFlags; 1.2407 + 1.2408 + OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, nullptr); 1.2409 + if (err != noErr) 1.2410 + return MacErrorMapper(err); 1.2411 + 1.2412 + return NS_OK; 1.2413 +} 1.2414 + 1.2415 +NS_IMETHODIMP 1.2416 +nsLocalFile::IsPackage(bool *_retval) 1.2417 +{ 1.2418 + if (NS_WARN_IF(!_retval)) 1.2419 + return NS_ERROR_INVALID_ARG; 1.2420 + *_retval = false; 1.2421 + 1.2422 + CFURLRef url; 1.2423 + nsresult rv = GetCFURL(&url); 1.2424 + if (NS_FAILED(rv)) 1.2425 + return rv; 1.2426 + 1.2427 + LSItemInfoRecord info; 1.2428 + OSStatus status = ::LSCopyItemInfoForURL(url, kLSRequestBasicFlagsOnly, &info); 1.2429 + 1.2430 + ::CFRelease(url); 1.2431 + 1.2432 + if (status != noErr) { 1.2433 + return NS_ERROR_FAILURE; 1.2434 + } 1.2435 + 1.2436 + *_retval = !!(info.flags & kLSItemInfoIsPackage); 1.2437 + 1.2438 + return NS_OK; 1.2439 +} 1.2440 + 1.2441 +NS_IMETHODIMP 1.2442 +nsLocalFile::GetBundleDisplayName(nsAString& outBundleName) 1.2443 +{ 1.2444 + bool isPackage = false; 1.2445 + nsresult rv = IsPackage(&isPackage); 1.2446 + if (NS_FAILED(rv) || !isPackage) 1.2447 + return NS_ERROR_FAILURE; 1.2448 + 1.2449 + nsAutoString name; 1.2450 + rv = GetLeafName(name); 1.2451 + if (NS_FAILED(rv)) 1.2452 + return rv; 1.2453 + 1.2454 + int32_t length = name.Length(); 1.2455 + if (Substring(name, length - 4, length).EqualsLiteral(".app")) { 1.2456 + // 4 characters in ".app" 1.2457 + outBundleName = Substring(name, 0, length - 4); 1.2458 + } 1.2459 + else { 1.2460 + outBundleName = name; 1.2461 + } 1.2462 + 1.2463 + return NS_OK; 1.2464 +} 1.2465 + 1.2466 +NS_IMETHODIMP 1.2467 +nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier) 1.2468 +{ 1.2469 + nsresult rv = NS_ERROR_FAILURE; 1.2470 + 1.2471 + CFURLRef urlRef; 1.2472 + if (NS_SUCCEEDED(GetCFURL(&urlRef))) { 1.2473 + CFBundleRef bundle = ::CFBundleCreate(nullptr, urlRef); 1.2474 + if (bundle) { 1.2475 + CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle); 1.2476 + if (bundleIdentifier) 1.2477 + rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier); 1.2478 + ::CFRelease(bundle); 1.2479 + } 1.2480 + ::CFRelease(urlRef); 1.2481 + } 1.2482 + 1.2483 + return rv; 1.2484 +} 1.2485 + 1.2486 +NS_IMETHODIMP 1.2487 +nsLocalFile::GetBundleContentsLastModifiedTime(int64_t *aLastModTime) 1.2488 +{ 1.2489 + CHECK_mPath(); 1.2490 + if (NS_WARN_IF(!aLastModTime)) 1.2491 + return NS_ERROR_INVALID_ARG; 1.2492 + 1.2493 + bool isPackage = false; 1.2494 + nsresult rv = IsPackage(&isPackage); 1.2495 + if (NS_FAILED(rv) || !isPackage) { 1.2496 + return GetLastModifiedTime(aLastModTime); 1.2497 + } 1.2498 + 1.2499 + nsAutoCString infoPlistPath(mPath); 1.2500 + infoPlistPath.AppendLiteral("/Contents/Info.plist"); 1.2501 + PRFileInfo64 info; 1.2502 + if (PR_GetFileInfo64(infoPlistPath.get(), &info) != PR_SUCCESS) { 1.2503 + return GetLastModifiedTime(aLastModTime); 1.2504 + } 1.2505 + int64_t modTime = int64_t(info.modifyTime); 1.2506 + if (modTime == 0) { 1.2507 + *aLastModTime = 0; 1.2508 + } else { 1.2509 + *aLastModTime = modTime / int64_t(PR_USEC_PER_MSEC); 1.2510 + } 1.2511 + 1.2512 + return NS_OK; 1.2513 +} 1.2514 + 1.2515 +NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) 1.2516 +{ 1.2517 + if (NS_WARN_IF(!aFile)) 1.2518 + return NS_ERROR_INVALID_ARG; 1.2519 + 1.2520 + nsAutoCString nativePath; 1.2521 + nsresult rv = aFile->GetNativePath(nativePath); 1.2522 + if (NS_FAILED(rv)) 1.2523 + return rv; 1.2524 + 1.2525 + return InitWithNativePath(nativePath); 1.2526 +} 1.2527 + 1.2528 +nsresult 1.2529 +NS_NewLocalFileWithFSRef(const FSRef* aFSRef, bool aFollowLinks, nsILocalFileMac** result) 1.2530 +{ 1.2531 + nsRefPtr<nsLocalFile> file = new nsLocalFile(); 1.2532 + 1.2533 + file->SetFollowLinks(aFollowLinks); 1.2534 + 1.2535 + nsresult rv = file->InitWithFSRef(aFSRef); 1.2536 + if (NS_FAILED(rv)) { 1.2537 + return rv; 1.2538 + } 1.2539 + file.forget(result); 1.2540 + return NS_OK; 1.2541 +} 1.2542 + 1.2543 +nsresult 1.2544 +NS_NewLocalFileWithCFURL(const CFURLRef aURL, bool aFollowLinks, nsILocalFileMac** result) 1.2545 +{ 1.2546 + nsRefPtr<nsLocalFile> file = new nsLocalFile(); 1.2547 + 1.2548 + file->SetFollowLinks(aFollowLinks); 1.2549 + 1.2550 + nsresult rv = file->InitWithCFURL(aURL); 1.2551 + if (NS_FAILED(rv)) { 1.2552 + return rv; 1.2553 + } 1.2554 + file.forget(result); 1.2555 + return NS_OK; 1.2556 +} 1.2557 + 1.2558 +#endif