// 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 "/./" which we convert to // "/". pwcNext--; continue; } if (wcNextToLast == L'.') { RonM_ASSERT(pwcNext > pwcBase + 1); // Must be at least "/.." if (pwcNext[-3] == L'/') { // We've found the pattern "//../" // which we convert to "/". // 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; } }