diff options
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp')
-rw-r--r-- | src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp | 1742 |
1 files changed, 1742 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp new file mode 100644 index 00000000..269a13d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp @@ -0,0 +1,1742 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or 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 Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka <sobotka@axess.com> + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "prtypes.h" +#include "prio.h" + +#include <ctype.h> // needed for toupper +#include <string.h> + +#include "nsXPIDLString.h" +#include "nsReadableUtils.h" +#include "prproces.h" +#include "prthread.h" + + +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor); +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor); +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf); +static int isleadbyte(int c); + +#include <unistd.h> +#include <io.h> + + +static nsresult ConvertOS2Error(int err) +{ + nsresult rv; + + switch (err) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rv = NS_ERROR_FILE_NOT_FOUND; + break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_SAME_DEVICE: + rv = NS_ERROR_FILE_ACCESS_DENIED; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_HANDLE: + case ERROR_ARENA_TRASHED: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + case ERROR_CURRENT_DIRECTORY: + rv = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + case ERROR_WRITE_PROTECT: + rv = NS_ERROR_FILE_READ_ONLY; + break; + case ERROR_HANDLE_DISK_FULL: + rv = NS_ERROR_FILE_TOO_BIG; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + case ERROR_CANNOT_MAKE: + rv = NS_ERROR_FILE_ALREADY_EXISTS; + break; + case 0: + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +static void +myLL_L2II(PRInt64 result, PRInt32 *hi, PRInt32 *lo ) +{ + PRInt64 a64, b64; // probably could have been done with + // only one PRInt64, but these are macros, + // and I am a wimp. + + // shift the hi word to the low word, then push it into a long. + LL_SHR(a64, result, 32); + LL_L2I(*hi, a64); + + // shift the low word to the hi word first, then shift it back. + LL_SHL(b64, result, 32); + LL_SHR(a64, b64, 32); + LL_L2I(*lo, a64); +} + + +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mDir(nsnull) + { + } + + nsresult Init(nsILocalFile* parent) + { + nsCAutoString filepath; + parent->GetNativeTarget(filepath); + + if (filepath.IsEmpty()) + { + parent->GetNativePath(filepath); + } + + if (filepath.IsEmpty()) + { + return NS_ERROR_UNEXPECTED; + } + + mDir = PR_OpenDir(filepath.get()); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mParent = parent; + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv; + if (mNext == nsnull && mDir) + { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) + { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + nsCOMPtr<nsIFile> file; + rv = mParent->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(nsDependentCString(entry->name)); + if (NS_FAILED(rv)) + return rv; + + // make sure the thing exists. If it does, try the next one. + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + return HasMoreElements(result); + } + + mNext = do_QueryInterface(file); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + private: + ~nsDirEnumerator() + { + if (mDir) + { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + } + + protected: + PRDir* mDir; + nsCOMPtr<nsILocalFile> mParent; + nsCOMPtr<nsILocalFile> mNext; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + + +nsLocalFile::nsLocalFile() +{ + MakeDirty(); +} + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mDirty(other.mDirty) + , mWorkingPath(other.mWorkingPath) + , mFileInfo64(other.mFileInfo64) +{ +} + +/* nsISupports interface implementation. */ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + +// This function resets any cached information about the file. +void +nsLocalFile::MakeDirty() +{ + mDirty = PR_TRUE; +} + +nsresult +nsLocalFile::Stat() +{ + if (!mDirty) + return NS_OK; + + char temp[4]; + const char* workingFilePath = mWorkingPath.get(); + const char* nsprPath = workingFilePath; + + if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') { + temp[0] = workingFilePath[0]; + temp[1] = workingFilePath[1]; + temp[2] = '\\'; + temp[3] = '\0'; + nsprPath = temp; + } + + DosError(FERR_DISABLEHARDERR); + PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64); + DosError(FERR_ENABLEHARDERR); + if ( status == PR_SUCCESS ) + return NS_OK; + + return NS_ERROR_FILE_NOT_FOUND; +} + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + MakeDirty(); + + nsACString::const_iterator begin, end; + filePath.BeginReading(begin); + filePath.EndReading(end); + + // input string must not be empty + if (begin == end) + return NS_ERROR_FAILURE; + + char firstChar = *begin; + char secondChar = *(++begin); + + // just do a sanity check. if it has any forward slashes, it is not a Native path + // on windows. Also, it must have a colon at after the first char. + + char *path = nsnull; + PRInt32 pathLen = 0; + + if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) || // normal path + ( (firstChar == '\\') && (secondChar == '\\') ) ) // network path + { + // This is a native path + path = ToNewCString(filePath); + pathLen = filePath.Length(); + } + + if (path == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // kill any trailing '\' provided it isn't the second char of DBCS + PRInt32 len = pathLen - 1; + if (path[len] == '\\' && !::isleadbyte(path[len-1])) + { + path[len] = '\0'; + pathLen = len; + } + + mWorkingPath.Adopt(path, pathLen); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = PR_Open(mWorkingPath.get(), flags, mode); + + if (*_retval) + return NS_OK; + + return NS_ErrorAccordingToNSPR(); +} + + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = fopen(mWorkingPath.get(), mode); + + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // create nested directories to target + unsigned char* slash = _mbschr((const unsigned char*) mWorkingPath.get(), '\\'); + + + if (slash) + { + // skip the first '\\' + ++slash; + slash = _mbschr(slash, '\\'); + + while (slash) + { + *slash = '\0'; + + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) { + rv = ConvertOS2Error(rv); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; + } + *slash = '\\'; + ++slash; + slash = _mbschr(slash, '\\'); + } + } + + if (type == NORMAL_FILE_TYPE) + { + PRFileDesc* file = PR_Open(mWorkingPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes); + if (!file) return NS_ERROR_FILE_ALREADY_EXISTS; + + PR_Close(file); + return NS_OK; + } + + if (type == DIRECTORY_TYPE) + { + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) + return ConvertOS2Error(rv); + else + return NS_OK; + } + + return NS_ERROR_FILE_UNKNOWN_TYPE; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + // Append only one component. Check for subdirs. + // XXX can we avoid the PromiseFlatCString call? + if (_mbschr((const unsigned char*) PromiseFlatCString(node).get(), '\\') != nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + return AppendRelativeNativePath(node); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &node) +{ + // Cannot start with a / or have .. or have / anywhere + nsACString::const_iterator begin, end; + node.BeginReading(begin); + node.EndReading(end); + if (node.IsEmpty() || FindCharInReadable('/', begin, end)) + { + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } + MakeDirty(); + mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + const char* temp = mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\'); + + // if the working path is just a node without any lashes. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName.Assign(leaf); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + MakeDirty(); + + const unsigned char* temp = (const unsigned char*) mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp); + if (offset) + { + mWorkingPath.Truncate(offset+1); + } + mWorkingPath.Append(aLeafName); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +nsresult +nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, PRBool move) +{ + nsresult rv; + nsCAutoString filePath; + + nsCAutoString destPath; + destParent->GetNativeTarget(destPath); + + destPath.Append("\\"); + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + sourceFile->GetNativeLeafName(aFileName); + destPath.Append(aFileName); + } + else + { + destPath.Append(newName); + } + + rv = sourceFile->GetNativePath(filePath); + + if (NS_FAILED(rv)) + return rv; + + APIRET rc = NO_ERROR; + + if( move ) + { + rc = DosMove(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get())); + } + + if (!move || rc == ERROR_NOT_SAME_DEVICE || rc == ERROR_ACCESS_DENIED) { + /* will get an error if the destination and source files aren't on the + * same drive. "MoveFile()" on Windows will go ahead and move the + * file without error, so we need to do the same IBM-AKR + */ + do { + rc = DosCopy(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get()), DCPY_EXISTING); + if (rc == ERROR_TOO_MANY_OPEN_FILES) { + ULONG CurMaxFH = 0; + LONG ReqCount = 20; + APIRET rc2; + rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); + if (rc2 != NO_ERROR) { + break; + } + } + } while (rc == ERROR_TOO_MANY_OPEN_FILES); + + /* WSOD2 HACK */ + if (rc == 65) { // NETWORK_ACCESS_DENIED + CHAR achProgram[CCHMAXPATH]; // buffer for program name, parameters + RESULTCODES rescResults; // buffer for results of dosexecpgm + + strcpy(achProgram, "CMD.EXE /C "); + strcat(achProgram, """COPY "); + strcat(achProgram, filePath.get()); + strcat(achProgram, " "); + strcat(achProgram, (PSZ)NS_CONST_CAST(char*, destPath.get())); + strcat(achProgram, """"); + achProgram[strlen(achProgram) + 1] = '\0'; + achProgram[7] = '\0'; + DosExecPgm(NULL, 0, + EXEC_SYNC, achProgram, (PSZ)NULL, + &rescResults, achProgram); + rc = 0; // Assume it worked + + } /* rc == 65 */ + /* moving the file is supposed to act like a rename, so delete the + * original file if we got this far without error + */ + if( move && (rc == NO_ERROR) ) + { + DosDelete( filePath.get() ); + } + } /* !move or ERROR */ + + if (rc) + rv = ConvertOS2Error(rc); + + return rv; +} + + +nsresult +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool move) +{ + nsCOMPtr<nsIFile> newParentDir = aParentDir; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + if (!newParentDir) + { + // no parent was specified. We must rename. + + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + if (!newParentDir) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + // make sure it exists and is a directory. Create it if not there. + PRBool exists; + newParentDir->Exists(&exists); + if (exists == PR_FALSE) + { + rv = newParentDir->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + PRBool isDir; + newParentDir->IsDirectory(&isDir); + if (isDir == PR_FALSE) + { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + // check to see if we are a directory, if so enumerate it. + + PRBool isDir; + IsDirectory(&isDir); + + if (!isDir) + { + rv = CopySingleFile(this, newParentDir, newName, move); + if (NS_FAILED(rv)) + return rv; + } + else + { + // create a new target destination in the new parentDir; + nsCOMPtr<nsIFile> target; + rv = newParentDir->Clone(getter_AddRefs(target)); + + if (NS_FAILED(rv)) + return rv; + + nsCAutoString allocatedNewName; + if (newName.IsEmpty()) + { + GetNativeLeafName(allocatedNewName);// this should be the leaf name of the + } + else + { + allocatedNewName = newName; + } + + rv = target->AppendNative(allocatedNewName); + if (NS_FAILED(rv)) + return rv; + + allocatedNewName.Truncate(); + + target->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (!dirEnum) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr<nsISimpleEnumerator> iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr<nsISupports> item; + nsCOMPtr<nsIFile> file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + PRBool isDir, isLink; + + file->IsDirectory(&isDir); + + if (move) + { + rv = file->MoveToNative(target, nsCString()); + } + else + { + rv = file->CopyToNative(target, nsCString()); + } + + iterator->HasMoreElements(&more); + } + // we've finished moving all the children of this directory + // in the new directory. so now delete the directory + // note, we don't need to do a recursive delete. + // MoveTo() is recursive. At this point, + // we've already moved the children of the current folder + // to the new location. nothing should be left in the folder. + if (move) + { + rv = Remove(PR_FALSE); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + + // If we moved, we want to adjust this. + if (move) + { + MakeDirty(); + + nsCAutoString newParentPath; + newParentDir->GetNativePath(newParentPath); + + if (newParentPath.IsEmpty()) + return NS_ERROR_FAILURE; + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + GetNativeLeafName(aFileName); + + InitWithNativePath(newParentPath); + AppendNative(aFileName); + } + else + { + InitWithNativePath(newParentPath); + AppendNative(newName); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_TRUE); +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + *_retval = PR_LoadLibrary(mWorkingPath.get()); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + PRBool isDir; + + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + if (isDir) + { + if (recursive) + { + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr<nsISimpleEnumerator> iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr<nsISupports> item; + nsCOMPtr<nsIFile> file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + + file->Remove(recursive); + + iterator->HasMoreElements(&more); + } + } + rv = rmdir(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + else + { + rv = remove(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + *aLastModifiedTime = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + // microseconds -> milliseconds + *aLastModifiedTime = mFileInfo64.modifyTime / PR_USEC_PER_MSEC; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + return nsLocalFile::SetModDate(aLastModifiedTime); +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsLocalFile::SetModDate(PRInt64 aLastModifiedTime) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + PRExplodedTime pret; + FILESTATUS3 pathInfo; + + rv = DosQueryPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (NS_FAILED(rv)) + { + rv = ConvertOS2Error(rv); + return rv; + } + + // PR_ExplodeTime expects usecs... + PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret); + /* fdateLastWrite.year is based off of 1980 */ + if (pret.tm_year >= 1980) + pathInfo.fdateLastWrite.year = pret.tm_year-1980; + else + pathInfo.fdateLastWrite.year = pret.tm_year; + pathInfo.fdateLastWrite.month = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0 +// ???? OS2TODO st.wDayOfWeek = pret.tm_wday; + pathInfo.fdateLastWrite.day = pret.tm_mday; + pathInfo.ftimeLastWrite.hours = pret.tm_hour; + pathInfo.ftimeLastWrite.minutes = pret.tm_min; + pathInfo.ftimeLastWrite.twosecs = pret.tm_sec / 2; // adjust for twosecs? +// ??? OS2TODO st.wMilliseconds = pret.tm_usec/1000; + + rv = DosSetPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo), + 0UL); + + if (NS_FAILED(rv)) + return rv; + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + if( chmod(filePath, aPermissions) == -1 ) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + *aFileSize = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + + *aFileSize = mFileInfo64.size; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + APIRET rc; + HFILE hFile; + ULONG actionTaken; + + rc = DosOpen(filePath, + &hFile, + &actionTaken, + 0, + FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, + NULL); + + if (rc != NO_ERROR) + { + MakeDirty(); + return NS_ERROR_FAILURE; + } + + // Seek to new, desired end of file + PRInt32 hi, lo; + myLL_L2II(aFileSize, &hi, &lo ); + + rc = DosSetFileSize(hFile, lo); + if (rc == NO_ERROR) + DosClose(hFile); + else + goto error; + + MakeDirty(); + return NS_OK; + + error: + MakeDirty(); + DosClose(hFile); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + ULONG ulDriveNo = toupper(mWorkingPath.CharAt(0)) + 1 - 'A'; + FSALLOCATE fsAllocate; + APIRET rc = DosQueryFSInfo(ulDriveNo, + FSIL_ALLOC, + &fsAllocate, + sizeof(fsAllocate)); + + if (rc != NO_ERROR) + return NS_ERROR_FAILURE; + + *aDiskSpaceAvailable = fsAllocate.cUnitAvail; + *aDiskSpaceAvailable *= fsAllocate.cSectorUnit; + *aDiskSpaceAvailable *= fsAllocate.cbSector; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + + nsCAutoString parentPath(mWorkingPath); + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\') + - (const unsigned char *) parentPath.get()); + if (offset < 0) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + parentPath.Truncate(offset); + + nsCOMPtr<nsILocalFile> localFile; + nsresult rv = NS_NewNativeLocalFile(parentPath, PR_TRUE, getter_AddRefs(localFile)); + + if(NS_SUCCEEDED(rv) && localFile) + { + return CallQueryInterface(localFile, aParent); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + MakeDirty(); + *_retval = NS_SUCCEEDED(Stat()); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = !((pathInfo.attrFile & FILE_READONLY) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + GetNativeTarget(path); + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) path.get(), '\\'); + + if ( (strstr(leaf, ".bat") != nsnull) || + (strstr(leaf, ".exe") != nsnull) || + (strstr(leaf, ".cmd") != nsnull) || + (strstr(leaf, ".com") != nsnull) ) { + *_retval = PR_TRUE; + } else { + *_retval = PR_FALSE; + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_HIDDEN) != 0); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + // No Symlinks on OS/2 + *_retval = PR_FALSE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_SYSTEM) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsCAutoString inFilePath; + inFile->GetNativePath(inFilePath); + + *_retval = inFilePath.Equals(mWorkingPath); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsCAutoString myFilePath; + if ( NS_FAILED(GetNativeTarget(myFilePath))) + GetNativePath(myFilePath); + + PRInt32 myFilePathLen = myFilePath.Length(); + + nsCAutoString inFilePath; + if ( NS_FAILED(inFile->GetNativeTarget(inFilePath))) + inFile->GetNativePath(inFilePath); + + if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0) + { + // now make sure that the |inFile|'s path has a trailing + // separator. + + if (inFilePath[myFilePathLen] == '\\') + { + *_retval = PR_TRUE; + } + + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = PR_TRUE; + return NS_OK; +} +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +#ifndef OPEN_DEFAULT +#define OPEN_DEFAULT 0 +#define OPEN_CONTENTS 1 +#endif + + +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + PRBool isDirectory = PR_FALSE; + nsCAutoString path; + + IsDirectory(&isDirectory); + if (isDirectory) + { + GetNativePath(path); + } + else + { + nsCOMPtr<nsIFile> parent; + GetParent(getter_AddRefs(parent)); + if (parent) + parent->GetNativePath(path); + } + + HOBJECT hobject = WinQueryObject(path.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_CONTENTS, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + HOBJECT hobject = WinQueryObject(mWorkingPath.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_DEFAULT, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + + *result = file; + return NS_OK; +} + +// Locates the first occurrence of charToSearchFor in the stringToSearch +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor) +{ + const unsigned char* p = stringToSearch; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinNextChar(0,0,0,(char*)p); + } while (*p); /* enddo */ + // Result is p or NULL + return *p ? (unsigned char*)p : NULL; +} + +// Locates last occurence of charToSearchFor in the stringToSearch +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor) +{ + int length = strlen((const char*)stringToSearch); + const unsigned char* p = stringToSearch+length; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinPrevChar(0,0,0,(char*)stringToSearch,(char*)p); + } while (p > stringToSearch); /* enddo */ + // Result is p or NULL + return (*p == charToSearchFor) ? (unsigned char*)p : NULL; +} + +// Implement equivalent of Win32 CreateDirectoryA +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf) +{ + APIRET rc; + nsresult rv; + FILESTATUS3 pathInfo; + + rc = DosCreateDir( path, ppEABuf ); + if (rc != NO_ERROR) { + rv = ConvertOS2Error(rc); + + // Check if directory already exists and if so, reflect that in the return value + rc = DosQueryPathInfo(path, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + if (rc == NO_ERROR) + rv = ERROR_FILE_EXISTS; + } + else + rv = rc; + + return rv; +} + +static int isleadbyte(int c) +{ + static BOOL bDBCSFilled=FALSE; + static BYTE DBCSInfo[12] = { 0 }; /* According to the Control Program Guide&Ref, + 12 bytes is sufficient */ + BYTE *curr; + BOOL retval = FALSE; + + if( !bDBCSFilled ) { + COUNTRYCODE ctrycodeInfo = { 0 }; + APIRET rc = NO_ERROR; + ctrycodeInfo.country = 0; /* Current Country */ + ctrycodeInfo.codepage = 0; /* Current Codepage */ + + rc = DosQueryDBCSEnv( sizeof( DBCSInfo ), + &ctrycodeInfo, + DBCSInfo ); + if( rc != NO_ERROR ) { + /* we had an error, do something? */ + return FALSE; + } + bDBCSFilled=TRUE; + } + + curr = DBCSInfo; + /* DBCSInfo returned by DosQueryDBCSEnv is terminated with two '0' bytes in a row */ + while(( *curr != 0 ) && ( *(curr+1) != 0)) { + if(( c >= *curr ) && ( c <= *(curr+1) )) { + retval=TRUE; + break; + } + curr+=2; + } + + return retval; +} + +NS_IMETHODIMP +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + if (filePath.IsEmpty()) + return InitWithNativePath(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(filePath, tmp); + + if (NS_SUCCEEDED(rv)) + return InitWithNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Append(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendNative(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendRelativeNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = GetNativeLeafName(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, aLeafName); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + if (aLeafName.IsEmpty()) + return SetNativeLeafName(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp); + + if (NS_SUCCEEDED(rv)) + return SetNativeLeafName(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mWorkingPath, _retval); +} + +NS_IMETHODIMP +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToFollowingLinksNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return MoveToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsCAutoString tmp; + nsresult rv = GetNativeTarget(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, _retval); + + return rv; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) { + *result = nsnull; + return rv; + } + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//---------------------------------------------------------------------------- +// global init/shutdown +//---------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} |