1472 lines
39 KiB
C++
1472 lines
39 KiB
C++
// Storage.cpp -- Implementation of class CStorage
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
DEBUGDEF(LONG CStorage:: CImpIStorage::s_cInCriticalSection = 0)
|
|
DEBUGDEF(LONG CFSStorage::CImpIFSStorage::s_cInCriticalSection = 0)
|
|
|
|
HRESULT STDMETHODCALLTYPE CopyStorage(IStorage *pStgDest, IStorage *pStgSrc,
|
|
BOOL fCopyStorages, BOOL fCopyStreams
|
|
)
|
|
{
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
IEnumSTATSTG *pEnumStatStg = NULL;
|
|
|
|
hr = pStgSrc->EnumElements(0, NULL, 0, &pEnumStatStg);
|
|
|
|
if (hr != S_OK) return hr;
|
|
|
|
typedef struct _NameList
|
|
{
|
|
struct _NameList *pNextName;
|
|
const WCHAR *pStorageName;
|
|
|
|
} NameList, *PNameList;
|
|
|
|
NameList *pNLHead = NULL;
|
|
|
|
const WCHAR *pwcsItem = NULL;
|
|
|
|
for (; ;)
|
|
{
|
|
STATSTG statstg;
|
|
ULONG cElts;
|
|
|
|
hr = pEnumStatStg->Next(1, &statstg, &cElts);
|
|
|
|
if (hr == S_FALSE) break;
|
|
|
|
if (hr == S_OK && cElts != 1)
|
|
hr = STG_E_UNKNOWN;
|
|
|
|
if (hr != S_OK) break;
|
|
|
|
IStream *pStrmDest = NULL,
|
|
*pStrmSrc = NULL;
|
|
|
|
pwcsItem = (const WCHAR *) statstg.pwcsName;
|
|
|
|
switch(statstg.type)
|
|
{
|
|
case STGTY_STORAGE:
|
|
|
|
if (!fCopyStorages) break;
|
|
|
|
{
|
|
PNameList pNL = New NameList;
|
|
|
|
pNL->pNextName = pNLHead;
|
|
pNL->pStorageName = pwcsItem;
|
|
|
|
pwcsItem = NULL;
|
|
|
|
pNLHead = pNL;
|
|
}
|
|
|
|
break;
|
|
|
|
case STGTY_STREAM:
|
|
|
|
if (!fCopyStreams) break;
|
|
|
|
hr = pStgDest->CreateStream(pwcsItem,
|
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE
|
|
| STGM_CREATE,
|
|
0, 0, &pStrmDest
|
|
);
|
|
|
|
if (hr != S_OK) break;
|
|
|
|
hr = pStgSrc->OpenStream(pwcsItem, NULL, STGM_READ | STGM_SHARE_DENY_NONE,
|
|
0, &pStrmSrc
|
|
);
|
|
|
|
if (hr != S_OK) break;
|
|
|
|
hr = pStrmSrc->CopyTo(pStrmDest, statstg.cbSize, NULL, NULL);
|
|
|
|
break;
|
|
|
|
case STGTY_LOCKBYTES:
|
|
case STGTY_PROPERTY:
|
|
default:
|
|
hr = STG_E_UNKNOWN;
|
|
|
|
break;
|
|
}
|
|
|
|
if (pwcsItem)
|
|
{
|
|
OLEHeap()->Free((void *) pwcsItem);
|
|
pwcsItem = NULL;
|
|
}
|
|
|
|
if (pStrmDest)
|
|
{
|
|
pStrmDest->Release();
|
|
pStrmDest = NULL;
|
|
}
|
|
|
|
if (pStrmSrc)
|
|
{
|
|
pStrmSrc->Release();
|
|
pStrmSrc = NULL;
|
|
}
|
|
|
|
if (hr != S_OK) break;
|
|
}
|
|
|
|
pEnumStatStg->Release();
|
|
pEnumStatStg = NULL;
|
|
|
|
RonM_ASSERT(hr != S_OK);
|
|
|
|
if (hr == S_FALSE)
|
|
hr = S_OK;
|
|
|
|
for (;;)
|
|
{
|
|
PNameList pNL = pNLHead;
|
|
|
|
if (!pNL) break;
|
|
|
|
pNLHead = pNL->pNextName;
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
IStorage *pStgChildDest = NULL,
|
|
*pStgChildSrc = NULL;
|
|
|
|
hr = pStgDest->CreateStorage(pNL->pStorageName,
|
|
STGM_READWRITE | STGM_SHARE_EXCLUSIVE
|
|
| STGM_CREATE,
|
|
0, 0, &pStgChildDest
|
|
);
|
|
|
|
if (hr == S_OK)
|
|
hr = pStgSrc->OpenStorage(pNL->pStorageName, NULL,
|
|
STGM_READ | STGM_SHARE_DENY_NONE,
|
|
NULL, 0, &pStgChildSrc
|
|
);
|
|
|
|
if (hr == S_OK)
|
|
hr = CopyStorage(pStgChildDest, pStgChildSrc, fCopyStorages, fCopyStreams);
|
|
|
|
if (pStgChildDest)
|
|
pStgChildDest->Release();
|
|
|
|
if (pStgChildSrc)
|
|
pStgChildSrc->Release();
|
|
}
|
|
|
|
OLEHeap()->Free((void *) pNL->pStorageName);
|
|
|
|
delete pNL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::OpenStorage(IUnknown *pUnkOuter,
|
|
IITFileSystem *pITFS,
|
|
PathInfo *pPathInfo,
|
|
DWORD grfMode,
|
|
IStorageITEx **ppStg
|
|
)
|
|
{
|
|
CStorage *pstg = New CStorage(pUnkOuter);
|
|
|
|
return FinishSetup(pstg? pstg->m_ImpIStorage.InitOpenStorage(pITFS, pPathInfo, grfMode)
|
|
: STG_E_INSUFFICIENTMEMORY,
|
|
pstg, IID_IStorageITEx, (PPVOID) ppStg
|
|
);
|
|
}
|
|
|
|
|
|
CStorage::CImpIStorage::CImpIStorage(CStorage *pBackObj, IUnknown *pUnkOuter)
|
|
: IIT_IStorageITEx(pBackObj, pUnkOuter, this->m_PathInfo.awszStreamPath)
|
|
{
|
|
m_pITFS = NULL;
|
|
m_grfMode = 0;
|
|
m_fWritable = FALSE;
|
|
|
|
ZeroMemory(&m_PathInfo, sizeof m_PathInfo);
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::InitOpenStorage
|
|
(IITFileSystem *pITFS, PathInfo *pPathInfo, DWORD grfMode)
|
|
{
|
|
pITFS->AddRef();
|
|
|
|
m_pITFS = pITFS;
|
|
m_PathInfo = *pPathInfo;
|
|
m_grfMode = grfMode;
|
|
m_fWritable = S_OK == m_pITFS->IsWriteable();
|
|
|
|
m_pITFS->ConnectStorage(this);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
CStorage::CImpIStorage::~CImpIStorage(void)
|
|
{
|
|
if (ActiveMark())
|
|
MarkInactive();
|
|
|
|
if (m_PathInfo.awszStreamPath[0] != L'/')
|
|
m_pITFS->FSObjectReleased();
|
|
|
|
m_pITFS->Release();
|
|
}
|
|
|
|
// IUnknown methods:
|
|
|
|
STDMETHODIMP_(ULONG) CStorage::CImpIStorage::Release(void)
|
|
{
|
|
// The actual work for the Release function is done by
|
|
// CImpITUnknown::Release() and ~CImpIStorage.
|
|
//
|
|
// We bracket that work as a critical section active storages
|
|
// are kept in a linked list. A release operation may remove
|
|
// this storage from that list, and we need to guard against
|
|
// having someone find a reference to this storage just before
|
|
// we destroy it.
|
|
|
|
CSyncWith sw(g_csITFS);
|
|
|
|
ULONG ulCnt = CImpITUnknown::Release();
|
|
|
|
return ulCnt;
|
|
}
|
|
|
|
// IStorage methods:
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::CreateStream(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD reserved1,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pITFS->CreateStream(NULL, awszNewBasePath, grfMode, (IStreamITEx **) ppstm);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* [local] */ HRESULT __stdcall CStorage::CImpIStorage::OpenStream(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ void __RPC_FAR *reserved1,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
|
|
{
|
|
return OpenStreamITEx(pwcsName, reserved1, grfMode, reserved2, (IStreamITEx **)ppstm);
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::CreateStorage(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD dwStgFmt,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pITFS->CreateStorage(NULL, awszNewBasePath, grfMode, (IStorageITEx **) ppstg);
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::OpenStorage(
|
|
/* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgPriority,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [unique][in] */ SNB snbExclude,
|
|
/* [in] */ DWORD reserved,
|
|
/* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pITFS->OpenStorage(NULL, awszNewBasePath, grfMode, (IStorageITEx **) ppstg);
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL CStorage::ValidStreamName(const WCHAR *pwcsName)
|
|
{
|
|
UINT cwcName = wcsLen(pwcsName);
|
|
|
|
if (!cwcName)
|
|
return FALSE;
|
|
|
|
for (; cwcName--; )
|
|
{
|
|
WCHAR wc = *pwcsName++;
|
|
|
|
if (wc < 0x20 || wc == L'<'
|
|
|| wc == L'>'
|
|
|| wc == L':'
|
|
|| wc == L'"'
|
|
|| wc == L'|'
|
|
|| wc == L'/'
|
|
|| wc == L'\\'
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall ResolvePath(PWCHAR pwcFullPath, const WCHAR *pwcBasePath,
|
|
const WCHAR *pwcRelativePath,
|
|
BOOL fStoragePath
|
|
)
|
|
{
|
|
if (pwcBasePath[0] != 0)
|
|
wcsCpy(pwcFullPath, pwcBasePath);
|
|
else
|
|
if ( (pwcRelativePath[0] == L'/' || pwcRelativePath[0] == L'\\')
|
|
&& (pwcRelativePath[1] == L'/' || pwcRelativePath[1] == L'\\')
|
|
)
|
|
{
|
|
// This is a UNC path. We expect the syntax pattern //ServerName/
|
|
|
|
wcsCpy(pwcFullPath, L"//");
|
|
|
|
pwcRelativePath += 2;
|
|
|
|
PWCHAR pwcDest = pwcFullPath + 2;
|
|
|
|
// The code below copies across the server name.
|
|
|
|
for (;;)
|
|
{
|
|
WCHAR wc = *pwcRelativePath++;
|
|
|
|
if (wc == L'\\')
|
|
wc = L'/';
|
|
|
|
if (wc < 0x20 || wc == L'<'
|
|
|| wc == L'>'
|
|
|| wc == L':'
|
|
|| wc == L'"'
|
|
|| wc == L'|'
|
|
)
|
|
return STG_E_INVALIDNAME; // Invalid path character
|
|
|
|
if (pwcDest - pwcFullPath > MAX_PATH - 2)
|
|
return STG_E_INVALIDNAME;
|
|
|
|
*pwcDest++ = wc;
|
|
|
|
// The code below rejects server names "." and ".."
|
|
|
|
if (wc == L'/')
|
|
{
|
|
if (pwcDest[-2] == L'.')
|
|
if ( pwcDest[-3] == L'/'
|
|
|| (pwcDest[-3] == L'.' && pwcDest[-4] == L'/')
|
|
) return STG_E_INVALIDNAME;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pwcDest= 0;
|
|
}
|
|
else
|
|
if ( pwcRelativePath[0]
|
|
&& Is_WC_Letter(pwcRelativePath[0])
|
|
&& pwcRelativePath[1] == L':'
|
|
&& (pwcRelativePath[2] == L'/' || pwcRelativePath[2] == L'\\')
|
|
)
|
|
{
|
|
pwcFullPath[0] = pwcRelativePath[0];
|
|
pwcFullPath[1] = L':';
|
|
pwcFullPath[2] = L'/';
|
|
pwcFullPath[3] = 0;
|
|
|
|
pwcRelativePath += 3;
|
|
}
|
|
else
|
|
{
|
|
char aszCurrentDir[MAX_PATH];
|
|
|
|
UINT cch = GetCurrentDirectory(MAX_PATH, aszCurrentDir);
|
|
|
|
if (!cch)
|
|
return CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
|
|
|
|
UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
|
aszCurrentDir, lstrlenA(aszCurrentDir) + 1,
|
|
pwcFullPath, MAX_PATH
|
|
);
|
|
|
|
if (!cwc || cwc == MAX_PATH)
|
|
return STG_E_INVALIDNAME;
|
|
|
|
RonM_ASSERT(cwc >= 2 && pwcFullPath[cwc - 2] != L'/'
|
|
&& pwcFullPath[cwc - 2] != L'\\');
|
|
|
|
pwcFullPath[cwc - 1] = L'/';
|
|
pwcFullPath[cwc ] = 0;
|
|
|
|
PWCHAR pwc = pwcFullPath + --cwc;
|
|
|
|
for (; cwc--; )
|
|
{
|
|
WCHAR wc = *--pwc;
|
|
|
|
if (wc == L'\\')
|
|
*pwc = L'/';
|
|
}
|
|
}
|
|
|
|
RonM_ASSERT(pwcFullPath[0] != 0);
|
|
|
|
PWCHAR pwcBase = pwcFullPath;
|
|
|
|
if ( (pwcBase[0] == L'/' && pwcBase[1] == L'/')
|
|
|| (pwcBase[0] == L':' && pwcBase[1] == L':')
|
|
)
|
|
for (pwcBase += 2; L'/' != *pwcBase++; )
|
|
RonM_ASSERT(pwcBase[-1]);
|
|
else
|
|
if (Is_WC_Letter(pwcBase[0]) && pwcBase[1] == L':' && pwcBase[2] == L'/')
|
|
pwcBase += 3;
|
|
else pwcBase++;
|
|
|
|
RonM_ASSERT(pwcBase[-1] == L'/');
|
|
|
|
WCHAR wcFirst = *pwcRelativePath;
|
|
|
|
if (wcFirst == L'/' || wcFirst == L'\\')
|
|
{
|
|
if (*pwcFullPath == L':')
|
|
return STG_E_INVALIDNAME;
|
|
|
|
*pwcBase = 0;
|
|
++pwcRelativePath;
|
|
}
|
|
|
|
PWCHAR pwcNext= pwcFullPath + wcsLen(pwcFullPath);
|
|
|
|
for (;;)
|
|
{
|
|
WCHAR wc= *pwcRelativePath++;
|
|
|
|
if (wc == L'\\')
|
|
wc = L'/';
|
|
|
|
if (!wc || wc == L'/')
|
|
{
|
|
RonM_ASSERT(pwcNext >= pwcBase); // We start with at least "/" and
|
|
// never go shorter than that.
|
|
WCHAR wcLast = pwcNext[-1];
|
|
|
|
if (wcLast == L'/')
|
|
{
|
|
if (!wc)
|
|
break;
|
|
|
|
else return STG_E_INVALIDNAME; // Empty storage name
|
|
}
|
|
|
|
if (wcLast == L'.')
|
|
{
|
|
RonM_ASSERT(pwcNext > pwcBase); // Must be at least "/."
|
|
|
|
WCHAR wcNextToLast= pwcNext[-2];
|
|
|
|
if (wcNextToLast == L'/')
|
|
{
|
|
// We've found the pattern "<prefix>/./" which we convert to
|
|
// "<prefix>/".
|
|
|
|
pwcNext--;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (wcNextToLast == L'.')
|
|
{
|
|
RonM_ASSERT(pwcNext > pwcBase + 1); // Must be at least "/.."
|
|
|
|
if (pwcNext[-3] == L'/')
|
|
{
|
|
// We've found the pattern "<prefix>/<StorageName>/../"
|
|
// which we convert to "<prefix>/".
|
|
|
|
// We don't allow this for paths beginning with ":".
|
|
// Those are system paths. For example --
|
|
//
|
|
// ::Transform/{200EAF82-9006-11d0-9E15-00A0C922E6EC}/InstanceData/
|
|
|
|
if (*pwcFullPath == L':')
|
|
return STG_E_INVALIDNAME;
|
|
|
|
// We must verify that we don't have "/../"
|
|
|
|
if (pwcNext == pwcBase + 2) // Can't back up beyond root!
|
|
return STG_E_INVALIDNAME;
|
|
|
|
for (pwcNext-= 4; *pwcNext != L'/'; pwcNext--);
|
|
|
|
++pwcNext;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wc || fStoragePath) // Trailing null adds a "/" only when we're
|
|
*pwcNext++ = L'/'; // constructing a directory path.
|
|
|
|
if (pwcNext - pwcFullPath >= MAX_PATH)
|
|
return STG_E_INVALIDNAME; // BugBug: Really should be "path too long".
|
|
|
|
if (!wc)
|
|
break;
|
|
else continue;
|
|
}
|
|
|
|
if (wc < 0x20 || wc == L'<'
|
|
|| wc == L'>'
|
|
|| wc == L':'
|
|
|| wc == L'"'
|
|
|| wc == L'|'
|
|
)
|
|
return STG_E_INVALIDNAME; // Invalid path character
|
|
|
|
*pwcNext++ = wc;
|
|
|
|
if (pwcNext - pwcFullPath >= MAX_PATH)
|
|
return STG_E_INVALIDNAME; // BugBug: Really should be "path too long".
|
|
}
|
|
|
|
RonM_ASSERT(pwcNext > pwcFullPath);
|
|
|
|
if (!fStoragePath && pwcNext[-1] == L'/')
|
|
return STG_E_INVALIDNAME; // BugBug: Really should be "Not a valid stream name"
|
|
|
|
*pwcNext= 0;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT STGCopyTo(IStorage *pStgSrc, DWORD ciidExclude, const IID __RPC_FAR *rgiidExclude,
|
|
SNB snbExclude, IStorage __RPC_FAR *pstgDest
|
|
)
|
|
{
|
|
if (snbExclude)
|
|
return STG_E_UNIMPLEMENTEDFUNCTION;
|
|
|
|
BOOL fCopyStorages = TRUE,
|
|
fCopyStreams = TRUE;
|
|
|
|
for (; ciidExclude--; rgiidExclude++)
|
|
{
|
|
if (*rgiidExclude == IID_IStorage)
|
|
fCopyStorages = FALSE;
|
|
|
|
if (*rgiidExclude == IID_IStream)
|
|
fCopyStreams = FALSE;
|
|
}
|
|
|
|
return CopyStorage(pstgDest, pStgSrc, fCopyStorages, fCopyStreams);
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::CopyTo(
|
|
/* [in] */ DWORD ciidExclude,
|
|
/* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude,
|
|
/* [unique][in] */ SNB snbExclude,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgDest)
|
|
{
|
|
return STGCopyTo((IStorage *) this, ciidExclude, rgiidExclude, snbExclude, pstgDest);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::MoveElementTo(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgDest,
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName,
|
|
/* [in] */ DWORD grfFlags)
|
|
{
|
|
RonM_ASSERT(FALSE); // To catch unexpected uses of this interface...
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::Commit(
|
|
/* [in] */ DWORD grfCommitFlags)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::Revert( void)
|
|
{
|
|
RonM_ASSERT(FALSE); // To catch unexpected uses of this interface...
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::EnumElements
|
|
(DWORD reserved1, void __RPC_FAR *reserved2,
|
|
DWORD reserved3,
|
|
IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum
|
|
)
|
|
{
|
|
return CEnumStorage::NewEnumStorage(NULL, m_pITFS, &m_PathInfo, ppenum);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::DestroyElement(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
// The call to ResolvePath combines pwcsName with the base path string
|
|
// associated with this storage. It will also force a trailing L'/' character.
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT cwc = lstrlenW(awszNewBasePath);
|
|
|
|
// Now we're going to delete the trailing '/' character to meet
|
|
// the needs of the DeleteItem method.
|
|
|
|
RonM_ASSERT(cwc > 0);
|
|
RonM_ASSERT(awszNewBasePath[cwc-1] == L'/');
|
|
awszNewBasePath[cwc-1] = 0;
|
|
|
|
hr = m_pITFS->DeleteItem(awszNewBasePath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::RenameElement(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName,
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName)
|
|
{
|
|
WCHAR awszOldBasePath[MAX_PATH];
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
// The calls to ResolvePath combine pwcsOldName and pwcsNewName with the base path string
|
|
// associated with this storage. It will also force a trailing L'/' character.
|
|
|
|
HRESULT hr = ResolvePath(awszOldBasePath, m_PathInfo.awszStreamPath, pwcsOldName, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsNewName, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Now we're going to delete the trailing '/' characters to meet
|
|
// the needs of the RenameItem method.
|
|
|
|
UINT cwc = lstrlenW(awszOldBasePath);
|
|
|
|
RonM_ASSERT(cwc > 0);
|
|
RonM_ASSERT(awszOldBasePath[cwc-1] == L'/');
|
|
|
|
awszOldBasePath[cwc-1] = 0;
|
|
|
|
cwc = lstrlenW(awszNewBasePath);
|
|
|
|
RonM_ASSERT(cwc > 0);
|
|
RonM_ASSERT(awszNewBasePath[cwc-1] == L'/');
|
|
|
|
awszNewBasePath[cwc-1] = 0;
|
|
|
|
hr = m_pITFS->RenameItem(awszOldBasePath, awszNewBasePath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::SetElementTimes(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ const FILETIME __RPC_FAR *pctime,
|
|
/* [in] */ const FILETIME __RPC_FAR *patime,
|
|
/* [in] */ const FILETIME __RPC_FAR *pmtime)
|
|
{
|
|
if ( m_PathInfo.cwcStreamPath != 1
|
|
&& m_PathInfo.awszStreamPath[0] != L'/'
|
|
&& S_OK != m_pITFS->SetITFSTimes(pctime, patime, pmtime)
|
|
)
|
|
return NO_ERROR;
|
|
|
|
return STG_E_UNIMPLEMENTEDFUNCTION;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::SetClass(
|
|
/* [in] */ REFCLSID clsid)
|
|
{
|
|
m_PathInfo.clsidStorage = clsid;
|
|
|
|
return m_pITFS->UpdatePathInfo(&m_PathInfo);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::SetStateBits(
|
|
/* [in] */ DWORD grfStateBits,
|
|
/* [in] */ DWORD grfMask)
|
|
{
|
|
m_PathInfo.uStateBits = (m_PathInfo.uStateBits & ~grfMask) | grfStateBits;
|
|
|
|
return m_pITFS->UpdatePathInfo(&m_PathInfo);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CStorage::CImpIStorage::Stat(
|
|
/* [out] */ STATSTG __RPC_FAR *pstatstg,
|
|
/* [in] */ DWORD grfStatFlag)
|
|
{
|
|
pstatstg->type = STGTY_STORAGE;
|
|
pstatstg->cbSize.LowPart = 0;
|
|
pstatstg->cbSize.HighPart = 0;
|
|
pstatstg->grfMode = m_grfMode;
|
|
pstatstg->grfLocksSupported = 0;
|
|
pstatstg->clsid = m_PathInfo.clsidStorage;
|
|
pstatstg->grfStateBits = m_PathInfo.uStateBits;
|
|
pstatstg->reserved = 0;
|
|
|
|
if ( m_PathInfo.cwcStreamPath != 1
|
|
|| m_PathInfo.awszStreamPath[0] != L'/'
|
|
|| S_OK != m_pITFS->GetITFSTimes(&(pstatstg->ctime),
|
|
&(pstatstg->atime),
|
|
&(pstatstg->mtime)
|
|
)
|
|
)
|
|
{
|
|
pstatstg->mtime.dwLowDateTime = 0;
|
|
pstatstg->ctime.dwLowDateTime = 0;
|
|
pstatstg->atime.dwLowDateTime = 0;
|
|
|
|
pstatstg->mtime.dwHighDateTime = 0;
|
|
pstatstg->ctime.dwHighDateTime = 0;
|
|
pstatstg->atime.dwHighDateTime = 0;
|
|
}
|
|
|
|
if (grfStatFlag == STATFLAG_NONAME)
|
|
pstatstg->pwcsName = NULL;
|
|
else
|
|
{
|
|
UINT cb = sizeof(WCHAR) * (m_PathInfo.cwcStreamPath + 1);
|
|
|
|
pstatstg->pwcsName = PWCHAR(OLEHeap()->Alloc(cb));
|
|
|
|
if (!pstatstg->pwcsName)
|
|
return STG_E_INSUFFICIENTMEMORY;
|
|
|
|
CopyMemory(pstatstg->pwcsName, m_PathInfo.awszStreamPath, cb);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::GetCheckSum(ULARGE_INTEGER *puli)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::CreateStreamITEx
|
|
(const WCHAR * pwcsName, const WCHAR *pwcsDataSpaceName,
|
|
DWORD grfMode, DWORD reserved1, DWORD reserved2,
|
|
IStreamITEx ** ppstm
|
|
)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pITFS->CreateStream(NULL, awszNewBasePath, pwcsDataSpaceName, grfMode, ppstm);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::OpenStreamITEx
|
|
(const OLECHAR * pwcsName, void * reserved1, DWORD grfMode,
|
|
DWORD reserved2, IStreamITEx ** ppstm
|
|
)
|
|
{
|
|
WCHAR awszNewBasePath[MAX_PATH];
|
|
|
|
HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = m_pITFS->OpenStream(NULL, awszNewBasePath, grfMode, ppstm);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CreateStorage
|
|
(IUnknown *pUnkOuter, const WCHAR *pwcsPath, DWORD grfMode,
|
|
IStorage **ppStg
|
|
)
|
|
{
|
|
CSyncWith sw(g_csITFS);
|
|
|
|
IStorage *pStorage = (IStorage *) CImpIFSStorage::FindStorage(pwcsPath, grfMode);
|
|
|
|
if (pStorage)
|
|
{
|
|
pStorage->Release();
|
|
|
|
return STG_E_INUSE;
|
|
}
|
|
|
|
CFSStorage *pstg = New CFSStorage(pUnkOuter);
|
|
|
|
return FinishSetup(pstg? pstg->m_ImpIFSStorage.InitCreateStorage(pwcsPath, grfMode)
|
|
: STG_E_INSUFFICIENTMEMORY,
|
|
pstg, IID_IStorage, (PPVOID) ppStg
|
|
);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::OpenStorage
|
|
(IUnknown *pUnkOuter, const WCHAR *pwcsPath, DWORD grfMode,
|
|
IStorage **ppStg
|
|
)
|
|
{
|
|
CSyncWith sw(g_csITFS);
|
|
|
|
IStorage *pStorage = CImpIFSStorage::FindStorage(pwcsPath, grfMode);
|
|
|
|
if (pStorage)
|
|
{
|
|
*ppStg = pStorage;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
CFSStorage *pstg = New CFSStorage(pUnkOuter);
|
|
|
|
return FinishSetup(pstg? pstg->m_ImpIFSStorage.InitOpenStorage(pwcsPath, grfMode)
|
|
: STG_E_INSUFFICIENTMEMORY,
|
|
pstg, IID_IStorage, (PPVOID) ppStg
|
|
);
|
|
}
|
|
|
|
|
|
CFSStorage::CImpIFSStorage::CImpIFSStorage(CFSStorage *pBackObj, IUnknown *punkOuter)
|
|
: IIT_IStorage(pBackObj, punkOuter, this->m_awcsPath)
|
|
{
|
|
m_awcsPath[0] = 0;
|
|
|
|
m_CP = GetACP();
|
|
}
|
|
|
|
CFSStorage::CImpIFSStorage::~CImpIFSStorage(void)
|
|
{
|
|
if (ActiveMark())
|
|
MarkInactive();
|
|
}
|
|
|
|
|
|
IStorage *CFSStorage::CImpIFSStorage::FindStorage(const WCHAR * pwszFileName, DWORD grfMode)
|
|
{
|
|
for (CImpITUnknown *pStg = g_pImpIFSStorageList;
|
|
pStg;
|
|
pStg = pStg->NextObject()
|
|
)
|
|
if (((CImpIFSStorage *)pStg)->IsNamed(pwszFileName))
|
|
{
|
|
pStg->AddRef();
|
|
|
|
return (IStorage *) pStg;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT __stdcall BuildMultiBytePath(UINT codepage, PCHAR pszPath, PWCHAR pwcsPath)
|
|
{
|
|
UINT cb = WideCharToMultiByte(codepage, WC_COMPOSITECHECK, pwcsPath,
|
|
wcsLen(pwcsPath) + 1, pszPath, MAX_PATH * 2,
|
|
NULL, NULL
|
|
);
|
|
|
|
if (cb == 0)
|
|
{
|
|
UINT uLastError = GetLastError();
|
|
|
|
switch(uLastError)
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
case ERROR_INVALID_FLAGS:
|
|
case ERROR_INVALID_PARAMETER:
|
|
|
|
return STG_E_INVALIDPARAMETER;
|
|
|
|
default:
|
|
|
|
return STG_E_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::InitCreateStorage(const WCHAR *pwcsPath, DWORD grfMode)
|
|
{
|
|
HRESULT hr = ResolvePath(m_awcsPath, m_awcsPath, pwcsPath, TRUE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
char achFullPath[MAX_PATH * 2];
|
|
|
|
hr = BuildMultiBytePath(m_CP, achFullPath, m_awcsPath);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
if (CreateDirectory(achFullPath, NULL))
|
|
hr = NO_ERROR;
|
|
else
|
|
hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
|
|
|
|
if (hr == S_OK)
|
|
MarkActive(g_pImpIFSStorageList);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::InitOpenStorage (const WCHAR *pwcsPath, DWORD grfMode)
|
|
{
|
|
HRESULT hr = ResolvePath(m_awcsPath, m_awcsPath, pwcsPath, TRUE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
char achFullPath[MAX_PATH * 2];
|
|
|
|
hr = BuildMultiBytePath(m_CP, achFullPath, m_awcsPath);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
WIN32_FIND_DATA fd;
|
|
|
|
HANDLE hFind = FindFirstFile(achFullPath, &fd);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
return CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
|
|
|
|
FindClose(hFind);
|
|
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
MarkActive(g_pImpIFSStorageList);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
return STG_E_INVALIDNAME;
|
|
}
|
|
|
|
|
|
// IUnknown methods:
|
|
|
|
STDMETHODIMP_(ULONG) CFSStorage::CImpIFSStorage::Release(void)
|
|
{
|
|
// The actual work for the Release function is done by
|
|
// CImpITUnknown::Release() and ~CImpIStorage.
|
|
//
|
|
// We bracket that work as a critical section active storages
|
|
// are kept in a linked list. A release operation may remove
|
|
// this storage from that list, and we need to guard against
|
|
// having someone find a reference to this storage just before
|
|
// we destroy it.
|
|
|
|
CSyncWith sw(g_csITFS);
|
|
|
|
ULONG ulCnt = CImpITUnknown::Release();
|
|
|
|
return ulCnt;
|
|
}
|
|
|
|
|
|
// IStorage methods:
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CreateStream(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD reserved1,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
|
|
{
|
|
WCHAR awcsStreamPath[MAX_PATH];
|
|
|
|
wcsCpy(awcsStreamPath, m_awcsPath);
|
|
|
|
HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, FALSE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
ILockBytes *pLKB = NULL;
|
|
|
|
hr = CFSLockBytes::Create(NULL, awcsStreamPath, grfMode, &pLKB);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CStream::OpenStream(NULL, pLKB, grfMode, (IStreamITEx **) ppstm);
|
|
|
|
if (hr != S_OK)
|
|
pLKB->Release();
|
|
}
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::OpenStream(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ void __RPC_FAR *reserved1,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
|
|
{
|
|
WCHAR awcsStreamPath[MAX_PATH];
|
|
|
|
wcsCpy(awcsStreamPath, m_awcsPath);
|
|
|
|
HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, FALSE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
ILockBytes *pLKB = NULL;
|
|
|
|
hr = CFSLockBytes::Open(NULL, awcsStreamPath, grfMode, &pLKB);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CStream::OpenStream(NULL, pLKB, grfMode, (IStreamITEx **) ppstm);
|
|
|
|
if (hr != S_OK)
|
|
pLKB->Release();
|
|
}
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CreateStorage(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [in] */ DWORD dwStgFmt,
|
|
/* [in] */ DWORD reserved2,
|
|
/* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
|
|
{
|
|
WCHAR awcsStreamPath[MAX_PATH];
|
|
|
|
wcsCpy(awcsStreamPath, m_awcsPath);
|
|
|
|
HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, TRUE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
hr = CFSStorage::CreateStorage(NULL, (const WCHAR *)awcsStreamPath, grfMode, ppstg);
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::OpenStorage(
|
|
/* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgPriority,
|
|
/* [in] */ DWORD grfMode,
|
|
/* [unique][in] */ SNB snbExclude,
|
|
/* [in] */ DWORD reserved,
|
|
/* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
|
|
{
|
|
WCHAR awcsStreamPath[MAX_PATH];
|
|
|
|
wcsCpy(awcsStreamPath, m_awcsPath);
|
|
|
|
HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, TRUE);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
hr = CFSStorage::OpenStorage(NULL, (const WCHAR *)awcsStreamPath, grfMode, ppstg);
|
|
|
|
RonM_ASSERT(IsUnlocked(g_csITFS));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CopyTo(
|
|
/* [in] */ DWORD ciidExclude,
|
|
/* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude,
|
|
/* [unique][in] */ SNB snbExclude,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgDest)
|
|
{
|
|
return STGCopyTo((IStorage *) this, ciidExclude, rgiidExclude, snbExclude, pstgDest);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::MoveElementTo(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [unique][in] */ IStorage __RPC_FAR *pstgDest,
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName,
|
|
/* [in] */ DWORD grfFlags)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::Commit(
|
|
/* [in] */ DWORD grfCommitFlags)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::Revert( void)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::EnumElements(
|
|
/* [in] */ DWORD reserved1,
|
|
/* [size_is][unique][in] */ void __RPC_FAR *reserved2,
|
|
/* [in] */ DWORD reserved3,
|
|
/* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
|
|
{
|
|
return CFSEnumStorage::NewEnumStorage(NULL, (CONST WCHAR *) m_awcsPath, ppenum);
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::DestroyElement(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::RenameElement(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName,
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::SetElementTimes(
|
|
/* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
|
|
/* [in] */ const FILETIME __RPC_FAR *pctime,
|
|
/* [in] */ const FILETIME __RPC_FAR *patime,
|
|
/* [in] */ const FILETIME __RPC_FAR *pmtime)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::SetClass(
|
|
/* [in] */ REFCLSID clsid)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::SetStateBits(
|
|
/* [in] */ DWORD grfStateBits,
|
|
/* [in] */ DWORD grfMask)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::Stat(
|
|
/* [out] */ STATSTG __RPC_FAR *pstatstg,
|
|
/* [in] */ DWORD grfStatFlag)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT CFSStorage::CImpIFSStorage::CFSEnumStorage::NewEnumStorage
|
|
(IUnknown *pUnkOuter, CONST WCHAR *pwcsPath, IEnumSTATSTG **ppEnumSTATSTG)
|
|
{
|
|
CFSEnumStorage *pEnumContainer = New CFSEnumStorage(pUnkOuter);
|
|
|
|
return FinishSetup(pEnumContainer? pEnumContainer->m_ImpIEnumStorage.Initial(pwcsPath)
|
|
: STG_E_INSUFFICIENTMEMORY,
|
|
pEnumContainer, IID_IEnumSTATSTG, (PPVOID) ppEnumSTATSTG
|
|
);
|
|
}
|
|
|
|
CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::CImpIEnumStorage
|
|
(CFSEnumStorage *pBackObj, IUnknown *punkOuter)
|
|
: IITEnumSTATSTG(pBackObj, punkOuter)
|
|
{
|
|
m_State = Before;
|
|
m_hEnum = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::~CImpIEnumStorage(void)
|
|
{
|
|
if (m_hEnum != INVALID_HANDLE_VALUE)
|
|
FindClose(m_hEnum);
|
|
}
|
|
|
|
HRESULT CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Initial(CONST WCHAR *pwcsPath)
|
|
{
|
|
RonM_ASSERT(m_State == Before);
|
|
RonM_ASSERT(m_hEnum == INVALID_HANDLE_VALUE);
|
|
|
|
UINT cwc = lstrlenW(pwcsPath);
|
|
|
|
if (!cwc || pwcsPath[cwc-1] != L'/' || cwc + 1 >= MAX_PATH)
|
|
return STG_E_INVALIDNAME;
|
|
|
|
wcsCpy(m_awszBasePath, pwcsPath);
|
|
wcsCat(m_awszBasePath, L"*");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// IEnumSTATSTG methods:
|
|
|
|
/* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Next
|
|
(
|
|
/* [in] */ ULONG celt,
|
|
/* [in] */ STATSTG __RPC_FAR *rgelt,
|
|
/* [out] */ ULONG __RPC_FAR *pceltFetched)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
UINT celtFetched = 0;
|
|
|
|
for (; celt--; rgelt++)
|
|
{
|
|
hr = NextEntry();
|
|
|
|
if (hr != S_OK) break;
|
|
|
|
WCHAR awcsBuffer[MAX_PATH];
|
|
|
|
UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED,
|
|
m_w32fd.cFileName, lstrlen(m_w32fd.cFileName) + 1,
|
|
awcsBuffer, MAX_PATH
|
|
);
|
|
|
|
if (!cwc)
|
|
{
|
|
hr = STG_E_UNKNOWN;
|
|
|
|
break;
|
|
}
|
|
|
|
PWCHAR pwcDest = PWCHAR(OLEHeap()->Alloc(cwc * sizeof(WCHAR)));
|
|
|
|
if (!pwcDest)
|
|
{
|
|
hr = STG_E_INSUFFICIENTMEMORY;
|
|
|
|
break;
|
|
}
|
|
|
|
CopyMemory(pwcDest, awcsBuffer, cwc * sizeof(WCHAR));
|
|
|
|
BOOL fStorage = (m_w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
|
|
|
rgelt->pwcsName = pwcDest; pwcDest = NULL;
|
|
rgelt->type = fStorage? STGTY_STORAGE : STGTY_STREAM;
|
|
rgelt->cbSize.LowPart = m_w32fd.nFileSizeLow;
|
|
rgelt->cbSize.HighPart = m_w32fd.nFileSizeHigh;
|
|
rgelt->mtime.dwLowDateTime = m_w32fd.ftLastWriteTime.dwLowDateTime;
|
|
rgelt->mtime.dwHighDateTime = m_w32fd.ftLastWriteTime.dwHighDateTime;
|
|
rgelt->ctime.dwLowDateTime = m_w32fd.ftCreationTime.dwLowDateTime;
|
|
rgelt->ctime.dwHighDateTime = m_w32fd.ftCreationTime.dwHighDateTime;
|
|
rgelt->atime.dwLowDateTime = m_w32fd.ftLastAccessTime.dwLowDateTime;
|
|
rgelt->atime.dwHighDateTime = m_w32fd.ftLastAccessTime.dwHighDateTime;
|
|
rgelt->grfMode = 0;
|
|
rgelt->grfLocksSupported = 0;
|
|
rgelt->clsid = CLSID_NULL;
|
|
rgelt->grfStateBits = 0;
|
|
rgelt->reserved = 0;
|
|
|
|
celtFetched++;
|
|
}
|
|
|
|
if (pceltFetched)
|
|
*pceltFetched = celtFetched;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Skip(ULONG celt)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
for (; celt--; )
|
|
{
|
|
hr = NextEntry();
|
|
|
|
if (hr != S_OK) break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Reset( void)
|
|
{
|
|
if (m_hEnum != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(m_hEnum);
|
|
m_hEnum = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
m_State = Before;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Clone
|
|
(
|
|
/* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::GetNextEntryInSeq
|
|
(ULONG celt, PathInfo *rgelt, ULONG *pceltFetched)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::GetFirstEntryInSeq
|
|
(PathInfo *rgelt)
|
|
{
|
|
RonM_ASSERT(FALSE);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::NextEntry()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch(m_State)
|
|
{
|
|
case Before:
|
|
|
|
{
|
|
char aszBuffer[MAX_PATH * 2];
|
|
|
|
UINT cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK | WC_DEFAULTCHAR,
|
|
m_awszBasePath, lstrlenW(m_awszBasePath) + 1,
|
|
aszBuffer, MAX_PATH * 2, NULL, NULL
|
|
);
|
|
|
|
if (!cb) return STG_E_UNKNOWN;
|
|
|
|
m_hEnum = FindFirstFile(aszBuffer, &m_w32fd);
|
|
|
|
if (m_hEnum == INVALID_HANDLE_VALUE)
|
|
return STG_E_INVALIDNAME;
|
|
|
|
m_State = During;
|
|
|
|
// For the Win32 file system the first two entries returned by
|
|
// FindFirstFile/FindNextFile will always be "." and "..". So we
|
|
// must skip over those items.
|
|
|
|
RonM_ASSERT(!lstrcmp(m_w32fd.cFileName, "."));
|
|
|
|
NextEntry();
|
|
|
|
RonM_ASSERT(!lstrcmp(m_w32fd.cFileName, ".."));
|
|
|
|
return NextEntry(); // To get the first real enumeration name.
|
|
}
|
|
|
|
case During:
|
|
|
|
RonM_ASSERT(m_hEnum != INVALID_HANDLE_VALUE);
|
|
|
|
if (FindNextFile(m_hEnum, &m_w32fd))
|
|
return NO_ERROR;
|
|
|
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
|
{
|
|
m_State = After;
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
case After:
|
|
return S_FALSE;
|
|
|
|
default:
|
|
return STG_E_UNKNOWN;
|
|
}
|
|
}
|