Fixes 116299 Reduce size of nsLocalFileWin by 2 ptrs by factoring out shortcut resolver. Also fixes crash 117258 caused by trying to create a file or directory to a nonexistant drive. sr=rpotts, dveditz for the first bug, and sr=darin, r=gagan for the second bug

git-svn-id: svn://10.0.0.236/trunk@111541 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dougt%netscape.com
2002-01-08 02:20:13 +00:00
parent 38aa2bbb0e
commit 6b5bff699c
3 changed files with 203 additions and 134 deletions

View File

@@ -52,6 +52,120 @@
#include "prproces.h"
#include "nsITimelineService.h"
#include "nsAutoLock.h"
class ShortcutResolver
{
public:
ShortcutResolver();
virtual ~ShortcutResolver();
nsresult Init();
nsresult Resolve(const unsigned short* in, char* out);
private:
PRLock* mLock;
IPersistFile* mPersistFile;
IShellLink* mShellLink;
};
ShortcutResolver::ShortcutResolver()
{
mLock = nsnull;
mPersistFile = nsnull;
mShellLink = nsnull;
}
ShortcutResolver::~ShortcutResolver()
{
if (mLock)
PR_DestroyLock(mLock);
// Release the pointer to the IPersistFile interface.
if (mPersistFile)
mPersistFile->Release();
// Release the pointer to the IShellLink interface.
if(mShellLink)
mShellLink->Release();
CoUninitialize();
}
nsresult
ShortcutResolver::Init()
{
CoInitialize(NULL); // FIX: we should probably move somewhere higher up during startup
mLock = PR_NewLock();
if (!mLock)
return NS_ERROR_FAILURE;
HRESULT hres = CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&mShellLink);
if (SUCCEEDED(hres))
{
// Get a pointer to the IPersistFile interface.
hres = mShellLink->QueryInterface(IID_IPersistFile, (void**)&mPersistFile);
}
if (mPersistFile == nsnull || mShellLink == nsnull)
return NS_ERROR_FAILURE;
return NS_OK;
}
// |out| must be an allocated buffer of size MAX_PATH
nsresult
ShortcutResolver::Resolve(const unsigned short* in, char* out)
{
nsAutoLock lock(mLock);
// see if we can Load the path.
HRESULT hres = mPersistFile->Load(in, STGM_READ);
if (FAILED(hres))
return NS_ERROR_FAILURE;
// Resolve the link.
hres = mShellLink->Resolve(nsnull, SLR_NO_UI );
if (FAILED(hres))
return NS_ERROR_FAILURE;
WIN32_FIND_DATA wfd;
// Get the path to the link target.
hres = mShellLink->GetPath( out, MAX_PATH, &wfd, SLGP_UNCPRIORITY );
if (FAILED(hres))
return NS_ERROR_FAILURE;
return NS_OK;
}
static ShortcutResolver * gResolver = nsnull;
nsresult NS_CreateShortcutResolver()
{
gResolver = new ShortcutResolver();
if (!gResolver)
return NS_ERROR_OUT_OF_MEMORY;
return gResolver->Init();
}
void NS_DestroyShortcutResolver()
{
delete gResolver;
gResolver = nsnull;
}
// certainly not all the error that can be
// encountered, but many of them common ones
static nsresult ConvertWinError(DWORD winErr)
@@ -245,9 +359,6 @@ NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator);
nsLocalFile::nsLocalFile()
{
NS_INIT_REFCNT();
mPersistFile = nsnull;
mShellLink = nsnull;
mLastResolution = PR_FALSE;
mFollowSymlinks = PR_FALSE;
MakeDirty();
@@ -255,13 +366,6 @@ nsLocalFile::nsLocalFile()
nsLocalFile::~nsLocalFile()
{
// Release the pointer to the IPersistFile interface.
if (mPersistFile)
mPersistFile->Release();
// Release the pointer to the IShellLink interface.
if(mShellLink)
mShellLink->Release();
}
/* nsISupports interface implementation. */
@@ -303,34 +407,16 @@ nsLocalFile::MakeDirty()
nsresult
nsLocalFile::ResolvePath(const char* workingPath, PRBool resolveTerminal, char** resolvedPath)
{
#ifdef DEBUG_dougt
printf("localfile - resolving symlink\n");
#endif
nsresult rv = NS_OK;
if (strstr(workingPath, ".lnk") == nsnull)
return NS_ERROR_FILE_INVALID_PATH;
if (mPersistFile == nsnull || mShellLink == nsnull)
{
HRESULT hres;
// FIX. This should be in a service.
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&mShellLink);
if (SUCCEEDED(hres))
{
// Get a pointer to the IPersistFile interface.
hres = mShellLink->QueryInterface(IID_IPersistFile, (void**)&mPersistFile);
}
if (mPersistFile == nsnull || mShellLink == nsnull)
{
return NS_ERROR_FILE_INVALID_PATH;
}
}
#ifdef DEBUG_dougt
printf("localfile - resolving symlink\n");
#endif
// Get the native path for |this|
char* filePath = (char*) nsMemory::Clone( workingPath, strlen(workingPath)+1 );
@@ -347,30 +433,27 @@ nsLocalFile::ResolvePath(const char* workingPath, PRBool resolveTerminal, char**
// Get the first slash.
char* slash = strchr(filePath, '\\');
if (slash == nsnull)
if (!slash && filePath[0] != nsnull && filePath[1] == ':' && filePath[2] == '\0')
{
if (filePath[0] != nsnull && filePath[1] == ':' && filePath[2] == '\0')
{
// we have a drive letter and a colon (eg 'c:'
// this is resolve already
int filePathLen = strlen(filePath);
char* rp = (char*) nsMemory::Alloc( filePathLen + 2 );
if (!rp)
return NS_ERROR_OUT_OF_MEMORY;
memcpy( rp, filePath, filePathLen );
rp[filePathLen] = '\\';
rp[filePathLen+1] = 0;
*resolvedPath = rp;
nsMemory::Free(filePath);
return NS_OK;
}
else
{
nsMemory::Free(filePath);
return NS_ERROR_FILE_INVALID_PATH;
}
// we have a drive letter and a colon (eg 'c:'
// this is resolve already
int filePathLen = strlen(filePath);
char* rp = (char*) nsMemory::Alloc( filePathLen + 2 );
if (!rp)
return NS_ERROR_OUT_OF_MEMORY;
memcpy( rp, filePath, filePathLen );
rp[filePathLen] = '\\';
rp[filePathLen+1] = 0;
*resolvedPath = rp;
nsMemory::Free(filePath);
return NS_OK;
}
else
{
nsMemory::Free(filePath);
return NS_ERROR_FILE_INVALID_PATH;
}
@@ -425,76 +508,57 @@ nsLocalFile::ResolvePath(const char* workingPath, PRBool resolveTerminal, char**
MultiByteToWideChar(CP_ACP, 0, linkStr, -1, wsz, MAX_PATH);
}
HRESULT hres;
// see if we can Load the path.
hres = mPersistFile->Load(wsz, STGM_READ);
char *temp = (char*) nsMemory::Alloc( MAX_PATH );
if (temp == nsnull)
return NS_ERROR_NULL_POINTER;
if (SUCCEEDED(hres))
if (gResolver)
rv = gResolver->Resolve(wsz, temp);
else
rv = NS_ERROR_FAILURE;
if (NS_SUCCEEDED(rv))
{
// Resolve the link.
hres = mShellLink->Resolve(nsnull, SLR_NO_UI );
if (SUCCEEDED(hres))
{
WIN32_FIND_DATA wfd;
char *temp = (char*) nsMemory::Alloc( MAX_PATH );
if (temp == nsnull)
return NS_ERROR_NULL_POINTER;
// Get the path to the link target.
hres = mShellLink->GetPath( temp, MAX_PATH, &wfd, SLGP_UNCPRIORITY );
if (SUCCEEDED(hres))
{
// found a new path.
// addend a slash on it since it does not come out of GetPath()
// with one only if it is a directory. If it is not a directory
// and there is more to append, than we have a problem.
struct stat st;
int statrv = stat(temp, &st);
if (0 == statrv && (_S_IFDIR & st.st_mode))
{
strcat(temp, "\\");
}
if (slash)
{
// save where we left off.
char *carot= (temp + strlen(temp) -1 );
// append all the stuff that we have not done.
strcat(temp, ++slash);
slash = carot;
}
nsMemory::Free(filePath);
filePath = temp;
// found a new path.
}
else
{
nsMemory::Free(temp);
}
}
else
// addend a slash on it since it does not come out of GetPath()
// with one only if it is a directory. If it is not a directory
// and there is more to append, than we have a problem.
struct stat st;
int statrv = stat(temp, &st);
if (0 == statrv && (_S_IFDIR & st.st_mode))
strcat(temp, "\\");
if (slash)
{
// could not resolve shortcut. Return error;
nsMemory::Free(filePath);
return NS_ERROR_FILE_INVALID_PATH;
// save where we left off.
char *carot= (temp + strlen(temp) -1 );
// append all the stuff that we have not done.
strcat(temp, ++slash);
slash = carot;
}
nsMemory::Free(filePath);
filePath = temp;
}
if (slash)
else
{
*slash = '\\';
++slash;
slash = strchr(slash, '\\');
// could not resolve shortcut. Return error;
nsMemory::Free(filePath);
return NS_ERROR_FILE_INVALID_PATH;
}
}
if (slash)
{
*slash = '\\';
++slash;
slash = strchr(slash, '\\');
}
// kill any trailing separator
@@ -695,24 +759,27 @@ nsLocalFile::Create(PRUint32 type, PRUint32 attributes)
// create nested directories to target
unsigned char* slash = _mbschr((const unsigned char*) mResolvedPath.get(), '\\');
// skip the first '\\'
++slash;
slash = _mbschr(slash, '\\');
while (slash)
if (slash)
{
*slash = '\0';
if (!CreateDirectoryA(mResolvedPath.get(), NULL)) {
rv = ConvertWinError(GetLastError());
if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv;
}
*slash = '\\';
// skip the first '\\'
++slash;
slash = _mbschr(slash, '\\');
while (slash)
{
*slash = '\0';
if (!CreateDirectoryA(mResolvedPath.get(), NULL)) {
rv = ConvertWinError(GetLastError());
if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv;
}
*slash = '\\';
++slash;
slash = _mbschr(slash, '\\');
}
}
if (type == NORMAL_FILE_TYPE)
{
PRFileDesc* file = PR_Open(mResolvedPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes);