diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 2006a7381750..92e6a8e6f8d9 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -257,8 +257,13 @@ myLL_L2II(PRInt64 result, PRInt32 *hi, PRInt32 *lo ) LL_L2I(*lo, a64); } -static PRBool IsShortcut(const char* workingPath, int filePathLen) +static PRBool +IsShortcut(const char* workingPath, int filePathLen) { + // XXX this is badly broken!! + // XXX consider "C:\FOO.LNK" + // XXX consider "C:\foo.lnkx\bar.lnk" + // check to see if it is shortcut, i.e., it has ".lnk" in it unsigned char* dest = _mbsstr((unsigned char*)workingPath, (unsigned char*)".lnk"); @@ -277,10 +282,8 @@ static PRBool IsShortcut(const char* workingPath, int filePathLen) return PR_FALSE; } return PR_TRUE; - } - //----------------------------------------------------------------------------- // nsDirEnumerator //----------------------------------------------------------------------------- @@ -448,13 +451,6 @@ nsLocalFile::nsLocalFile(const nsLocalFile& other) { } -// This function resets any cached information about the file. -void -nsLocalFile::MakeDirty() -{ - mDirty = PR_TRUE; -} - // ResolvePath // this function will walk the native path of |this| resolving any symbolic // links found. The new resulting path will be placed into mResolvedPath. @@ -545,7 +541,7 @@ nsLocalFile::ResolvePath(const char* workingPath, PRBool resolveTerminal, char** // check to see the file is a shortcut by the magic .lnk extension. size_t offset = strlen(filePath) - 4; - if ((offset > 0) && (strncmp( (filePath + offset), ".lnk", 4) == 0)) + if ((offset > 0) && (strnicmp( (filePath + offset), ".lnk", 4) == 0)) { nsAutoString ucsBuf; NS_CopyNativeToUnicode(nsDependentCString(filePath), ucsBuf); @@ -662,7 +658,7 @@ nsLocalFile::ResolveAndStat(PRBool resolveTerminal) // if we found the file and we are not following symlinks, then return success. - if (!mFollowSymlinks || pathLen < 4 || (strcmp(leaf, ".lnk") != 0)) + if (!mFollowSymlinks || pathLen < 4 || (stricmp(leaf, ".lnk") != 0)) { mDirty = PR_FALSE; return NS_OK; @@ -1239,26 +1235,20 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool fol return NS_ERROR_FILE_DIR_NOT_EMPTY; } - - nsDirEnumerator* dirEnum = new nsDirEnumerator(); - if (!dirEnum) - return NS_ERROR_OUT_OF_MEMORY; - - rv = dirEnum->Init(this); + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); if (NS_FAILED(rv)) { NS_WARNING("dirEnum initalization failed"); return rv; } - nsCOMPtr iterator = do_QueryInterface(dirEnum); - PRBool more; - iterator->HasMoreElements(&more); - while (more) + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) { nsCOMPtr item; nsCOMPtr file; - iterator->GetNext(getter_AddRefs(item)); + dirEnum.GetNext(getter_AddRefs(item)); file = do_QueryInterface(item); if (file) { @@ -1284,7 +1274,6 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool fol NS_ENSURE_SUCCESS(rv,rv); } } - iterator->HasMoreElements(&more); } // we've finished moving all the children of this directory // in the new directory. so now delete the directory @@ -1373,46 +1362,78 @@ nsLocalFile::Load(PRLibrary * *_retval) NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive) { - PRBool isDir; - - nsresult rv = IsDirectory(&isDir); - if (NS_FAILED(rv)) - return rv; + nsresult rv; + PRBool isDir, isLink; + nsXPIDLCString buf; + const char *filePath; + + // NOTE: + // + // if the working path points to a shortcut, then we will only + // delete the shortcut itself. even if the shortcut points to + // a directory, we will not recurse into that directory or + // delete that directory itself. likewise, if the shortcut + // points to a normal file, we will not delete the real file. + // this is done to be consistent with the other platforms that + // behave this way. we do this even if the followLinks attribute + // is set to true. this helps protect against misuse that could + // lead to security bugs (e.g., bug 210588). + // + // in the case of non-terminal shortcuts, those are all followed + // unconditionally. this is done because 1) we only delete + // terminal nodes and possibly their children, and 2) the remove + // and rmdir CRT calls don't know how to handle shortcuts. + + IsSymlink(&isLink); + if (isLink) + { + isDir = PR_FALSE; + // resolve non-terminal nodes only. + rv = ResolvePath(mWorkingPath.get(), PR_FALSE, getter_Copies(buf)); + if (NS_FAILED(rv)) + return rv; + filePath = buf.get(); + } + else + { + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + // in this case, it doesn't matter that terminal nodes were + // resolved, so we can safely leverage mResolvedPath. + filePath = mResolvedPath.get(); + } - const char *filePath = mResolvedPath.get(); - if (isDir) { if (recursive) { - nsDirEnumerator* dirEnum = new nsDirEnumerator(); - if (dirEnum == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - rv = dirEnum->Init(this); + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); + if (NS_FAILED(rv)) + return rv; - nsCOMPtr iterator = do_QueryInterface(dirEnum); - PRBool more; - iterator->HasMoreElements(&more); - while (more) + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) { nsCOMPtr item; - nsCOMPtr file; - iterator->GetNext(getter_AddRefs(item)); - file = do_QueryInterface(item); + dirEnum.GetNext(getter_AddRefs(item)); + nsCOMPtr file = do_QueryInterface(item); if (file) file->Remove(recursive); - - iterator->HasMoreElements(&more); } } - rv = rmdir(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + rv = rmdir(filePath); } else { - rv = remove(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + rv = remove(filePath); } + + // fixup error code if necessary... + if (rv == -1) + rv = NSRESULT_FOR_ERRNO(); MakeDirty(); return rv; @@ -1858,16 +1879,15 @@ nsLocalFile::IsExecutable(PRBool *_retval) NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval) { - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; + NS_PRECONDITION(_retval, "null pointer"); nsresult rv = ResolveAndStat(PR_TRUE); - - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { + *_retval = PR_FALSE; return rv; + } *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); - return NS_OK; } @@ -1917,22 +1937,15 @@ nsLocalFile::IsHidden(PRBool *_retval) NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval) { - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; + NS_PRECONDITION(_retval, "null pointer"); - nsCAutoString path; - int pathLen; - - GetNativePath(path); - pathLen = path.Length(); - - const char* leaf = path.get() + pathLen - 4; - - if ( (strcmp(leaf, ".lnk") == 0)) - { - *_retval = PR_TRUE; + PRUint32 len = mWorkingPath.Length(); + if (len < 4) + *_retval = PR_FALSE; + else { + const char* leaf = mWorkingPath.get() + len - 4; + *_retval = (strnicmp(leaf, ".lnk", 4) == 0); } - return NS_OK; } diff --git a/xpcom/io/nsLocalFileWin.h b/xpcom/io/nsLocalFileWin.h index 411a40f98ea1..529c3dd4ac03 100644 --- a/xpcom/io/nsLocalFileWin.h +++ b/xpcom/io/nsLocalFileWin.h @@ -86,7 +86,7 @@ private: static PRBool mFSCharsetIsUTF8; - void MakeDirty(); + void MakeDirty() { mDirty = PR_TRUE; } nsresult ResolveAndStat(PRBool resolveTerminal); nsresult ResolvePath(const char* workingPath, PRBool resolveTerminal, char** resolvedPath);