From 86e239c98f28cbcd8a7d3349eedfcd90e126920a Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Tue, 19 Sep 2000 00:22:41 +0000 Subject: [PATCH] =?UTF-8?q?Fixes=20to=20use=20atomic=20rename(2)=20if=20po?= =?UTF-8?q?ssible=20in=20nsLocalFile::MoveTo=20(33098,=20r=3D=3F),=20plus?= =?UTF-8?q?=20a=20bunch=20of=20other=20fixes=20and=20cleanups:?= - Fix comment misstatements of fact in nsIFile.idl, improve style slightly. - Fix typo in comment in nsILocalFile.idl. - Avoid gratuitous nsCString and nsXPIDLCString copy-constructions, which entail malloc'ing, in nsLocalFileUnix.cpp's CopyTo and GetParent methods. But do use nsXPIDLCString instead of raw nsMemory::Alloc/Free. - Get rid of unnecessary mLL_II2L and mLL_L2II macros, use "prlong.h" API only. Also use the LL_* macros consistently in case a Unix lacking long long type support wants to use this code. * BTW, the "Date" methods should be renamed to use "Time" instead -- after all PRTime is the type, and traditionally "time" refers to the time-number, a scalar independent of one's position on the surface of the earth, while "date" refers to a struct full of locale-specific information derived from time and some "environment" variables such as DST. Can we rename these nsIFile methods before Mozilla 0.9 / Netscape 6? - Use CHECK_mPath consistently and first, before any assertions relating to arguments (which logically come after the 'this' parameter CHECK_mPath is making assertions about). - Use nsCOMPtr for singly-inheriting implementations of XPCOM interfaces, to avoid scary-when-scaled 0-refcnt instances from being handled (these all got a ref via QI or equivalent soon enough, but you never know). This also removed some naked deletes. - Canonize all paths copied into mPath to lack trailing slashes, so we don't need to strip trailing slashes elsewhere, in higher-frequency methods (you set path less often than you get it or a substring of it). - ssize_t for strlen return values. - Since shaver used a function pointer to consolidate creat/mkdir logic, but didn't fold the necessary close of the new fd returned by non-failing creat into the pointed-at function, I did that. - AppendRelativePath forbids .. as a component (bounded by / or beginning or end of string on either side), not just in the middle of fragment (so that foo..bar is not an illegal relative pathname -- it should not be). BTW, what the heck is the difference between NS_ERROR_FILE_UNRECOGNIZED_PATH and ...INVALID_PATH? - SetLeafName was overallocating the new pathname buffer by failing to subtract the old leafname's length. - CopyTo was failing to return an NSRESULT_FOR_ERRNO(), it just called that macro on a line by itself -- eek! It also contained redundant if (newFD == nsnull) {...} cleanup code, it did a useless PR_GetFileInfo call, and it leaked FDs on read or write error. - Implemented CopyToFollowingLinks as a forwarded call to CopyTo, Unix does not support "copying" a symlink via normal file i/o. Should we instead lstat in CopyTo and if a link is the source of the copy, do readlink and then symlink? - Fixed the readlink method (GetTarget) to null-terminate the link string in the out parameter (readlink does not do that for you). - Lots of little nsnull vs. NULL vs. 0, == and != applied to boolean or null literals, white-space, indentation, bracing, comment, and sloppy code order (e.g., declaring an initialized variable that's not used till after early returns) fixes. Also invert some return logic so that NS_OK is the normal, least indented, final return. git-svn-id: svn://10.0.0.236/trunk@79492 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/io/nsIFile.idl | 34 +- mozilla/xpcom/io/nsILocalFile.idl | 2 +- mozilla/xpcom/io/nsLocalFileUnix.cpp | 863 +++++++++++++-------------- mozilla/xpcom/io/nsLocalFileUnix.h | 5 +- 4 files changed, 438 insertions(+), 466 deletions(-) diff --git a/mozilla/xpcom/io/nsIFile.idl b/mozilla/xpcom/io/nsIFile.idl index dc5c0f2354a..bf5a130fdcb 100644 --- a/mozilla/xpcom/io/nsIFile.idl +++ b/mozilla/xpcom/io/nsIFile.idl @@ -102,14 +102,15 @@ interface nsIFile : nsISupports * * @param newParentDir * This param is the destination directory. If the - * newParentDir is nsnull, copyTo() will simply - * rename the file. If the newParentDir is not - * null and does not exists, an error will be + * newParentDir is null, copyTo() will use the parent + * directory of this file. If the newParentDir is not + * null and is not a directory, an error will be * returned (NS_ERROR_FILE_DESTINATION_NOT_DIR) * * @param newName - * This param allows you to specify a new name - * for the file to be copied. This can be nsnull. + * This param allows you to specify a new name for + * the file to be copied. This param may be null, in + * which case the current leaf name will be used. * */ void copyTo(in nsIFile newParentDir, [const] in string newName); @@ -119,7 +120,9 @@ interface nsIFile : nsISupports * copyToFollowingLinks * * This function is identical to copyTo except it, as - * the name implies, follows symbolic links. + * the name implies, follows symbolic links. Some OSes + * such as Unix and Linux always follow symbolic links + * when copying. */ void copyToFollowingLinks(in nsIFile newParentDir, [const] in string newName); void copyToFollowingLinksUnicode(in nsIFile newParentDir, [const] in wstring newName); @@ -138,14 +141,15 @@ interface nsIFile : nsISupports * * @param newParentDir * This param is the destination directory. If the - * newParentDir is nsnull, moveTo() will simply - * rename the file. If the newParentDir is not - * null and does not exists, an error will be - * returned (NS_ERROR_FILE_DESTINATION_NOT_DIR) + * newParentDir is null, moveTo() will rename the file + * within its current directory. If the newParentDir is + * not null and does not name a directory, an error will + * be returned (NS_ERROR_FILE_DESTINATION_NOT_DIR) * * @param newName - * This param allows you to specify a new name - * for the file to be moved. This can be nsnull. + * This param allows you to specify a new name for + * the file to be moved. This param may be null, in + * which case the current leaf name will be used. * */ void moveTo(in nsIFile newParentDir, [const] in string newName); @@ -277,13 +281,13 @@ interface nsIFile : nsISupports boolean equals(in nsIFile inFile); /** - * Will determine if the inFile is a descendant - * If |recur| is true, it will descend subdirectories looking for + * Will determine if inFile is a descendant of this file + * If |recur| is true, look in subdirectories too */ boolean contains(in nsIFile inFile, in boolean recur); /** - * Parent will be nsnull when this is at the top of the volume. + * Parent will be null when this is at the top of the volume. */ readonly attribute nsIFile parent; diff --git a/mozilla/xpcom/io/nsILocalFile.idl b/mozilla/xpcom/io/nsILocalFile.idl index cbe079e41cf..67043e81314 100644 --- a/mozilla/xpcom/io/nsILocalFile.idl +++ b/mozilla/xpcom/io/nsILocalFile.idl @@ -52,7 +52,7 @@ interface nsILocalFile : nsIFile * @param filePath * A string which specifies a full file path to a * location. Relative paths will be treated as an - * error (NS_ERROR_FILE_UNRECONGNIZED_PATH). This + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). This * path must in native. */ void initWithPath([const] in string filePath); diff --git a/mozilla/xpcom/io/nsLocalFileUnix.cpp b/mozilla/xpcom/io/nsLocalFileUnix.cpp index 8771c07a5ba..1b74cfa7230 100644 --- a/mozilla/xpcom/io/nsLocalFileUnix.cpp +++ b/mozilla/xpcom/io/nsLocalFileUnix.cpp @@ -10,19 +10,20 @@ * implied. See the License for the specific language governing * rights and limitations under the License. * - * The Original Code is Mozilla Communicator client code, - * released March 31, 1998. + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. * - * The Initial Developer of the Original Code is Netscape Communications + * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are * Copyright (C) 1998-1999 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): * Mike Shaver * Christopher Blizzard * Jason Eager * Stuart Parmenter + * Brendan Eich */ /* @@ -50,7 +51,7 @@ #include "nsILocalFile.h" #include "nsLocalFileUnix.h" #include "nsIComponentManager.h" -#include "nsString.h" +#include "nsXPIDLString.h" #include "prproces.h" // we need these for statfs() @@ -83,51 +84,37 @@ #endif #define VALIDATE_STAT_CACHE() \ - PR_BEGIN_MACRO \ - if (!mHaveCachedStat) { \ - FillStatCache(); \ - if (!mHaveCachedStat) \ - return NSRESULT_FOR_ERRNO(); \ - } \ - PR_END_MACRO + PR_BEGIN_MACRO \ + if (!mHaveCachedStat) { \ + FillStatCache(); \ + if (!mHaveCachedStat) \ + return NSRESULT_FOR_ERRNO(); \ + } \ + PR_END_MACRO -#define CHECK_mPath() \ - PR_BEGIN_MACRO \ - if (!(const char *)mPath) \ - return NS_ERROR_NOT_INITIALIZED; \ - PR_END_MACRO - -#define mLL_II2L(hi, lo, res) \ - LL_I2L(res, hi); \ - LL_SHL(res, res, 32); \ - LL_ADD(res, res, lo); - -#define mLL_L2II(a64, hi, lo) \ - PR_BEGIN_MACRO \ - PRInt64 tmp; \ - LL_SHR(tmp, a64, 32); \ - LL_L2I(hi, tmp); \ - LL_SHL(tmp, a64, 32); \ - LL_SHR(tmp, tmp, 32); \ - LL_L2I(lo, tmp); \ - PR_END_MACRO +#define CHECK_mPath() \ + PR_BEGIN_MACRO \ + if (!(const char *)mPath) \ + return NS_ERROR_NOT_INITIALIZED; \ + PR_END_MACRO /* directory enumerator */ class NS_COM nsDirEnumeratorUnix : public nsISimpleEnumerator { - public: + public: nsDirEnumeratorUnix(); virtual ~nsDirEnumeratorUnix(); // nsISupports interface NS_DECL_ISUPPORTS - + // nsISimpleEnumerator interface NS_DECL_NSISIMPLEENUMERATOR NS_IMETHOD Init(nsIFile *parent, PRBool ignored); - protected: + + protected: NS_IMETHOD GetNextEntry(); DIR *mDir; @@ -154,8 +141,9 @@ nsDirEnumeratorUnix::Init(nsIFile *parent, PRBool resolveSymlinks /*ignored*/) { nsXPIDLCString dirPath; if (NS_FAILED(parent->GetPath(getter_Copies(dirPath))) || - (const char *)dirPath == 0) + (const char *)dirPath == nsnull) { return NS_ERROR_FILE_INVALID_PATH; + } if (NS_FAILED(parent->GetPath(getter_Copies(mParentPath)))) return NS_ERROR_FAILURE; @@ -202,22 +190,21 @@ nsDirEnumeratorUnix::GetNextEntry() errno = 0; mEntry = readdir(mDir); - /* end of dir or error */ + // end of dir or error if (!mEntry) return NSRESULT_FOR_ERRNO(); - /* keep going past "." and ".." */ - } while (mEntry->d_name[0] == '.' && - (mEntry->d_name[1] == '\0' || /* .\0 */ + // keep going past "." and ".." + } while (mEntry->d_name[0] == '.' && + (mEntry->d_name[1] == '\0' || // .\0 (mEntry->d_name[1] == '.' && - mEntry->d_name[2] == '\0'))); /* ..\0 */ + mEntry->d_name[2] == '\0'))); // ..\0 return NS_OK; } nsLocalFile::nsLocalFile() : - mHaveCachedStat(PR_FALSE) + mHaveCachedStat(PR_FALSE) { - mPath = ""; NS_INIT_REFCNT(); } @@ -228,12 +215,13 @@ nsLocalFile::~nsLocalFile() NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) nsresult -nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, void **aInstancePtr) +nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, + void **aInstancePtr) { NS_ENSURE_ARG_POINTER(aInstancePtr); NS_ENSURE_NO_AGGREGATION(outer); - - *aInstancePtr = 0; + + *aInstancePtr = nsnull; nsCOMPtr inst = new nsLocalFile(); if (!inst) @@ -244,23 +232,19 @@ nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, void NS_IMETHODIMP nsLocalFile::Clone(nsIFile **file) { - nsresult rv; + CHECK_mPath(); NS_ENSURE_ARG(file); - - *file = nsnull; nsCOMPtr localFile = new nsLocalFile(); - if (localFile == nsnull) + if (!localFile) return NS_ERROR_OUT_OF_MEMORY; - - rv = localFile->InitWithPath(mPath); - - if (NS_FAILED(rv)) + + nsresult rv = localFile->InitWithPath(mPath); + if (NS_FAILED(rv)) return rv; *file = localFile; NS_ADDREF(*file); - return NS_OK; } @@ -268,18 +252,15 @@ NS_IMETHODIMP nsLocalFile::InitWithPath(const char *filePath) { NS_ENSURE_ARG(filePath); - - int len = strlen(filePath); - char* name = (char*) nsMemory::Clone( filePath, len+1 ); - if (name[len-1] == '/') { - if (len != 1) - name[len-1] = '\0'; - } - + + ssize_t len = strlen(filePath); + char *name = (char *) nsMemory::Clone(filePath, len+1); + while (name[len-1] == '/' && len > 1) + name[--len] = '\0'; + mPath = name; - nsMemory::Free(name); - + InvalidateCache(); return NS_OK; } @@ -287,19 +268,21 @@ nsLocalFile::InitWithPath(const char *filePath) NS_IMETHODIMP nsLocalFile::CreateAllAncestors(PRUint32 permissions) { - /* I promise to play nice */ + CHECK_mPath(); + + // I promise to play nice char *buffer = NS_CONST_CAST(char *, (const char *)mPath), - *ptr = buffer; + *slashp = buffer; #ifdef DEBUG_NSIFILE fprintf(stderr, "nsIFile: before: %s\n", buffer); #endif - while ((ptr = strchr(ptr + 1, '/'))) { + while ((slashp = strchr(slashp + 1, '/'))) { /* * Sequences of '/' are equivalent to a single '/'. */ - if (ptr[1] == '/') + if (slashp[1] == '/') continue; /* @@ -308,16 +291,18 @@ nsLocalFile::CreateAllAncestors(PRUint32 permissions) * component again, and it's easier to condition the logic here than * there. */ - if (!ptr[1]) + if (slashp[1] == '\0') break; + /* Temporarily NUL-terminate here */ - *ptr = '\0'; + *slashp = '\0'; #ifdef DEBUG_NSIFILE fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer); #endif int result = mkdir(buffer, permissions); + /* Put the / back before we (maybe) return */ - *ptr = '/'; + *slashp = '/'; /* * We could get EEXISTS for an existing file -- not directory -- @@ -332,42 +317,46 @@ nsLocalFile::CreateAllAncestors(PRUint32 permissions) #ifdef DEBUG_NSIFILE fprintf(stderr, "nsIFile: after: %s\n", buffer); #endif - - return NS_OK; + return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) { CHECK_mPath(); - + *_retval = PR_Open(mPath, flags, mode); - - if (*_retval) - return NS_OK; + if (! *_retval) + return NS_ERROR_FAILURE; - return NS_ERROR_FAILURE; + return NS_OK; } -NS_IMETHODIMP -nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) { - CHECK_mPath(); - - *_retval = fopen(mPath, mode); - - if (*_retval) - return NS_OK; + CHECK_mPath(); - return NS_ERROR_FAILURE; + *_retval = fopen(mPath, mode); + if (! *_retval) + return NS_ERROR_FAILURE; + + return NS_OK; } -static int exclusive_create(const char * path, mode_t mode) { - return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); + +static int exclusive_create(const char *path, mode_t mode) +{ + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); + if (fd >= 0) + close(fd); + return fd; } -static int exclusive_mkdir(const char * path, mode_t mode) { - return mkdir(path, mode); + +static int exclusive_mkdir(const char *path, mode_t mode) +{ + return mkdir(path, mode); } NS_IMETHODIMP @@ -378,17 +367,15 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions) return NS_ERROR_FILE_UNKNOWN_TYPE; int result; - /* use creat(2) for NORMAL_FILE, mkdir(2) for DIRECTORY */ - int (*creationFunc)(const char *, mode_t) = - type == NORMAL_FILE_TYPE ? exclusive_create : exclusive_mkdir; - - result = creationFunc((const char *)mPath, permissions); + int (*exclusiveCreateFunc)(const char *, mode_t) = + (type == NORMAL_FILE_TYPE) ? exclusive_create : exclusive_mkdir; + result = exclusiveCreateFunc((const char *)mPath, permissions); if (result == -1 && errno == ENOENT) { /* * If we failed because of missing ancestor components, try to create * them and then retry the original creation. - * + * * Ancestor directories get the same permissions as the file we're * creating, with the X bit set for each of (user,group,other) with * an R bit in the original permissions. If you want to do anything @@ -403,7 +390,7 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions) dirperm |= S_IXOTH; #ifdef DEBUG_NSIFILE - fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, + fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, dirperm); #endif @@ -413,13 +400,7 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions) #ifdef DEBUG_NSIFILE fprintf(stderr, "nsIFile: Create(\"%s\") again\n", (const char *)mPath); #endif - result = creationFunc((const char *)mPath, permissions); - } - - /* creat(2) leaves the file open */ - if (result >= 0 && type == NORMAL_FILE_TYPE) { - close(result); - return NS_OK; + result = exclusiveCreateFunc((const char *)mPath, permissions); } return NSRESULT_FOR_RETURN(result); @@ -428,14 +409,12 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions) NS_IMETHODIMP nsLocalFile::Append(const char *fragment) { - NS_ENSURE_ARG(fragment); CHECK_mPath(); + NS_ENSURE_ARG(fragment); // only one component of path can be appended - if (strstr(fragment, "/") != nsnull) - { + if (strchr(fragment, '/')) return NS_ERROR_FILE_UNRECOGNIZED_PATH; - } return AppendRelativePath(fragment); } @@ -443,22 +422,36 @@ nsLocalFile::Append(const char *fragment) NS_IMETHODIMP nsLocalFile::AppendRelativePath(const char *fragment) { - NS_ENSURE_ARG(fragment); CHECK_mPath(); + NS_ENSURE_ARG(fragment); - // Cannot start with a '/' and no .. allowed in the fragment - if ((*fragment == '/') || (strstr(fragment, "..") != nsnull)) - { + // No leading '/' and no ".." component is allowed in the fragment. + if (*fragment == '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char *dots = strstr(fragment, ".."); + if (dots && + (dots == fragment || dots[-1] == '/') && + (dots[2] == '\0' || dots[2] == '/')) { + // XXXbe what's the difference between UNRECOGNIZED and INVALID? return NS_ERROR_FILE_UNRECOGNIZED_PATH; } - char * newPath = (char *)nsMemory::Alloc(strlen(mPath) + - strlen(fragment) + 2); + char *newPath = (char *)nsMemory::Alloc(strlen(mPath) + + strlen(fragment) + + 2); if (!newPath) return NS_ERROR_OUT_OF_MEMORY; strcpy(newPath, mPath); strcat(newPath, "/"); strcat(newPath, fragment); + + // strip trailing slashes that came from fragment + ssize_t len = strlen(newPath); + while (newPath[len-1] == '/' && len > 1) + newPath[--len] = '\0'; + + // nsXPIDLCString will copy. mPath = newPath; InvalidateCache(); nsMemory::Free(newPath); @@ -468,23 +461,23 @@ nsLocalFile::AppendRelativePath(const char *fragment) NS_IMETHODIMP nsLocalFile::Normalize() { - char resolved_path[PATH_MAX]; - char *resolved_path_ptr = NULL; CHECK_mPath(); + char resolved_path[PATH_MAX]; + char *resolved_path_ptr = nsnull; + #ifdef XP_BEOS - BEntry be_e((const char*)mPath, true); + BEntry be_e((const char *)mPath, true); BPath be_p; status_t err; - if ((err = be_e.GetPath(&be_p)) == B_OK) { + if ((err = be_e.GetPath(&be_p)) == B_OK) resolved_path_ptr = be_p.Path(); - }; #else resolved_path_ptr = realpath((const char *)mPath, resolved_path); #endif // if there is an error, the return is null. - if (resolved_path_ptr == NULL) { + if (!resolved_path_ptr) return NSRESULT_FOR_ERRNO(); - } + // nsXPIDLCString will copy. mPath = resolved_path; return NS_OK; @@ -495,8 +488,9 @@ nsLocalFile::GetLeafNameRaw(const char **_retval) { CHECK_mPath(); const char *leafName = strrchr((const char *)mPath, '/'); + NS_ASSERTION(leafName, "non-canonical mPath?"); if (!leafName) - return NS_ERROR_FILE_INVALID_PATH; + return NS_ERROR_FILE_INVALID_PATH; *_retval = leafName+1; return NS_OK; } @@ -508,33 +502,35 @@ nsLocalFile::GetLeafName(char **aLeafName) nsresult rv; const char *leafName; if (NS_FAILED(rv = GetLeafNameRaw(&leafName))) - return rv; - + return rv; + *aLeafName = nsCRT::strdup(leafName); if (!*aLeafName) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } - - NS_IMETHODIMP nsLocalFile::SetLeafName(const char *aLeafName) { - NS_ENSURE_ARG(aLeafName); CHECK_mPath(); + NS_ENSURE_ARG(aLeafName); nsresult rv; char *leafName; - if (NS_FAILED(rv = GetLeafNameRaw((const char**)&leafName))) - return rv; - char* newPath = (char *)nsMemory::Alloc(strlen(mPath) + - strlen(aLeafName) + 2); - *leafName = 0; - + if (NS_FAILED(rv = GetLeafNameRaw((const char **)&leafName))) + return rv; + + char *newPath = (char *)nsMemory::Alloc((leafName - (const char *)mPath) + + strlen(aLeafName) + + 1); + if (!newPath) + return NS_ERROR_OUT_OF_MEMORY; + *leafName = '\0'; strcpy(newPath, mPath); - strcat(newPath, "/"); strcat(newPath, aLeafName); + + // nsXPIDLCString will copy. mPath = newPath; InvalidateCache(); nsMemory::Free(newPath); @@ -547,8 +543,8 @@ nsLocalFile::GetPath(char **_retval) NS_ENSURE_ARG_POINTER(_retval); if (!(const char *)mPath) { - *_retval = nsnull; - return NS_OK; + *_retval = nsnull; + return NS_OK; } *_retval = nsCRT::strdup((const char *)mPath); @@ -557,16 +553,62 @@ nsLocalFile::GetPath(char **_retval) return NS_OK; } +nsresult +nsLocalFile::GetTargetPathName(nsIFile *newParent, const char *newName, + char **_retval) +{ + nsresult rv; + nsCOMPtr oldParent; + + if (!newParent) { + if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent)))) + return rv; + newParent = oldParent.get(); + } else { + // check to see if our target directory exists + PRBool targetExists; + newParent->Exists(&targetExists); + + if (!targetExists) { + // XXX create the new directory with some permissions + rv = newParent->Create(DIRECTORY_TYPE, 0755); + if (NS_FAILED(rv)) + return rv; + } else { + // make sure that the target is actually a directory + PRBool targetIsDirectory; + newParent->IsDirectory(&targetIsDirectory); + if (!targetIsDirectory) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + if (!newName && NS_FAILED(rv = GetLeafNameRaw(&newName))) + return rv; + + nsXPIDLCString dirName; + if (NS_FAILED(rv = newParent->GetPath(getter_Copies(dirName)))) + return rv; + + char *newPathName = (char *)nsMemory::Alloc(strlen(dirName) + + strlen(newName) + + 2); + if (!newPathName) + return NS_ERROR_OUT_OF_MEMORY; + + strcpy(newPathName, dirName); + strcat(newPathName, "/"); + strcat(newPathName, newName); + + *_retval = newPathName; + return NS_OK; +} + NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParent, const char *newName) { nsresult rv; - // check to make sure that we have a new parent - // or have a new name - if (newParent == nsnull && newName == nsnull) - return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; - // check to make sure that this has been initialized properly CHECK_mPath(); @@ -574,85 +616,28 @@ nsLocalFile::CopyTo(nsIFile *newParent, const char *newName) PRBool isDirectory; IsDirectory(&isDirectory); - if (isDirectory) - { - // XXX - return NS_ERROR_NOT_IMPLEMENTED; - } - else - { - // ok, we're a file so this should be easy as pie. - // check to see if our target exists - PRBool targetExists; - newParent->Exists(&targetExists); - // check to see if we need to create it - if (targetExists == PR_FALSE) - { - // XXX create the new directory with some permissions - rv = newParent->Create(DIRECTORY_TYPE, 0755); - if (NS_FAILED(rv)) - return rv; - } - // make sure that the target is actually a directory - PRBool targetIsDirectory; - newParent->IsDirectory(&targetIsDirectory); - if (targetIsDirectory == PR_FALSE) - return NS_ERROR_FILE_DESTINATION_NOT_DIR; - // ok, we got this far. create the name of the new file. - nsXPIDLCString leafName; - nsXPIDLCString newPath; - const char *tmpConstChar; - char *tmpChar; - // get the leaf name of the new file if a name isn't supplied. - if (newName == nsnull) - { - if (NS_FAILED(rv = GetLeafNameRaw(&tmpConstChar))) - return rv; - leafName = tmpConstChar; - } - else - { - leafName = newName; - } - // get the path name - if (NS_FAILED(rv = newParent->GetPath(&tmpChar))) + if (isDirectory) { + // XXXbe what's the bugzilla.mozilla.org bug number for this? + rv = NS_ERROR_NOT_IMPLEMENTED; + } else { + nsXPIDLCString newPathName; + rv = GetTargetPathName(newParent, newName, getter_Copies(newPathName)); + if (NS_FAILED(rv)) return rv; - // this is the full path to the dir of the new file - newPath = tmpChar; - nsMemory::Free(tmpChar); - - // create the final name - char *newPathName; - newPathName = (char *)nsMemory::Alloc(strlen(newPath) + strlen(leafName) + 2); - if (!newPathName) - return NS_ERROR_OUT_OF_MEMORY; - - strcpy(newPathName, newPath); - strcat(newPathName, "/"); - strcat(newPathName, leafName); - #ifdef DEBUG_blizzard - printf("nsLocalFile::CopyTo() %s -> %s\n", (const char *)mPath, newPathName); + printf("nsLocalFile::CopyTo() %s -> %s\n", (const char *)mPath, (const char *)newPathName); #endif - nsXPIDLCString newPathNameAuto; - newPathNameAuto = newPathName; - nsMemory::Free(newPathName); - // actually create the file. - nsLocalFile *newFile = new nsLocalFile(); - newFile->AddRef(); // we own this. - if (newFile == nsnull) - { + if (!newFile) { return NS_ERROR_OUT_OF_MEMORY; } + NS_ADDREF(newFile); - rv = newFile->InitWithPath(newPathNameAuto); - - if (NS_FAILED(rv)) - { + rv = newFile->InitWithPath(newPathName); + if (NS_FAILED(rv)) { NS_RELEASE(newFile); return rv; } @@ -660,94 +645,67 @@ nsLocalFile::CopyTo(nsIFile *newParent, const char *newName) // get the old permissions PRUint32 myPerms; GetPermissions(&myPerms); + // create the new file with the same permissions rv = newFile->Create(NORMAL_FILE_TYPE, myPerms); - if (NS_FAILED(rv)) - { + if (NS_FAILED(rv)) { NS_RELEASE(newFile); return rv; } // open the new file. - PRInt32 openFlags = PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE; PRInt32 modeFlags = myPerms; - PRFileDesc *newFD = nsnull; + PRFileDesc *newFD; rv = newFile->OpenNSPRFileDesc(openFlags, modeFlags, &newFD); - if (NS_FAILED(rv)) - { + if (NS_FAILED(rv)) { NS_RELEASE(newFile); return rv; } - if (newFD == nsnull) - { - NS_RELEASE(newFile); - NSRESULT_FOR_ERRNO(); - } // open the old file, too - openFlags = PR_RDONLY; - PRFileDesc *oldFD = nsnull; + PRFileDesc *oldFD; rv = OpenNSPRFileDesc(openFlags, modeFlags, &oldFD); - // make sure to clean up properly - if (NS_FAILED(rv)) - { - NS_RELEASE(newFile); + if (NS_FAILED(rv)) { + // make sure to clean up properly PR_Close(newFD); + NS_RELEASE(newFile); return rv; } - if (newFD == nsnull) - { - NS_RELEASE(newFile); - PR_Close(newFD); - NSRESULT_FOR_ERRNO(); - } - // get the length of the file - - PRStatus status; - PRFileInfo fileInfo; - status = PR_GetFileInfo(mPath, &fileInfo); - if (status != PR_SUCCESS) - { - NS_RELEASE(newFile); - PR_Close(newFD); - NSRESULT_FOR_ERRNO(); - } - - // get the size of the file. - - PROffset32 fileSize; - fileSize = fileInfo.size; - PRInt32 bytesRead = 0; - PRInt32 bytesWritten = 0; +#ifdef DEBUG_blizzard PRInt32 totalRead = 0; PRInt32 totalWritten = 0; - +#endif char buf[BUFSIZ]; - - while(1) - { - bytesRead = PR_Read(oldFD, &buf, BUFSIZ); - if (bytesRead == 0) - break; - if (bytesRead == -1) - return NS_ERROR_FAILURE; + PRInt32 bytesRead; + + while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) { +#ifdef DEBUG_blizzard totalRead += bytesRead; - bytesWritten = PR_Write(newFD, &buf, bytesRead); - if (bytesWritten == -1) - return NS_ERROR_FAILURE; +#endif + + // PR_Write promises never to do a short write + PRInt32 bytesWritten = PR_Write(newFD, buf, bytesRead); + if (bytesWritten < 0) { + bytesRead = -1; + break; + } + NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?"); + +#ifdef DEBUG_blizzard totalWritten += bytesWritten; - } +#endif + } #ifdef DEBUG_blizzard printf("read %d bytes, wrote %d bytes\n", totalRead, totalWritten); #endif - + // close the files PR_Close(newFD); PR_Close(oldFD); @@ -755,29 +713,52 @@ nsLocalFile::CopyTo(nsIFile *newParent, const char *newName) // free our resources NS_RELEASE(newFile); + // check for read (or write) error after cleaning up + if (bytesRead < 0) + return NSRESULT_FOR_ERRNO(); } - + return rv; } NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParent, const char *newName) { - return NS_ERROR_NOT_IMPLEMENTED; + return CopyTo(newParent, newName); } NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParent, const char *newName) { - nsresult rv = CopyTo(newParent, newName); - if (NS_SUCCEEDED(rv)) - rv = Delete(PR_TRUE); + nsresult rv; + + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // check to make sure that we have a new parent + nsXPIDLCString newPathName; + rv = GetTargetPathName(newParent, newName, getter_Copies(newPathName)); + if (NS_FAILED(rv)) + return rv; + + // try for atomic rename, falling back to copy/delete + if (rename((const char *)mPath, (const char *)newPathName) < 0) { + if (errno == EXDEV) { + rv = CopyTo(newParent, newName); + if (NS_SUCCEEDED(rv)) + rv = Delete(PR_TRUE); + } else { + rv = NSRESULT_FOR_ERRNO(); + } + } return rv; } NS_IMETHODIMP nsLocalFile::Delete(PRBool recursive) { + CHECK_mPath(); + VALIDATE_STAT_CACHE(); PRBool isDir = S_ISDIR(mCachedStat.st_mode); @@ -789,37 +770,26 @@ nsLocalFile::Delete(PRBool recursive) if (isDir) { if (recursive) { - nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + nsCOMPtr dir = new nsDirEnumeratorUnix(); if (!dir) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = dir->Init(this, PR_FALSE); - if (NS_FAILED(rv)) { - delete dir; + if (NS_FAILED(rv)) return rv; - } - - nsCOMPtr iterator; - iterator = do_QueryInterface(dir, &rv); - if (NS_FAILED(rv)) { - delete dir; - return rv; - } PRBool more; - rv = iterator->HasMoreElements(&more); - while (NS_SUCCEEDED(rv) && more) { + while (dir->HasMoreElements(&more), more) { nsCOMPtr item; - nsCOMPtr file; - rv = iterator->GetNext(getter_AddRefs(item)); + rv = dir->GetNext(getter_AddRefs(item)); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - file = do_QueryInterface(item, &rv); + + nsCOMPtr file = do_QueryInterface(item, &rv); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; if (NS_FAILED(rv = file->Delete(recursive))) return rv; - rv = iterator->HasMoreElements(&more); } } @@ -833,53 +803,62 @@ nsLocalFile::Delete(PRBool recursive) return NS_OK; } -NS_IMETHODIMP -nsLocalFile::GetLastModificationDate(PRInt64 *aLastModificationDate) +NS_IMETHODIMP +nsLocalFile::GetLastModificationDate(PRInt64 *aLastModTime) { - NS_ENSURE_ARG(aLastModificationDate); CHECK_mPath(); + NS_ENSURE_ARG(aLastModTime); + PRFileInfo64 info; - if (PR_GetFileInfo64(mPath, &info) != PR_SUCCESS) { + if (PR_GetFileInfo64(mPath, &info) != PR_SUCCESS) return NSRESULT_FOR_ERRNO(); - } + // PRTime is a 64 bit value // microseconds -> milliseconds - *aLastModificationDate = info.modifyTime / PR_USEC_PER_MSEC; + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModTime, info.modifyTime, usecPerMsec); return NS_OK; } -NS_IMETHODIMP -nsLocalFile::SetLastModificationDate(PRInt64 aLastModificationDate) +NS_IMETHODIMP +nsLocalFile::SetLastModificationDate(PRInt64 aLastModTime) { + CHECK_mPath(); + int result; - if (aLastModificationDate) { + if (aLastModTime) { VALIDATE_STAT_CACHE(); struct utimbuf ut; ut.actime = mCachedStat.st_atime; - // convert PRTime microsecs to unix seconds since the epoch + // convert milliseconds to seconds since the unix epoch double dTime; - LL_L2D(dTime, aLastModificationDate); - ut.modtime = (time_t)( (PRUint32)(dTime / PR_MSEC_PER_SEC) ); + LL_L2D(dTime, aLastModTime); + ut.modtime = (time_t) (dTime / PR_MSEC_PER_SEC); result = utime(mPath, &ut); } else { - result = utime(mPath, NULL); + result = utime(mPath, nsnull); } InvalidateCache(); return NSRESULT_FOR_RETURN(result); } -NS_IMETHODIMP -nsLocalFile::GetLastModificationDateOfLink(PRInt64 *aLastModificationDateOfLink) +NS_IMETHODIMP +nsLocalFile::GetLastModificationDateOfLink(PRInt64 *aLastModTimeOfLink) { - NS_ENSURE_ARG(aLastModificationDateOfLink); + CHECK_mPath(); + NS_ENSURE_ARG(aLastModTimeOfLink); + struct stat sbuf; if (lstat(mPath, &sbuf) == -1) return NSRESULT_FOR_ERRNO(); - mLL_II2L(0, (PRUint32)sbuf.st_mtime, *aLastModificationDateOfLink); + LL_I2L(*aLastModTimeOfLink, (PRInt32)sbuf.st_mtime); - // lstat returns st_mtime in seconds! - *aLastModificationDateOfLink *= PR_MSEC_PER_SEC; + // lstat returns st_mtime in seconds + PRInt64 msecPerSec; + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_MUL(*aLastModTimeOfLink, *aLastModTimeOfLink, msecPerSec); return NS_OK; } @@ -887,10 +866,10 @@ nsLocalFile::GetLastModificationDateOfLink(PRInt64 *aLastModificationDateOfLink) /* * utime(2) may or may not dereference symlinks, joy. */ -NS_IMETHODIMP -nsLocalFile::SetLastModificationDateOfLink(PRInt64 aLastModificationDateOfLink) +NS_IMETHODIMP +nsLocalFile::SetLastModificationDateOfLink(PRInt64 aLastModTimeOfLink) { - return SetLastModificationDate(aLastModificationDateOfLink); + return SetLastModificationDate(aLastModTimeOfLink); } /* @@ -899,7 +878,7 @@ nsLocalFile::SetLastModificationDateOfLink(PRInt64 aLastModificationDateOfLink) */ #define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO)) -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions) { NS_ENSURE_ARG(aPermissions); @@ -908,10 +887,12 @@ nsLocalFile::GetPermissions(PRUint32 *aPermissions) return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) { + CHECK_mPath(); NS_ENSURE_ARG(aPermissionsOfLink); + struct stat sbuf; if (lstat(mPath, &sbuf) == -1) return NSRESULT_FOR_ERRNO(); @@ -919,14 +900,16 @@ nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions) { + CHECK_mPath(); + InvalidateCache(); return NSRESULT_FOR_RETURN(chmod(mPath, aPermissions)); } -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) { return SetPermissions(aPermissions); @@ -937,40 +920,41 @@ nsLocalFile::GetFileSize(PRInt64 *aFileSize) { NS_ENSURE_ARG_POINTER(aFileSize); VALIDATE_STAT_CACHE(); - - /* XXX autoconf for and use stat64 if available */ - if( S_ISDIR(mCachedStat.st_mode) ) - { - mLL_II2L(0, (PRUint32)0, *aFileSize); - } - else - { - mLL_II2L(0, (PRUint32)mCachedStat.st_size, *aFileSize); - } + + /* XXX autoconf for and use stat64 if available */ + if (S_ISDIR(mCachedStat.st_mode)) { + *aFileSize = LL_ZERO; + } else { + LL_UI2L(*aFileSize, (PRUint32)mCachedStat.st_size); + } return NS_OK; } NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize) { - PRInt32 hi, lo; - mLL_L2II(aFileSize, hi, lo); + CHECK_mPath(); + + PRInt32 size; + LL_L2I(size, aFileSize); /* XXX truncate64? */ InvalidateCache(); - if (truncate((const char *)mPath, (off_t)lo) == -1) + if (truncate((const char *)mPath, (off_t)size) == -1) return NSRESULT_FOR_ERRNO(); - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) { + CHECK_mPath(); NS_ENSURE_ARG(aFileSize); + struct stat sbuf; if (lstat(mPath, &sbuf) == -1) return NSRESULT_FOR_ERRNO(); /* XXX autoconf for and use lstat64 if available */ - mLL_II2L(0, (PRInt32)sbuf.st_size, *aFileSize); + LL_UI2L(*aFileSize, (PRUint32)sbuf.st_size); return NS_OK; } @@ -979,15 +963,13 @@ nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) { NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); - PRInt64 bytesFree = 0; + // These systems have the operations necessary to check disk space. - //These systems have the operations necessary to check disk space. - #if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) // check to make sure that mPath is properly initialized CHECK_mPath(); - + struct STATFS fs_buf; // Members of the STATFS struct that you should know about: @@ -995,16 +977,15 @@ nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) // f_bavail = number of free blocks available to a non-superuser. // f_bfree = number of total free blocks in file system. - if (STATFS(mPath, &fs_buf) < 0) - // The call to STATFS failed. - { + if (STATFS(mPath, &fs_buf) < 0) { + // The call to STATFS failed. #ifdef DEBUG printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n"); #endif return NS_ERROR_FAILURE; } #ifdef DEBUG_DISK_SPACE - printf("DiskSpaceAvailable: %d bytes\n", + printf("DiskSpaceAvailable: %d bytes\n", fs_buf.f_bsize * (fs_buf.f_bavail - 1)); #endif @@ -1012,18 +993,17 @@ nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) // a non-superuser, minus one as a fudge factor, multiplied by the size // of the beforementioned blocks. - LL_I2L( bytesFree, (fs_buf.f_bsize * (fs_buf.f_bavail - 1) ) ); - *aDiskSpaceAvailable = bytesFree; + LL_I2L(*aDiskSpaceAvailable, fs_buf.f_bsize * (fs_buf.f_bavail - 1)); return NS_OK; -#else +#else /* ** This platform doesn't have statfs or statvfs. ** I'm sure that there's a way to check for free disk space - ** on platforms that don't have statfs + ** on platforms that don't have statfs ** (I'm SURE they have df, for example). - ** - ** Until we figure out how to do that, lets be honest + ** + ** Until we figure out how to do that, lets be honest ** and say that this command isn't implemented ** properly for these platforms yet. */ @@ -1033,47 +1013,38 @@ nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) return NS_ERROR_NOT_IMPLEMENTED; #endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ - + } NS_IMETHODIMP nsLocalFile::GetParent(nsIFile **aParent) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(aParent); *aParent = nsnull; - CHECK_mPath(); + // I promise to play nice + char *buffer = NS_CONST_CAST(char *, (const char *)mPath), + *slashp = buffer; - nsCString parentPath(NS_STATIC_CAST(const char*, mPath)); - - // check to see whether or not we need to cut off any trailing - // slashes - - PRInt32 offset = parentPath.RFindChar('/'); - PRInt32 length = parentPath.Length(); - - // eat of trailing slash marks - while ((length > 1) && offset && (length == (offset + 1))) { - parentPath.Truncate(offset); - offset = parentPath.RFindChar('/'); - length = parentPath.Length(); - } - - if (offset == -1) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; + // find the last significant slash in buffer + slashp = strrchr(buffer, '/'); + NS_ASSERTION(slashp, "non-canonical mPath?"); + if (!slashp) + return NS_ERROR_FILE_INVALID_PATH; // for the case where we are at '/' - if (offset == 0) - offset++; - parentPath.Truncate(offset); + if (slashp == buffer) + slashp++; + // temporarily terminate buffer at the last significant slash + *slashp = '\0'; nsCOMPtr localFile; - nsresult rv = NS_NewLocalFile(parentPath.GetBuffer(), PR_TRUE, getter_AddRefs(localFile)); - - if(NS_SUCCEEDED(rv) && localFile) - { - return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aParent); - } + nsresult rv = NS_NewLocalFile(buffer, PR_TRUE, getter_AddRefs(localFile)); + *slashp = '/'; + + if (NS_SUCCEEDED(rv) && localFile) + rv = localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aParent); return rv; } @@ -1084,19 +1055,21 @@ nsLocalFile::GetParent(nsIFile **aParent) NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); - PRBool accessOK; - *_retval = accessOK = (access(mPath, F_OK) == 0); + + *_retval = (access(mPath, F_OK) == 0); return NS_OK; } NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); - PRBool accessOK; - *_retval = accessOK = (access(mPath, W_OK) == 0); - if (accessOK || errno == EACCES) + + *_retval = (access(mPath, W_OK) == 0); + if (*_retval || errno == EACCES) return NS_OK; return NSRESULT_FOR_ERRNO(); } @@ -1104,10 +1077,11 @@ nsLocalFile::IsWritable(PRBool *_retval) NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); - PRBool accessOK; - *_retval = accessOK = (access(mPath, R_OK) == 0); - if (accessOK || errno == EACCES) + + *_retval = (access(mPath, R_OK) == 0); + if (*_retval || errno == EACCES) return NS_OK; return NSRESULT_FOR_ERRNO(); } @@ -1115,10 +1089,11 @@ nsLocalFile::IsReadable(PRBool *_retval) NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); - PRBool accessOK; - *_retval = accessOK = (access(mPath, X_OK) == 0); - if (accessOK || errno == EACCES) + + *_retval = (access(mPath, X_OK) == 0); + if (*_retval || errno == EACCES) return NS_OK; return NSRESULT_FOR_ERRNO(); } @@ -1148,7 +1123,7 @@ nsLocalFile::IsHidden(PRBool *_retval) nsresult rv; const char *leafName; if (NS_FAILED(rv = GetLeafNameRaw(&leafName))) - return rv; + return rv; *_retval = (leafName[0] == '.'); return NS_OK; } @@ -1167,8 +1142,9 @@ nsLocalFile::IsSpecial(PRBool *_retval) { NS_ENSURE_ARG_POINTER(_retval); VALIDATE_STAT_CACHE(); - *_retval = !(S_ISLNK(mCachedStat.st_mode) || S_ISREG(mCachedStat.st_mode) || - S_ISDIR(mCachedStat.st_mode)); + *_retval = !S_ISLNK(mCachedStat.st_mode) && + !S_ISREG(mCachedStat.st_mode) && + !S_ISDIR(mCachedStat.st_mode); return NS_OK; } @@ -1178,45 +1154,40 @@ nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) NS_ENSURE_ARG(inFile); NS_ENSURE_ARG_POINTER(_retval); *_retval = PR_FALSE; - + nsresult rv; nsXPIDLCString myPath, inPath; - + if (NS_FAILED(rv = GetPath(getter_Copies(myPath)))) return rv; if (NS_FAILED(rv = inFile->GetPath(getter_Copies(inPath)))) return rv; - *_retval = !FILE_STRCMP(inPath, myPath); + *_retval = !FILE_STRCMP(inPath, myPath); return NS_OK; } NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) { + CHECK_mPath(); NS_ENSURE_ARG(inFile); NS_ENSURE_ARG_POINTER(_retval); - + nsXPIDLCString inPath; nsresult rv; - - *_retval = PR_FALSE; if (NS_FAILED(rv = inFile->GetPath(getter_Copies(inPath)))) return rv; - + + *_retval = PR_FALSE; + ssize_t len = strlen(mPath); - - if ( FILE_STRNCMP( mPath, inPath, len) == 0) - { - // now make sure that the |inFile|'s path has a trailing - // separator. - + if (FILE_STRNCMP(mPath, inPath, len) == 0) { + // Now make sure that the |inFile|'s path has a separator at len, + // which implies that it has more components after len. if (inPath[len] == '/') - { *_retval = PR_TRUE; - } - } return NS_OK; @@ -1225,7 +1196,9 @@ nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) NS_IMETHODIMP nsLocalFile::GetTarget(char **_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); + VALIDATE_STAT_CACHE(); if (!S_ISLNK(mCachedStat.st_mode)) return NS_ERROR_FILE_INVALID_PATH; @@ -1234,19 +1207,19 @@ nsLocalFile::GetTarget(char **_retval) if (NS_FAILED(GetFileSizeOfLink(&targetSize64))) return NS_ERROR_FAILURE; - PRInt32 hi, lo; - mLL_L2II(targetSize64, hi, lo); - char *target = (char *)nsMemory::Alloc(lo); + PRInt32 size; + LL_L2I(size, targetSize64); + char *target = (char *)nsMemory::Alloc(size + 1); if (!target) return NS_ERROR_OUT_OF_MEMORY; - int result = readlink(mPath, target, (size_t)lo); - if (!result) { - *_retval = target; - return NS_OK; + if (readlink(mPath, target, (size_t)size) < 0) { + nsMemory::Free(target); + return NSRESULT_FOR_ERRNO(); } - nsMemory::Free(target); - return NSRESULT_FOR_ERRNO(); + target[size] = '\0'; + *_retval = target; + return NS_OK; } NS_IMETHODIMP @@ -1254,50 +1227,42 @@ nsLocalFile::Spawn(const char **args, PRUint32 count) { CHECK_mPath(); - // status from our create process - PRStatus rv = PR_FAILURE; - - // this is the argv that will hold the args that - char ** my_argv = NULL; - // make sure that when we allocate we have 1 greater than the // count since we need to null terminate the list for the argv to // pass into PR_CreateProcessDetached - my_argv = (char **)malloc(sizeof(char *) * (count + 2) ); - if (!my_argv) { + char **my_argv = (char **)malloc(sizeof(char *) * (count + 2) ); + if (!my_argv) return NS_ERROR_OUT_OF_MEMORY; - } + // copy the args PRUint32 i; - for (i=0; i < count; i++) { + for (i=0; i < count; i++) my_argv[i+1] = (char *)args[i]; - } + // we need to set argv[0] to the program name. my_argv[0] = (char *)(const char *)mPath; - - // null terminate the array - my_argv[count+1] = NULL; - rv = PR_CreateProcessDetached(mPath, my_argv, NULL, NULL); + // null terminate the array + my_argv[count+1] = nsnull; + + PRStatus rv = PR_CreateProcessDetached(mPath, my_argv, nsnull, nsnull); // free up our argv free(my_argv); - if (PR_SUCCESS == rv) - return NS_OK; - else + if (rv != PR_SUCCESS) return NS_ERROR_FILE_EXECUTION_FAILED; + return NS_OK; } - /* attribute PRBool followLinks; */ -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) { *aFollowLinks = PR_TRUE; return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks) { return NS_OK; @@ -1306,17 +1271,15 @@ nsLocalFile::SetFollowLinks(PRBool aFollowLinks) NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries) { - nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + nsCOMPtr dir = new nsDirEnumeratorUnix(); if (!dir) return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = dir->Init(this, PR_FALSE); - if (NS_FAILED(rv)) { - delete dir; - return rv; - } - /* QI needed? */ + nsresult rv = dir->Init(this, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + /* QI needed? If not, need to ADDREF. */ return dir->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)entries); } @@ -1334,7 +1297,9 @@ NS_IMETHODIMP nsLocalFile::SetURL(const char * aURL) NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) { + CHECK_mPath(); NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_LoadLibrary(mPath); if (!*_retval) return NS_ERROR_FAILURE; @@ -1342,24 +1307,24 @@ nsLocalFile::Load(PRLibrary **_retval) } NS_IMETHODIMP -nsLocalFile::GetPersistentDescriptor(char * *aPersistentDescriptor) +nsLocalFile::GetPersistentDescriptor(char **aPersistentDescriptor) { NS_ENSURE_ARG_POINTER(aPersistentDescriptor); return GetPath(aPersistentDescriptor); } NS_IMETHODIMP -nsLocalFile::SetPersistentDescriptor(const char * aPersistentDescriptor) +nsLocalFile::SetPersistentDescriptor(const char *aPersistentDescriptor) { - NS_ENSURE_ARG(aPersistentDescriptor); - return InitWithPath(aPersistentDescriptor); + NS_ENSURE_ARG(aPersistentDescriptor); + return InitWithPath(aPersistentDescriptor); } -nsresult -NS_NewLocalFile(const char* path, PRBool followSymlinks, nsILocalFile* *result) +nsresult +NS_NewLocalFile(const char *path, PRBool followSymlinks, nsILocalFile **result) { - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) + nsLocalFile *file = new nsLocalFile(); + if (!file) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(file); diff --git a/mozilla/xpcom/io/nsLocalFileUnix.h b/mozilla/xpcom/io/nsLocalFileUnix.h index 7cc7342e5e7..29026f53160 100644 --- a/mozilla/xpcom/io/nsLocalFileUnix.h +++ b/mozilla/xpcom/io/nsLocalFileUnix.h @@ -38,7 +38,7 @@ #include "nsLocalFile.h" #include "nsXPIDLString.h" -#define NSRESULT_FOR_RETURN(ret) (!(ret) ? NS_OK : NSRESULT_FOR_ERRNO()) +#define NSRESULT_FOR_RETURN(ret) (((ret) < 0) ? NSRESULT_FOR_ERRNO() : NS_OK) inline nsresult nsresultForErrno(int err) @@ -94,6 +94,8 @@ protected: nsresult CreateAllAncestors(PRUint32 permissions); nsresult GetLeafNameRaw(const char **_retval); + nsresult GetTargetPathName(nsIFile *newParent, const char *newName, + char **_retval); void InvalidateCache() { mHaveCachedStat = PR_FALSE; } @@ -109,4 +111,5 @@ protected: } }; + #endif /* _nsLocalFileUNIX_H_ */