Author: cwittich Date: Sat May 29 13:34:57 2010 New Revision: 47405
URL: http://svn.reactos.org/svn/reactos?rev=47405&view=rev Log: [OLE32] sync to wine 1.2 RC2
Modified: trunk/reactos/dll/win32/ole32/clipboard.c trunk/reactos/dll/win32/ole32/comcat.c trunk/reactos/dll/win32/ole32/compobj.c trunk/reactos/dll/win32/ole32/compositemoniker.c trunk/reactos/dll/win32/ole32/defaulthandler.c trunk/reactos/dll/win32/ole32/hglobalstream.c trunk/reactos/dll/win32/ole32/ifs.c trunk/reactos/dll/win32/ole32/marshal.c trunk/reactos/dll/win32/ole32/moniker.c trunk/reactos/dll/win32/ole32/ole2.c trunk/reactos/dll/win32/ole32/stg_prop.c trunk/reactos/dll/win32/ole32/storage32.c trunk/reactos/dll/win32/ole32/storage32.h trunk/reactos/dll/win32/ole32/usrmarshal.c
Modified: trunk/reactos/dll/win32/ole32/clipboard.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/clipboard.c... ============================================================================== --- trunk/reactos/dll/win32/ole32/clipboard.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/clipboard.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -1266,9 +1266,9 @@ ole_priv_data_entry *entry; TYMED supported;
+ if ( !fmt || !med ) return E_INVALIDARG; + TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed); - - if ( !fmt || !med ) return E_INVALIDARG;
if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
Modified: trunk/reactos/dll/win32/ole32/comcat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/comcat.c?re... ============================================================================== --- trunk/reactos/dll/win32/ole32/comcat.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/comcat.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -232,18 +232,20 @@ LPCWSTR string;
/* Check that every given category is implemented by class. */ - res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey); - if (res != ERROR_SUCCESS) return S_FALSE; - for (string = categories->impl_strings; *string; string += 39) { - HKEY catkey; - res = RegOpenKeyExW(subkey, string, 0, 0, &catkey); - if (res != ERROR_SUCCESS) { - RegCloseKey(subkey); - return S_FALSE; + if (*categories->impl_strings) { + res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey); + if (res != ERROR_SUCCESS) return S_FALSE; + for (string = categories->impl_strings; *string; string += 39) { + HKEY catkey; + res = RegOpenKeyExW(subkey, string, 0, 0, &catkey); + if (res != ERROR_SUCCESS) { + RegCloseKey(subkey); + return S_FALSE; + } + RegCloseKey(catkey); } - RegCloseKey(catkey); - } - RegCloseKey(subkey); + RegCloseKey(subkey); + }
/* Check that all categories required by class are given. */ res = RegOpenKeyExW(key, req_keyname, 0, KEY_READ, &subkey);
Modified: trunk/reactos/dll/win32/ole32/compobj.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/compobj.c?r... ============================================================================== --- trunk/reactos/dll/win32/ole32/compobj.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/compobj.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -4156,7 +4156,6 @@ break;
case DLL_PROCESS_DETACH: - OLEDD_UnInitialize(); COMPOBJ_UninitProcess(); RPC_UnregisterAllChannelHooks(); COMPOBJ_DllList_Free();
Modified: trunk/reactos/dll/win32/ole32/compositemoniker.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/compositemo... ============================================================================== --- trunk/reactos/dll/win32/ole32/compositemoniker.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/compositemoniker.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -445,7 +445,6 @@ CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, IMoniker** ppmkToLeft, IMoniker** ppmkReduced) { - HRESULT res; IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk; IEnumMoniker *enumMoniker;
@@ -462,8 +461,8 @@ IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); IEnumMoniker_Release(enumMoniker);
- res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + CreateAntiMoniker(&antiMk); + IMoniker_ComposeWith(iface,antiMk,0,&tempMk); IMoniker_Release(antiMk);
return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); @@ -479,8 +478,8 @@ IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); IEnumMoniker_Release(enumMoniker);
- res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + CreateAntiMoniker(&antiMk); + IMoniker_ComposeWith(iface,antiMk,0,&tempMk); IMoniker_Release(antiMk);
/* If any of the components reduces itself, the method returns S_OK and passes back a composite */
Modified: trunk/reactos/dll/win32/ole32/defaulthandler.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/defaulthand... ============================================================================== --- trunk/reactos/dll/win32/ole32/defaulthandler.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/defaulthandler.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -365,7 +365,7 @@ if (This->clientSite) IOleClientSite_AddRef(This->clientSite);
- return S_OK; + return hr; }
/************************************************************************
Modified: trunk/reactos/dll/win32/ole32/hglobalstream.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/hglobalstre... ============================================================================== --- trunk/reactos/dll/win32/ole32/hglobalstream.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/hglobalstream.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -370,12 +370,6 @@
TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition); - - if (dlibMove.u.LowPart >= 0x80000000) - { - hr = STG_E_SEEKERROR; - goto end; - }
/* * The file pointer is moved depending on the given "function" @@ -405,9 +399,18 @@ newPosition.u.HighPart = 0; newPosition.u.LowPart += dlibMove.QuadPart;
+ if (dlibMove.u.LowPart >= 0x80000000 && + newPosition.u.LowPart >= dlibMove.u.LowPart) + { + /* We tried to seek backwards and went past the start. */ + hr = STG_E_SEEKERROR; + goto end; + } + + This->currentPosition = newPosition; + end: - if (plibNewPosition) *plibNewPosition = newPosition; - This->currentPosition = newPosition; + if (plibNewPosition) *plibNewPosition = This->currentPosition;
return hr; }
Modified: trunk/reactos/dll/win32/ole32/ifs.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/ifs.c?rev=4... ============================================================================== --- trunk/reactos/dll/win32/ole32/ifs.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/ifs.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -501,7 +501,7 @@ } LeaveCriticalSection(&IMalloc32_SpyCS);
- return S_OK; + return hres; }
/******************************************************************************
Modified: trunk/reactos/dll/win32/ole32/marshal.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/marshal.c?r... ============================================================================== --- trunk/reactos/dll/win32/ole32/marshal.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/marshal.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -1214,16 +1214,13 @@ RPC_StartRemoting(apt);
hres = marshal_object(apt, &stdobjref, riid, pv, mshlflags); - if (hres) + if (hres != S_OK) { ERR("Failed to create ifstub, hres=0x%x\n", hres); return hres; }
- hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return hres; - - return S_OK; + return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); }
/* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with @@ -1321,10 +1318,10 @@
/* read STDOBJREF from wire */ hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return STG_E_READFAULT; + if (hres != S_OK) return STG_E_READFAULT;
hres = apartment_getoxid(apt, &oxid); - if (hres) return hres; + if (hres != S_OK) return hres;
/* check if we're marshalling back to ourselves */ if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) @@ -1374,7 +1371,7 @@ if (stubmgr) stub_manager_int_release(stubmgr); if (stub_apt) apartment_release(stub_apt);
- if (hres) WARN("Failed with error 0x%08x\n", hres); + if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres); else TRACE("Successfully created proxy %p\n", *ppv);
return hres; @@ -1392,7 +1389,7 @@ TRACE("iface=%p, pStm=%p\n", iface, pStm);
hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return STG_E_READFAULT; + if (hres != S_OK) return STG_E_READFAULT;
TRACE("oxid = %s, oid = %s, ipid = %s\n", wine_dbgstr_longlong(stdobjref.oxid), @@ -1516,7 +1513,7 @@ if (!pUnk) return E_POINTER; hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal); - if (hr) + if (hr != S_OK) hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, pMarshal); return hr; @@ -1537,7 +1534,7 @@
/* read common OBJREF header */ hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); - if (hr || (res != FIELD_OFFSET(OBJREF, u_objref))) + if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref))) { ERR("Failed to read common OBJREF header, 0x%08x\n", hr); return STG_E_READFAULT; @@ -1566,7 +1563,7 @@ /* read constant sized OR_CUSTOM data from stream */ hr = IStream_Read(stream, &objref.u_objref.u_custom, custom_header_size, &res); - if (hr || (res != custom_header_size)) + if (hr != S_OK || (res != custom_header_size)) { ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr); return STG_E_READFAULT; @@ -1583,7 +1580,7 @@ return RPC_E_INVALID_OBJREF; }
- if (hr) + if (hr != S_OK) ERR("Failed to create marshal, 0x%08x\n", hr);
return hr; @@ -1618,12 +1615,12 @@ CLSID marshaler_clsid;
hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); - if (hr) + if (hr != S_OK) return hr;
hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &marshaler_clsid); - if (hr) + if (hr != S_OK) { ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); IMarshal_Release(pMarshal); @@ -1711,7 +1708,7 @@
/* get the marshaler for the specified interface */ hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); - if (hr) + if (hr != S_OK) { ERR("Failed to get marshaller, 0x%08x\n", hr); return hr; @@ -1719,7 +1716,7 @@
hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &marshaler_clsid); - if (hr) + if (hr != S_OK) { ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); goto cleanup; @@ -1733,7 +1730,7 @@
/* write the common OBJREF header to the stream */ hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); - if (hr) + if (hr != S_OK) { ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr); goto cleanup; @@ -1749,7 +1746,7 @@ hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &objref.u_objref.u_custom.size); - if (hr) + if (hr != S_OK) { ERR("Failed to get max size of marshal data, error 0x%08x\n", hr); goto cleanup; @@ -1757,7 +1754,7 @@ /* write constant sized common header and OR_CUSTOM data into stream */ hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL); - if (hr) + if (hr != S_OK) { ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr); goto cleanup; @@ -1769,7 +1766,7 @@ hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext, pvDestContext, mshlFlags);
- if (hr) + if (hr != S_OK) { ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr); goto cleanup; @@ -1821,7 +1818,7 @@
/* call the helper object to do the actual unmarshaling */ hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object); - if (hr) + if (hr != S_OK) ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
if (hr == S_OK) @@ -1831,7 +1828,7 @@ { TRACE("requested interface != marshalled interface, additional QI needed\n"); hr = IUnknown_QueryInterface(object, riid, ppv); - if (hr) + if (hr != S_OK) ERR("Couldn't query for interface %s, hr = 0x%08x\n", debugstr_guid(riid), hr); IUnknown_Release(object); @@ -1885,7 +1882,7 @@
/* call the helper object to do the releasing of marshal data */ hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); - if (hr) + if (hr != S_OK) ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
IMarshal_Release(pMarshal);
Modified: trunk/reactos/dll/win32/ole32/moniker.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/moniker.c?r... ============================================================================== --- trunk/reactos/dll/win32/ole32/moniker.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/moniker.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -1109,7 +1109,13 @@
TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
- if (!(IsValidInterface((LPUNKNOWN) pbc))) + if (!pbc || !IsValidInterface((LPUNKNOWN) pbc)) + return E_INVALIDARG; + + if (!szDisplayName || !*szDisplayName) + return E_INVALIDARG; + + if (!pchEaten || !ppmk) return E_INVALIDARG;
*pchEaten = 0;
Modified: trunk/reactos/dll/win32/ole32/ole2.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/ole2.c?rev=... ============================================================================== --- trunk/reactos/dll/win32/ole32/ole2.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/ole2.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -57,13 +57,6 @@ * These are static/global variables and internal data structures that the * OLE module uses to maintain it's state. */ -typedef struct tagDropTargetNode -{ - HWND hwndTarget; - IDropTarget* dropTarget; - struct list entry; -} DropTargetNode; - typedef struct tagTrackerWindowInfo { IDataObject* dataObject; @@ -110,12 +103,25 @@ /* * Name of our registered window class. */ -static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; +static const WCHAR OLEDD_DRAGTRACKERCLASS[] = + {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
/* - * This is the head of the Drop target container. - */ -static struct list targetListHead = LIST_INIT(targetListHead); + * Name of menu descriptor property. + */ +static const WCHAR prop_olemenuW[] = + {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0}; + +/* property to store IDropTarget pointer */ +static const WCHAR prop_oledroptarget[] = + {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0}; + +static const WCHAR clsidfmtW[] = + {'C','L','S','I','D','\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', + '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x', + '%','0','2','x','%','0','2','x','}','\',0}; + +static const WCHAR emptyW[] = { 0 };
/****************************************************************************** * These are the prototypes of miscellaneous utility methods @@ -144,21 +150,11 @@ /****************************************************************************** * These are the prototypes of the utility methods used for OLE Drag n Drop */ -static void OLEDD_Initialize(void); -static DropTargetNode* OLEDD_FindDropTarget( - HWND hwndOfTarget); -static void OLEDD_FreeDropTarget(DropTargetNode*, BOOL); -static LRESULT WINAPI OLEDD_DragTrackerWindowProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); -static void OLEDD_TrackMouseMove( - TrackerWindowInfo* trackerInfo); -static void OLEDD_TrackStateChange( - TrackerWindowInfo* trackerInfo); +static void OLEDD_Initialize(void); +static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo); +static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo); static DWORD OLEDD_GetButtonState(void); -
/****************************************************************************** * OleBuildVersion [OLE32.@] @@ -270,14 +266,22 @@ return 0; }
+/*** + * OLEDD_FindDropTarget() + * + * Returns IDropTarget pointer registered for this window. + */ +static inline IDropTarget* OLEDD_FindDropTarget(HWND hwnd) +{ + return GetPropW(hwnd, prop_oledroptarget); +} + /*********************************************************************** * RegisterDragDrop (OLE32.@) */ -HRESULT WINAPI RegisterDragDrop( - HWND hwnd, - LPDROPTARGET pDropTarget) -{ - DropTargetNode* dropTargetInfo; +HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget) +{ + DWORD pid = 0;
TRACE("(%p,%p)\n", hwnd, pDropTarget);
@@ -296,32 +300,20 @@ return DRAGDROP_E_INVALIDHWND; }
- /* - * First, check if the window is already registered. - */ - dropTargetInfo = OLEDD_FindDropTarget(hwnd); - - if (dropTargetInfo!=NULL) + /* block register for other processes windows */ + GetWindowThreadProcessId(hwnd, &pid); + if (pid != GetCurrentProcessId()) + { + FIXME("register for another process windows is disabled\n"); + return DRAGDROP_E_INVALIDHWND; + } + + /* check if the window is already registered */ + if (OLEDD_FindDropTarget(hwnd)) return DRAGDROP_E_ALREADYREGISTERED;
- /* - * If it's not there, we can add it. We first create a node for it. - */ - dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode)); - - if (dropTargetInfo==NULL) - return E_OUTOFMEMORY; - - dropTargetInfo->hwndTarget = hwnd; - - /* - * Don't forget that this is an interface pointer, need to nail it down since - * we keep a copy of it. - */ IDropTarget_AddRef(pDropTarget); - dropTargetInfo->dropTarget = pDropTarget; - - list_add_tail(&targetListHead, &dropTargetInfo->entry); + SetPropW(hwnd, prop_oledroptarget, pDropTarget);
return S_OK; } @@ -329,10 +321,9 @@ /*********************************************************************** * RevokeDragDrop (OLE32.@) */ -HRESULT WINAPI RevokeDragDrop( - HWND hwnd) -{ - DropTargetNode* dropTargetInfo; +HRESULT WINAPI RevokeDragDrop(HWND hwnd) +{ + IDropTarget* droptarget;
TRACE("(%p)\n", hwnd);
@@ -342,18 +333,12 @@ return DRAGDROP_E_INVALIDHWND; }
- /* - * First, check if the window is already registered. - */ - dropTargetInfo = OLEDD_FindDropTarget(hwnd); - - /* - * If it ain't in there, it's an error. - */ - if (dropTargetInfo==NULL) + /* no registration data */ + if (!(droptarget = OLEDD_FindDropTarget(hwnd))) return DRAGDROP_E_NOTREGISTERED;
- OLEDD_FreeDropTarget(dropTargetInfo, TRUE); + IDropTarget_Release(droptarget); + RemovePropW(hwnd, prop_oledroptarget);
return S_OK; } @@ -371,13 +356,12 @@ DWORD dwFormOfType, LPOLESTR* pszUserType) { - char keyName[60]; + WCHAR keyName[60]; DWORD dwKeyType; DWORD cbData; HKEY clsidKey; LONG hres; - LPSTR buffer; - HRESULT retVal; + /* * Initialize the out parameter. */ @@ -386,17 +370,17 @@ /* * Build the key name we're looking for */ - sprintf( keyName, "CLSID\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\", - clsid->Data1, clsid->Data2, clsid->Data3, - clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], - clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - - TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType); + sprintfW( keyName, clsidfmtW, + clsid->Data1, clsid->Data2, clsid->Data3, + clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], + clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); + + TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwFormOfType, pszUserType);
/* * Open the class id Key */ - hres = RegOpenKeyA(HKEY_CLASSES_ROOT, + hres = RegOpenKeyW(HKEY_CLASSES_ROOT, keyName, &clsidKey);
@@ -408,8 +392,8 @@ */ cbData = 0;
- hres = RegQueryValueExA(clsidKey, - "", + hres = RegQueryValueExW(clsidKey, + emptyW, NULL, &dwKeyType, NULL, @@ -424,7 +408,7 @@ /* * Allocate a buffer for the registry value. */ - *pszUserType = CoTaskMemAlloc(cbData*2); + *pszUserType = CoTaskMemAlloc(cbData);
if (*pszUserType==NULL) { @@ -432,41 +416,24 @@ return E_OUTOFMEMORY; }
- buffer = HeapAlloc(GetProcessHeap(), 0, cbData); - - if (buffer == NULL) - { - RegCloseKey(clsidKey); - CoTaskMemFree(*pszUserType); - *pszUserType=NULL; - return E_OUTOFMEMORY; - } - - hres = RegQueryValueExA(clsidKey, - "", + hres = RegQueryValueExW(clsidKey, + emptyW, NULL, &dwKeyType, - (LPBYTE) buffer, + (LPBYTE) *pszUserType, &cbData);
RegCloseKey(clsidKey);
- - if (hres!=ERROR_SUCCESS) + if (hres != ERROR_SUCCESS) { CoTaskMemFree(*pszUserType); - *pszUserType=NULL; - - retVal = REGDB_E_READREGDB; - } - else - { - MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ ); - retVal = S_OK; - } - HeapFree(GetProcessHeap(), 0, buffer); - - return retVal; + *pszUserType = NULL; + + return REGDB_E_READREGDB; + } + + return S_OK; }
/*********************************************************************** @@ -478,17 +445,19 @@ DWORD dwOKEffect, /* [in] effects allowed by the source */ DWORD *pdwEffect) /* [out] ptr to effects of the source */ { + static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0}; TrackerWindowInfo trackerInfo; HWND hwndTrackWindow; MSG msg;
- TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource); + TRACE("(%p, %p, %d, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect); + + if (!pDataObject || !pDropSource || !pdwEffect) + return E_INVALIDARG;
/* * Setup the drag n drop tracking window. */ - if (!IsValidInterface((LPUNKNOWN)pDropSource)) - return E_INVALIDARG;
trackerInfo.dataObject = pDataObject; trackerInfo.dropSource = pDropSource; @@ -500,12 +469,12 @@ trackerInfo.curTargetHWND = 0; trackerInfo.curDragTarget = 0;
- hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, "TrackerWindow", + hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, &trackerInfo);
- if (hwndTrackWindow!=0) + if (hwndTrackWindow) { /* * Capture the mouse input @@ -517,7 +486,7 @@ /* * Pump messages. All mouse input should go to the capture window. */ - while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) ) + while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) ) { trackerInfo.curMousePos.x = msg.pt.x; trackerInfo.curMousePos.y = msg.pt.y; @@ -548,7 +517,7 @@ /* * Dispatch the messages only when it's not a keyboard message. */ - DispatchMessageA(&msg); + DispatchMessageW(&msg); } }
@@ -584,7 +553,9 @@ DWORD dwAspect, DWORD* pdwStatus) { - char keyName[60]; + static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0}; + static const WCHAR dfmtW[] = {'%','d',0}; + WCHAR keyName[60]; HKEY clsidKey; HKEY miscStatusKey; HKEY aspectKey; @@ -598,17 +569,17 @@ /* * Build the key name we're looking for */ - sprintf( keyName, "CLSID\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\", - clsid->Data1, clsid->Data2, clsid->Data3, - clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], - clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - - TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus); + sprintfW( keyName, clsidfmtW, + clsid->Data1, clsid->Data2, clsid->Data3, + clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], + clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); + + TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwAspect, pdwStatus);
/* * Open the class id Key */ - result = RegOpenKeyA(HKEY_CLASSES_ROOT, + result = RegOpenKeyW(HKEY_CLASSES_ROOT, keyName, &clsidKey);
@@ -618,8 +589,8 @@ /* * Get the MiscStatus */ - result = RegOpenKeyA(clsidKey, - "MiscStatus", + result = RegOpenKeyW(clsidKey, + miscstatusW, &miscStatusKey);
@@ -637,9 +608,9 @@ /* * Open the key specific to the requested aspect. */ - sprintf(keyName, "%d", dwAspect); - - result = RegOpenKeyA(miscStatusKey, + sprintfW(keyName, dfmtW, dwAspect); + + result = RegOpenKeyW(miscStatusKey, keyName, &aspectKey);
@@ -1180,7 +1151,7 @@ */ static BOOL OLEMenu_InstallHooks( DWORD tid ) { - OleMenuHookItem *pHookItem = NULL; + OleMenuHookItem *pHookItem;
/* Create an entry for the hook table */ if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0, @@ -1189,15 +1160,16 @@
pHookItem->tid = tid; pHookItem->hHeap = GetProcessHeap(); + pHookItem->CallWndProc_hHook = NULL;
/* Install a thread scope message hook for WH_GETMESSAGE */ - pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc, + pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc, 0, GetCurrentThreadId() ); if ( !pHookItem->GetMsg_hHook ) goto CLEANUP;
/* Install a thread scope message hook for WH_CALLWNDPROC */ - pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc, + pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc, 0, GetCurrentThreadId() ); if ( !pHookItem->CallWndProc_hHook ) goto CLEANUP; @@ -1271,7 +1243,7 @@ */ static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) { - OleMenuHookItem *pHookItem = NULL; + OleMenuHookItem *pHookItem;
/* Do a simple linear search for an entry whose tid matches ours. * We really need a map but efficiency is not a concern here. */ @@ -1376,7 +1348,7 @@ */ static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) { - LPCWPSTRUCT pMsg = NULL; + LPCWPSTRUCT pMsg; HOLEMENU hOleMenu = 0; OleMenuDescriptor *pOleMenuDescriptor = NULL; OleMenuHookItem *pHookItem = NULL; @@ -1395,7 +1367,7 @@ * If the window has an OLEMenu property we may need to dispatch * the menu message to its active objects window instead. */
- hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); + hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW ); if ( !hOleMenu ) goto NEXTHOOK;
@@ -1413,7 +1385,7 @@ pOleMenuDescriptor->bIsServerItem = FALSE;
/* Send this message to the server as well */ - SendMessageA( pOleMenuDescriptor->hwndActiveObject, + SendMessageW( pOleMenuDescriptor->hwndActiveObject, pMsg->message, pMsg->wParam, pMsg->lParam ); goto NEXTHOOK; } @@ -1454,7 +1426,7 @@ /* If the message was for the server dispatch it accordingly */ if ( pOleMenuDescriptor->bIsServerItem ) { - SendMessageA( pOleMenuDescriptor->hwndActiveObject, + SendMessageW( pOleMenuDescriptor->hwndActiveObject, pMsg->message, pMsg->wParam, pMsg->lParam ); }
@@ -1481,7 +1453,7 @@ */ static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) { - LPMSG pMsg = NULL; + LPMSG pMsg; HOLEMENU hOleMenu = 0; OleMenuDescriptor *pOleMenuDescriptor = NULL; OleMenuHookItem *pHookItem = NULL; @@ -1500,7 +1472,7 @@ * If the window has an OLEMenu property we may need to dispatch * the menu message to its active objects window instead. */
- hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); + hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW ); if ( !hOleMenu ) goto NEXTHOOK;
@@ -1671,7 +1643,7 @@ pOleMenuDescriptor = NULL;
/* Add a menu descriptor windows property to the frame window */ - SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu ); + SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
/* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */ if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) ) @@ -1684,7 +1656,7 @@ return E_FAIL;
/* Remove the menu descriptor property from the frame window */ - RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" ); + RemovePropW( hwndFrame, prop_olemenuW ); }
return S_OK; @@ -1870,9 +1842,9 @@ */ static void OLEDD_Initialize(void) { - WNDCLASSA wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSA)); + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); wndClass.style = CS_GLOBALCLASS; wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; wndClass.cbClsExtra = 0; @@ -1881,58 +1853,7 @@ wndClass.hbrBackground = 0; wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
- RegisterClassA (&wndClass); -} - -/*** - * OLEDD_FreeDropTarget() - * - * Frees the drag and drop data structure - */ -static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target) -{ - list_remove(&dropTargetInfo->entry); - if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget); - HeapFree(GetProcessHeap(), 0, dropTargetInfo); -} - -/*** - * OLEDD_UnInitialize() - * - * Releases the OLE drag and drop data structures. - */ -void OLEDD_UnInitialize(void) -{ - /* - * Simply empty the list. - */ - while (!list_empty(&targetListHead)) - { - DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry); - OLEDD_FreeDropTarget(curNode, FALSE); - } -} - -/*** - * OLEDD_FindDropTarget() - * - * Finds information about the drop target. - */ -static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget) -{ - DropTargetNode* curNode; - - /* - * Iterate the list to find the HWND value. - */ - LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry) - if (hwndOfTarget==curNode->hwndTarget) - return curNode; - - /* - * If we get here, the item is not in the list - */ - return NULL; + RegisterClassW (&wndClass); }
/*** @@ -1958,7 +1879,7 @@ { LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
- SetWindowLongPtrA(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams); + SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams); SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
break; @@ -1989,7 +1910,7 @@ /* * This is a window proc after all. Let's call the default. */ - return DefWindowProcA (hwnd, uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); }
/*** @@ -2038,46 +1959,65 @@ } else { - DropTargetNode* newDropTargetNode = 0; - /* * If we changed window, we have to notify our old target and check for * the new one. */ - if (trackerInfo->curDragTarget!=0) - { + if (trackerInfo->curDragTarget) IDropTarget_DragLeave(trackerInfo->curDragTarget); - }
/* * Make sure we're hovering over a window. */ - if (hwndNewTarget!=0) + if (hwndNewTarget) { /* * Find-out if there is a drag target under the mouse */ - HWND nexttar = hwndNewTarget; + HWND next_target_wnd = hwndNewTarget; + IDropTarget *new_target; + DWORD pid; + trackerInfo->curTargetHWND = hwndNewTarget;
do { - newDropTargetNode = OLEDD_FindDropTarget(nexttar); - } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0); - if(nexttar) hwndNewTarget = nexttar; - - trackerInfo->curDragTargetHWND = hwndNewTarget; - trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0; + new_target = OLEDD_FindDropTarget(next_target_wnd); + } while (!new_target && (next_target_wnd = GetParent(next_target_wnd))); + + if (next_target_wnd) hwndNewTarget = next_target_wnd; + + GetWindowThreadProcessId(hwndNewTarget, &pid); + if (pid != GetCurrentProcessId()) + { + FIXME("drop to another process window is unsupported\n"); + trackerInfo->curDragTargetHWND = 0; + trackerInfo->curTargetHWND = 0; + trackerInfo->curDragTarget = 0; + } + else + { + trackerInfo->curDragTargetHWND = hwndNewTarget; + trackerInfo->curDragTarget = new_target; + }
/* * If there is, notify it that we just dragged-in */ - if (trackerInfo->curDragTarget!=0) + if (trackerInfo->curDragTarget) { - IDropTarget_DragEnter(trackerInfo->curDragTarget, - trackerInfo->dataObject, - trackerInfo->dwKeyState, - trackerInfo->curMousePos, - trackerInfo->pdwEffect); + hr = IDropTarget_DragEnter(trackerInfo->curDragTarget, + trackerInfo->dataObject, + trackerInfo->dwKeyState, + trackerInfo->curMousePos, + trackerInfo->pdwEffect); + + /* failed DragEnter() means invalid target */ + if (hr != S_OK) + { + trackerInfo->curDragTargetHWND = 0; + trackerInfo->curTargetHWND = 0; + trackerInfo->curDragTarget = 0; + } } } else @@ -2110,24 +2050,28 @@ * when that's the case, we must display the standard drag and drop * cursors. */ - if (hr==DRAGDROP_S_USEDEFAULTCURSORS) - { + if (hr == DRAGDROP_S_USEDEFAULTCURSORS) + { + HCURSOR hCur; + if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) { - SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(1))); + hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1)); } else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY) { - SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(2))); + hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2)); } else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK) { - SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(3))); + hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3)); } else { - SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(0))); - } + hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(0)); + } + + SetCursor(hCur); } }
@@ -2174,7 +2118,7 @@ * If we end-up over a target, drop the object in the target or * inform the target that the operation was cancelled. */ - if (trackerInfo->curDragTarget!=0) + if (trackerInfo->curDragTarget) { switch (trackerInfo->returnValue) { @@ -2183,14 +2127,16 @@ * the drop target that we just dropped the object in it. */ case DRAGDROP_S_DROP: - { - IDropTarget_Drop(trackerInfo->curDragTarget, - trackerInfo->dataObject, - trackerInfo->dwKeyState, - trackerInfo->curMousePos, - trackerInfo->pdwEffect); - break; - } + if (*trackerInfo->pdwEffect != DROPEFFECT_NONE) + IDropTarget_Drop(trackerInfo->curDragTarget, + trackerInfo->dataObject, + trackerInfo->dwKeyState, + trackerInfo->curMousePos, + trackerInfo->pdwEffect); + else + IDropTarget_DragLeave(trackerInfo->curDragTarget); + break; + /* * If the source told us that we should cancel, fool the drop * target by telling it that the mouse left it's window. @@ -2256,13 +2202,13 @@ HKEY regKey, DWORD* pdwValue) { - char buffer[20]; + WCHAR buffer[20]; + DWORD cbData = sizeof(buffer); DWORD dwKeyType; - DWORD cbData = 20; LONG lres;
- lres = RegQueryValueExA(regKey, - "", + lres = RegQueryValueExW(regKey, + emptyW, NULL, &dwKeyType, (LPBYTE)buffer, @@ -2278,7 +2224,7 @@ case REG_EXPAND_SZ: case REG_MULTI_SZ: case REG_SZ: - *pdwValue = (DWORD)strtoul(buffer, NULL, 10); + *pdwValue = (DWORD)strtoulW(buffer, NULL, 10); break; } }
Modified: trunk/reactos/dll/win32/ole32/stg_prop.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/stg_prop.c?... ============================================================================== --- trunk/reactos/dll/win32/ole32/stg_prop.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/stg_prop.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -1314,6 +1314,13 @@ hr = PropertyStorage_ReadFmtIdOffsetFromStream(This->stm, &fmtOffset); if (FAILED(hr)) goto end; + if (!IsEqualGUID(&fmtOffset.fmtid, &FMTID_DocSummaryInformation) && + !IsEqualGUID(&fmtOffset.fmtid, &FMTID_SummaryInformation)) + { + WARN("not reading unknown fmtid %s\n", debugstr_guid(&fmtOffset.fmtid)); + hr = S_FALSE; + goto end; + } if (fmtOffset.dwOffset > stat.cbSize.u.LowPart) { WARN("invalid offset %d (stream length is %d)\n", fmtOffset.dwOffset,
Modified: trunk/reactos/dll/win32/ole32/storage32.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/storage32.c... ============================================================================== --- trunk/reactos/dll/win32/ole32/storage32.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/storage32.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -118,17 +118,61 @@ static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry); static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry);
+typedef struct TransactedDirEntry +{ + /* If applicable, a reference to the original DirEntry in the transacted + * parent. If this is a newly-created entry, DIRENTRY_NULL. */ + DirRef transactedParentEntry; + + /* True if this entry is being used. */ + int inuse; + + /* True if data is up to date. */ + int read; + + /* True if this entry has been modified. */ + int dirty; + + /* True if this entry's stream has been modified. */ + int stream_dirty; + + /* True if this entry has been deleted in the transacted storage, but the + * delete has not yet been committed. */ + int deleted; + + /* If this entry's stream has been modified, a reference to where the stream + * is stored in the snapshot file. */ + DirRef stream_entry; + + /* This directory entry's data, including any changes that have been made. */ + DirEntry data; + + /* A reference to the parent of this node. This is only valid while we are + * committing changes. */ + DirRef parent; + + /* A reference to a newly-created entry in the transacted parent. This is + * always equal to transactedParentEntry except when committing changes. */ + DirRef newTransactedParentEntry; +} TransactedDirEntry; + /**************************************************************************** - * Transacted storage object that reads/writes a snapshot file. + * Transacted storage object. */ typedef struct TransactedSnapshotImpl { struct StorageBaseImpl base;
/* - * Changes are temporarily saved to the snapshot. - */ - StorageBaseImpl *snapshot; + * Modified streams are temporarily saved to the scratch file. + */ + StorageBaseImpl *scratch; + + /* The directory structure is kept here, so that we can track how these + * entries relate to those in the parent storage. */ + TransactedDirEntry *entries; + ULONG entries_size; + ULONG firstFreeEntry;
/* * Changes are committed to the transacted parent. @@ -1291,46 +1335,6 @@ memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData); - - return hr; -} - - -/*************************************************************************** - * - * Internal Method - * - * Destroy an entry, its attached data, and all entries reachable from it. - */ -static HRESULT DestroyReachableEntries( - StorageBaseImpl *base, - DirRef index) -{ - HRESULT hr = S_OK; - DirEntry data; - ULARGE_INTEGER zero; - - zero.QuadPart = 0; - - if (index != DIRENTRY_NULL) - { - hr = StorageBaseImpl_ReadDirEntry(base, index, &data); - - if (SUCCEEDED(hr)) - hr = DestroyReachableEntries(base, data.dirRootEntry); - - if (SUCCEEDED(hr)) - hr = DestroyReachableEntries(base, data.leftChild); - - if (SUCCEEDED(hr)) - hr = DestroyReachableEntries(base, data.rightChild); - - if (SUCCEEDED(hr)) - hr = StorageBaseImpl_StreamSetSize(base, index, zero); - - if (SUCCEEDED(hr)) - hr = StorageBaseImpl_DestroyDirEntry(base, index); - }
return hr; } @@ -2347,6 +2351,21 @@ return &This->blockChainCache[free_index]; }
+static void StorageImpl_DeleteCachedBlockChainStream(StorageImpl *This, DirRef index) +{ + int i; + + for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++) + { + if (This->blockChainCache[i] && This->blockChainCache[i]->ownerDirEntry == index) + { + BlockChainStream_Destroy(This->blockChainCache[i]); + This->blockChainCache[i] = NULL; + return; + } + } +} + static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead) { @@ -2536,6 +2555,30 @@
return hr; } +} + +static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst, + DirRef src) +{ + StorageImpl *This = (StorageImpl*)base; + DirEntry dst_data, src_data; + HRESULT hr; + + hr = StorageImpl_ReadDirEntry(This, dst, &dst_data); + + if (SUCCEEDED(hr)) + hr = StorageImpl_ReadDirEntry(This, src, &src_data); + + if (SUCCEEDED(hr)) + { + StorageImpl_DeleteCachedBlockChainStream(This, src); + dst_data.startingBlock = src_data.startingBlock; + dst_data.size = src_data.size; + + hr = StorageImpl_WriteDirEntry(This, dst, &dst_data); + } + + return hr; }
/* @@ -2573,7 +2616,8 @@ StorageImpl_DestroyDirEntry, StorageImpl_StreamReadAt, StorageImpl_StreamWriteAt, - StorageImpl_StreamSetSize + StorageImpl_StreamSetSize, + StorageImpl_StreamLink };
static HRESULT StorageImpl_Construct( @@ -3540,6 +3584,9 @@ buffer, &bytesRead);
+ if (bytesRead != RAW_DIRENTRY_SIZE) + return STG_E_READFAULT; + return hr; }
@@ -3885,6 +3932,11 @@
offset.u.LowPart += cbRead; } + else + { + resRead = STG_E_READFAULT; + break; + } } while (cbTotalRead.QuadPart < size.QuadPart); HeapFree(GetProcessHeap(),0,buffer);
@@ -3983,6 +4035,11 @@
offset.u.LowPart += cbRead; } + else + { + resRead = STG_E_READFAULT; + break; + } }while(cbTotalRead.QuadPart < size.QuadPart); HeapFree(GetProcessHeap(), 0, buffer);
@@ -4011,40 +4068,384 @@ return SmallBlockChainStream_Construct(This, NULL, streamEntryRef); }
-static HRESULT CreateSnapshotFile(StorageBaseImpl* original, StorageBaseImpl **snapshot) +static HRESULT StorageBaseImpl_CopyStream( + StorageBaseImpl *dst, DirRef dst_entry, + StorageBaseImpl *src, DirRef src_entry) { HRESULT hr; - DirEntry parentData, snapshotData; - - hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DELETEONRELEASE, - 0, (IStorage**)snapshot); + BYTE data[4096]; + DirEntry srcdata; + ULARGE_INTEGER bytes_copied; + ULONG bytestocopy, bytesread, byteswritten; + + hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
if (SUCCEEDED(hr)) { - hr = StorageBaseImpl_ReadDirEntry(original, - original->storageDirEntry, &parentData); + hr = StorageBaseImpl_StreamSetSize(dst, dst_entry, srcdata.size); + + bytes_copied.QuadPart = 0; + while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr)) + { + bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart); + + hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy, + data, &bytesread); + if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT; + + if (SUCCEEDED(hr)) + hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy, + data, &byteswritten); + if (SUCCEEDED(hr)) + { + if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT; + bytes_copied.QuadPart += byteswritten; + } + } + } + + return hr; +} + +static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This) +{ + DirRef result=This->firstFreeEntry; + + while (result < This->entries_size && This->entries[result].inuse) + result++; + + if (result == This->entries_size) + { + ULONG new_size = This->entries_size * 2; + TransactedDirEntry *new_entries; + + new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * new_size); + if (!new_entries) return DIRENTRY_NULL; + + memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size); + HeapFree(GetProcessHeap(), 0, This->entries); + + This->entries = new_entries; + This->entries_size = new_size; + } + + This->entries[result].inuse = 1; + + This->firstFreeEntry = result+1; + + return result; +} + +static DirRef TransactedSnapshotImpl_CreateStubEntry( + TransactedSnapshotImpl *This, DirRef parentEntryRef) +{ + DirRef stubEntryRef; + TransactedDirEntry *entry; + + stubEntryRef = TransactedSnapshotImpl_FindFreeEntry(This); + + if (stubEntryRef != DIRENTRY_NULL) + { + entry = &This->entries[stubEntryRef]; + + entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef; + + entry->read = 0; + } + + return stubEntryRef; +} + +static HRESULT TransactedSnapshotImpl_EnsureReadEntry( + TransactedSnapshotImpl *This, DirRef entry) +{ + HRESULT hr=S_OK; + DirEntry data; + + if (!This->entries[entry].read) + { + hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, + This->entries[entry].transactedParentEntry, + &data); + + if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL) + { + data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild); + + if (data.leftChild == DIRENTRY_NULL) + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL) + { + data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild); + + if (data.rightChild == DIRENTRY_NULL) + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL) + { + data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry); + + if (data.dirRootEntry == DIRENTRY_NULL) + hr = E_OUTOFMEMORY; + }
if (SUCCEEDED(hr)) - hr = StorageBaseImpl_ReadDirEntry((*snapshot), - (*snapshot)->storageDirEntry, &snapshotData); + { + memcpy(&This->entries[entry].data, &data, sizeof(DirEntry)); + This->entries[entry].read = 1; + } + } + + return hr; +} + +static HRESULT TransactedSnapshotImpl_MakeStreamDirty( + TransactedSnapshotImpl *This, DirRef entry) +{ + HRESULT hr = S_OK; + + if (!This->entries[entry].stream_dirty) + { + DirEntry new_entrydata; + + memset(&new_entrydata, 0, sizeof(DirEntry)); + new_entrydata.name[0] = 'S'; + new_entrydata.sizeOfNameString = 1; + new_entrydata.stgType = STGTY_STREAM; + new_entrydata.startingBlock = BLOCK_END_OF_CHAIN; + new_entrydata.leftChild = DIRENTRY_NULL; + new_entrydata.rightChild = DIRENTRY_NULL; + new_entrydata.dirRootEntry = DIRENTRY_NULL; + + hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata, + &This->entries[entry].stream_entry); + + if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL) + { + hr = StorageBaseImpl_CopyStream( + This->scratch, This->entries[entry].stream_entry, + This->transactedParent, This->entries[entry].transactedParentEntry); + + if (FAILED(hr)) + StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry); + }
if (SUCCEEDED(hr)) - { - memcpy(snapshotData.name, parentData.name, sizeof(snapshotData.name)); - snapshotData.sizeOfNameString = parentData.sizeOfNameString; - snapshotData.stgType = parentData.stgType; - snapshotData.clsid = parentData.clsid; - snapshotData.ctime = parentData.ctime; - snapshotData.mtime = parentData.mtime; - hr = StorageBaseImpl_WriteDirEntry((*snapshot), - (*snapshot)->storageDirEntry, &snapshotData); - } - - if (SUCCEEDED(hr)) - hr = IStorage_CopyTo((IStorage*)original, 0, NULL, NULL, - (IStorage*)(*snapshot)); - - if (FAILED(hr)) IStorage_Release((IStorage*)(*snapshot)); + This->entries[entry].stream_dirty = 1; + + if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL) + { + /* Since this entry is modified, and we aren't using its stream data, we + * no longer care about the original entry. */ + DirRef delete_ref; + delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry); + + if (delete_ref != DIRENTRY_NULL) + This->entries[delete_ref].deleted = 1; + + This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL; + } + } + + return hr; +} + +/* Find the first entry in a depth-first traversal. */ +static DirRef TransactedSnapshotImpl_FindFirstChild( + TransactedSnapshotImpl* This, DirRef parent) +{ + DirRef cursor, prev; + TransactedDirEntry *entry; + + cursor = parent; + entry = &This->entries[cursor]; + while (entry->read) + { + if (entry->data.leftChild != DIRENTRY_NULL) + { + prev = cursor; + cursor = entry->data.leftChild; + entry = &This->entries[cursor]; + entry->parent = prev; + } + else if (entry->data.rightChild != DIRENTRY_NULL) + { + prev = cursor; + cursor = entry->data.rightChild; + entry = &This->entries[cursor]; + entry->parent = prev; + } + else if (entry->data.dirRootEntry != DIRENTRY_NULL) + { + prev = cursor; + cursor = entry->data.dirRootEntry; + entry = &This->entries[cursor]; + entry->parent = prev; + } + else + break; + } + + return cursor; +} + +/* Find the next entry in a depth-first traversal. */ +static DirRef TransactedSnapshotImpl_FindNextChild( + TransactedSnapshotImpl* This, DirRef current) +{ + DirRef parent; + TransactedDirEntry *parent_entry; + + parent = This->entries[current].parent; + parent_entry = &This->entries[parent]; + + if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current) + { + if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL) + { + This->entries[parent_entry->data.rightChild].parent = parent; + return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.rightChild); + } + + if (parent_entry->data.dirRootEntry != DIRENTRY_NULL) + { + This->entries[parent_entry->data.dirRootEntry].parent = parent; + return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.dirRootEntry); + } + } + + return parent; +} + +/* Return TRUE if we've made a copy of this entry for committing to the parent. */ +static inline BOOL TransactedSnapshotImpl_MadeCopy( + TransactedSnapshotImpl* This, DirRef entry) +{ + return entry != DIRENTRY_NULL && + This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry; +} + +/* Destroy the entries created by CopyTree. */ +static void TransactedSnapshotImpl_DestroyTemporaryCopy( + TransactedSnapshotImpl* This, DirRef stop) +{ + DirRef cursor; + TransactedDirEntry *entry; + ULARGE_INTEGER zero; + + zero.QuadPart = 0; + + if (!This->entries[This->base.storageDirEntry].read) + return; + + cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry; + + if (cursor == DIRENTRY_NULL) + return; + + cursor = TransactedSnapshotImpl_FindFirstChild(This, cursor); + + while (cursor != DIRENTRY_NULL && cursor != stop) + { + if (TransactedSnapshotImpl_MadeCopy(This, cursor)) + { + entry = &This->entries[cursor]; + + if (entry->stream_dirty) + StorageBaseImpl_StreamSetSize(This->transactedParent, + entry->newTransactedParentEntry, zero); + + StorageBaseImpl_DestroyDirEntry(This->transactedParent, + entry->newTransactedParentEntry); + + entry->newTransactedParentEntry = entry->transactedParentEntry; + } + + cursor = TransactedSnapshotImpl_FindNextChild(This, cursor); + } +} + +/* Make a copy of our edited tree that we can use in the parent. */ +static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl* This) +{ + DirRef cursor; + TransactedDirEntry *entry; + HRESULT hr = S_OK; + + cursor = This->base.storageDirEntry; + entry = &This->entries[cursor]; + entry->parent = DIRENTRY_NULL; + entry->newTransactedParentEntry = entry->transactedParentEntry; + + if (entry->data.dirRootEntry == DIRENTRY_NULL) + return S_OK; + + This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL; + + cursor = TransactedSnapshotImpl_FindFirstChild(This, entry->data.dirRootEntry); + entry = &This->entries[cursor]; + + while (cursor != DIRENTRY_NULL) + { + /* Make a copy of this entry in the transacted parent. */ + if (!entry->read || + (!entry->dirty && !entry->stream_dirty && + !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) && + !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) && + !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry))) + entry->newTransactedParentEntry = entry->transactedParentEntry; + else + { + DirEntry newData; + + memcpy(&newData, &entry->data, sizeof(DirEntry)); + + newData.size.QuadPart = 0; + newData.startingBlock = BLOCK_END_OF_CHAIN; + + if (newData.leftChild != DIRENTRY_NULL) + newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry; + + if (newData.rightChild != DIRENTRY_NULL) + newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry; + + if (newData.dirRootEntry != DIRENTRY_NULL) + newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry; + + hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData, + &entry->newTransactedParentEntry); + if (FAILED(hr)) + { + TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor); + return hr; + } + + if (entry->stream_dirty) + { + hr = StorageBaseImpl_CopyStream( + This->transactedParent, entry->newTransactedParentEntry, + This->scratch, entry->stream_entry); + } + else if (entry->data.size.QuadPart) + { + hr = StorageBaseImpl_StreamLink( + This->transactedParent, entry->newTransactedParentEntry, + entry->transactedParentEntry); + } + + if (FAILED(hr)) + { + cursor = TransactedSnapshotImpl_FindNextChild(This, cursor); + TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor); + return hr; + } + } + + cursor = TransactedSnapshotImpl_FindNextChild(This, cursor); + entry = &This->entries[cursor]; }
return hr; @@ -4055,10 +4456,13 @@ DWORD grfCommitFlags) /* [in] */ { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface; + TransactedDirEntry *root_entry; + DirRef i, dir_root_ref; + DirEntry data; + ULARGE_INTEGER zero; HRESULT hr; - DirEntry data, tempStorageData, snapshotRootData; - DirRef tempStorageEntry, oldDirRoot; - StorageInternalImpl *tempStorage; + + zero.QuadPart = 0;
TRACE("(%p,%x)\n", iface, grfCommitFlags);
@@ -4072,75 +4476,71 @@ * needed in the rare situation where we have just enough free disk space to * overwrite the existing data. */
- /* Create an orphaned storage in the parent for the new directory structure. */ - memset(&data, 0, sizeof(data)); - data.name[0] = 'D'; - data.sizeOfNameString = 1; - data.stgType = STGTY_STORAGE; - data.leftChild = DIRENTRY_NULL; - data.rightChild = DIRENTRY_NULL; - data.dirRootEntry = DIRENTRY_NULL; - hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &data, &tempStorageEntry); - + root_entry = &This->entries[This->base.storageDirEntry]; + + if (!root_entry->read) + return S_OK; + + hr = TransactedSnapshotImpl_CopyTree(This); if (FAILED(hr)) return hr;
- tempStorage = StorageInternalImpl_Construct(This->transactedParent, - STGM_READWRITE|STGM_SHARE_EXCLUSIVE, tempStorageEntry); - if (tempStorage) - { - hr = IStorage_CopyTo((IStorage*)This->snapshot, 0, NULL, NULL, - (IStorage*)tempStorage); - - list_init(&tempStorage->ParentListEntry); - - IStorage_Release((IStorage*) tempStorage); - } + if (root_entry->data.dirRootEntry == DIRENTRY_NULL) + dir_root_ref = DIRENTRY_NULL; else - hr = E_OUTOFMEMORY; - - if (FAILED(hr)) - { - DestroyReachableEntries(This->transactedParent, tempStorageEntry); - return hr; - } + dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
/* Update the storage to use the new data in one step. */ hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, - This->transactedParent->storageDirEntry, &data); + root_entry->transactedParentEntry, &data);
if (SUCCEEDED(hr)) { - hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, - tempStorageEntry, &tempStorageData); + data.dirRootEntry = dir_root_ref; + data.clsid = root_entry->data.clsid; + data.ctime = root_entry->data.ctime; + data.mtime = root_entry->data.mtime; + + hr = StorageBaseImpl_WriteDirEntry(This->transactedParent, + root_entry->transactedParentEntry, &data); }
if (SUCCEEDED(hr)) { - hr = StorageBaseImpl_ReadDirEntry(This->snapshot, - This->snapshot->storageDirEntry, &snapshotRootData); - } - - if (SUCCEEDED(hr)) - { - oldDirRoot = data.dirRootEntry; - data.dirRootEntry = tempStorageData.dirRootEntry; - data.clsid = snapshotRootData.clsid; - data.ctime = snapshotRootData.ctime; - data.mtime = snapshotRootData.mtime; - - hr = StorageBaseImpl_WriteDirEntry(This->transactedParent, - This->transactedParent->storageDirEntry, &data); - } - - if (SUCCEEDED(hr)) - { /* Destroy the old now-orphaned data. */ - DestroyReachableEntries(This->transactedParent, oldDirRoot); - StorageBaseImpl_DestroyDirEntry(This->transactedParent, tempStorageEntry); + for (i=0; i<This->entries_size; i++) + { + TransactedDirEntry *entry = &This->entries[i]; + if (entry->inuse) + { + if (entry->deleted) + { + StorageBaseImpl_StreamSetSize(This->transactedParent, + entry->transactedParentEntry, zero); + StorageBaseImpl_DestroyDirEntry(This->transactedParent, + entry->transactedParentEntry); + memset(entry, 0, sizeof(TransactedDirEntry)); + This->firstFreeEntry = min(i, This->firstFreeEntry); + } + else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry) + { + if (entry->transactedParentEntry != DIRENTRY_NULL) + StorageBaseImpl_DestroyDirEntry(This->transactedParent, + entry->transactedParentEntry); + if (entry->stream_dirty) + { + StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero); + StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry); + entry->stream_dirty = 0; + } + entry->dirty = 0; + entry->transactedParentEntry = entry->newTransactedParentEntry; + } + } + } } else { - DestroyReachableEntries(This->transactedParent, tempStorageEntry); + TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL); }
return hr; @@ -4150,21 +4550,31 @@ IStorage* iface) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface; - StorageBaseImpl *newSnapshot; - HRESULT hr; + ULARGE_INTEGER zero; + ULONG i;
TRACE("(%p)\n", iface); - - /* Create a new copy of the parent data. */ - hr = CreateSnapshotFile(This->transactedParent, &newSnapshot); - if (FAILED(hr)) return hr;
/* Destroy the open objects. */ StorageBaseImpl_DeleteAll(&This->base);
- /* Replace our current snapshot. */ - IStorage_Release((IStorage*)This->snapshot); - This->snapshot = newSnapshot; + /* Clear out the scratch file. */ + zero.QuadPart = 0; + for (i=0; i<This->entries_size; i++) + { + if (This->entries[i].stream_dirty) + { + StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry, + zero); + + StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry); + } + } + + memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size); + + This->firstFreeEntry = 0; + This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
return S_OK; } @@ -4185,11 +4595,13 @@ { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
- TransactedSnapshotImpl_Invalidate(iface); + TransactedSnapshotImpl_Revert((IStorage*)iface);
IStorage_Release((IStorage*)This->transactedParent);
- IStorage_Release((IStorage*)This->snapshot); + IStorage_Release((IStorage*)This->scratch); + + HeapFree(GetProcessHeap(), 0, This->entries);
HeapFree(GetProcessHeap(), 0, This); } @@ -4198,27 +4610,76 @@ const DirEntry *newData, DirRef *index) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; - - return StorageBaseImpl_CreateDirEntry(This->snapshot, - newData, index); + DirRef new_ref; + TransactedDirEntry *new_entry; + + new_ref = TransactedSnapshotImpl_FindFreeEntry(This); + if (new_ref == DIRENTRY_NULL) + return E_OUTOFMEMORY; + + new_entry = &This->entries[new_ref]; + + new_entry->newTransactedParentEntry = new_entry->transactedParentEntry = DIRENTRY_NULL; + new_entry->read = 1; + new_entry->dirty = 1; + memcpy(&new_entry->data, newData, sizeof(DirEntry)); + + *index = new_ref; + + TRACE("%s l=%x r=%x d=%x <-- %x\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index); + + return S_OK; }
static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base, DirRef index, const DirEntry *data) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; - - return StorageBaseImpl_WriteDirEntry(This->snapshot, - index, data); + HRESULT hr; + + TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry); + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, index); + if (FAILED(hr)) return hr; + + memcpy(&This->entries[index].data, data, sizeof(DirEntry)); + + if (index != This->base.storageDirEntry) + { + This->entries[index].dirty = 1; + + if (data->size.QuadPart == 0 && + This->entries[index].transactedParentEntry != DIRENTRY_NULL) + { + /* Since this entry is modified, and we aren't using its stream data, we + * no longer care about the original entry. */ + DirRef delete_ref; + delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry); + + if (delete_ref != DIRENTRY_NULL) + This->entries[delete_ref].deleted = 1; + + This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL; + } + } + + return S_OK; }
static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base, DirRef index, DirEntry *data) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; - - return StorageBaseImpl_ReadDirEntry(This->snapshot, - index, data); + HRESULT hr; + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, index); + if (FAILED(hr)) return hr; + + memcpy(data, &This->entries[index].data, sizeof(DirEntry)); + + TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry); + + return S_OK; }
static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base, @@ -4226,8 +4687,21 @@ { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
- return StorageBaseImpl_DestroyDirEntry(This->snapshot, - index); + if (This->entries[index].transactedParentEntry == DIRENTRY_NULL || + This->entries[index].data.size.QuadPart != 0) + { + /* If we deleted this entry while it has stream data. We must have left the + * data because some other entry is using it, and we need to leave the + * original entry alone. */ + memset(&This->entries[index], 0, sizeof(TransactedDirEntry)); + This->firstFreeEntry = min(index, This->firstFreeEntry); + } + else + { + This->entries[index].deleted = 1; + } + + return S_OK; }
static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base, @@ -4235,26 +4709,122 @@ { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
- return StorageBaseImpl_StreamReadAt(This->snapshot, - index, offset, size, buffer, bytesRead); + if (This->entries[index].stream_dirty) + { + return StorageBaseImpl_StreamReadAt(This->scratch, + This->entries[index].stream_entry, offset, size, buffer, bytesRead); + } + else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL) + { + /* This stream doesn't live in the parent, and we haven't allocated storage + * for it yet */ + *bytesRead = 0; + return S_OK; + } + else + { + return StorageBaseImpl_StreamReadAt(This->transactedParent, + This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead); + } }
static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; - - return StorageBaseImpl_StreamWriteAt(This->snapshot, - index, offset, size, buffer, bytesWritten); + HRESULT hr; + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, index); + if (FAILED(hr)) return hr; + + hr = TransactedSnapshotImpl_MakeStreamDirty(This, index); + if (FAILED(hr)) return hr; + + hr = StorageBaseImpl_StreamWriteAt(This->scratch, + This->entries[index].stream_entry, offset, size, buffer, bytesWritten); + + if (SUCCEEDED(hr) && size != 0) + This->entries[index].data.size.QuadPart = max( + This->entries[index].data.size.QuadPart, + offset.QuadPart + size); + + return hr; }
static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER newsize) { TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; - - return StorageBaseImpl_StreamSetSize(This->snapshot, - index, newsize); + HRESULT hr; + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, index); + if (FAILED(hr)) return hr; + + if (This->entries[index].data.size.QuadPart == newsize.QuadPart) + return S_OK; + + if (newsize.QuadPart == 0) + { + /* Destroy any parent references or entries in the scratch file. */ + if (This->entries[index].stream_dirty) + { + ULARGE_INTEGER zero; + zero.QuadPart = 0; + StorageBaseImpl_StreamSetSize(This->scratch, + This->entries[index].stream_entry, zero); + StorageBaseImpl_DestroyDirEntry(This->scratch, + This->entries[index].stream_entry); + This->entries[index].stream_dirty = 0; + } + else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL) + { + DirRef delete_ref; + delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry); + + if (delete_ref != DIRENTRY_NULL) + This->entries[delete_ref].deleted = 1; + + This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL; + } + } + else + { + hr = TransactedSnapshotImpl_MakeStreamDirty(This, index); + if (FAILED(hr)) return hr; + + hr = StorageBaseImpl_StreamSetSize(This->scratch, + This->entries[index].stream_entry, newsize); + } + + if (SUCCEEDED(hr)) + This->entries[index].data.size = newsize; + + return hr; +} + +static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base, + DirRef dst, DirRef src) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + HRESULT hr; + TransactedDirEntry *dst_entry, *src_entry; + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, src); + if (FAILED(hr)) return hr; + + hr = TransactedSnapshotImpl_EnsureReadEntry(This, dst); + if (FAILED(hr)) return hr; + + dst_entry = &This->entries[dst]; + src_entry = &This->entries[src]; + + dst_entry->stream_dirty = src_entry->stream_dirty; + dst_entry->stream_entry = src_entry->stream_entry; + dst_entry->transactedParentEntry = src_entry->transactedParentEntry; + dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry; + dst_entry->data.size = src_entry->data.size; + + return S_OK; }
static const IStorageVtbl TransactedSnapshotImpl_Vtbl = @@ -4289,7 +4859,8 @@ TransactedSnapshotImpl_DestroyDirEntry, TransactedSnapshotImpl_StreamReadAt, TransactedSnapshotImpl_StreamWriteAt, - TransactedSnapshotImpl_StreamSetSize + TransactedSnapshotImpl_StreamSetSize, + TransactedSnapshotImpl_StreamLink };
static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage, @@ -4317,17 +4888,35 @@
(*result)->base.filename = parentStorage->filename;
- /* Create a new temporary storage to act as the snapshot */ - hr = CreateSnapshotFile(parentStorage, &(*result)->snapshot); + /* Create a new temporary storage to act as the scratch file. */ + hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE, + 0, (IStorage**)&(*result)->scratch);
if (SUCCEEDED(hr)) { - (*result)->base.storageDirEntry = (*result)->snapshot->storageDirEntry; - - /* parentStorage already has 1 reference, which we take over here. */ - (*result)->transactedParent = parentStorage; - - parentStorage->transactedChild = (StorageBaseImpl*)*result; + ULONG num_entries = 20; + + (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries); + + (*result)->entries_size = num_entries; + + (*result)->firstFreeEntry = 0; + + if ((*result)->entries) + { + /* parentStorage already has 1 reference, which we take over here. */ + (*result)->transactedParent = parentStorage; + + parentStorage->transactedChild = (StorageBaseImpl*)*result; + + (*result)->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(*result, parentStorage->storageDirEntry); + } + else + { + IStorage_Release((IStorage*)(*result)->scratch); + + hr = E_OUTOFMEMORY; + } }
if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result)); @@ -4472,6 +5061,15 @@
return StorageBaseImpl_StreamSetSize(This->parentStorage, index, newsize); +} + +static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base, + DirRef dst, DirRef src) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_StreamLink(This->parentStorage, + dst, src); }
/****************************************************************************** @@ -4833,7 +5431,8 @@ StorageInternalImpl_DestroyDirEntry, StorageInternalImpl_StreamReadAt, StorageInternalImpl_StreamWriteAt, - StorageInternalImpl_StreamSetSize + StorageInternalImpl_StreamSetSize, + StorageInternalImpl_StreamLink };
/****************************************************************************** @@ -5026,38 +5625,134 @@ ** BlockChainStream implementation */
+/* Read and save the index of all blocks in this stream. */ +HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream* This) +{ + ULONG next_sector, next_offset; + HRESULT hr; + struct BlockChainRun *last_run; + + if (This->indexCacheLen == 0) + { + last_run = NULL; + next_offset = 0; + next_sector = BlockChainStream_GetHeadOfChain(This); + } + else + { + last_run = &This->indexCache[This->indexCacheLen-1]; + next_offset = last_run->lastOffset+1; + hr = StorageImpl_GetNextBlockInChain(This->parentStorage, + last_run->firstSector + last_run->lastOffset - last_run->firstOffset, + &next_sector); + if (FAILED(hr)) return hr; + } + + while (next_sector != BLOCK_END_OF_CHAIN) + { + if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset) + { + /* Add the current block to the cache. */ + if (This->indexCacheSize == 0) + { + This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16); + if (!This->indexCache) return E_OUTOFMEMORY; + This->indexCacheSize = 16; + } + else if (This->indexCacheSize == This->indexCacheLen) + { + struct BlockChainRun *new_cache; + ULONG new_size; + + new_size = This->indexCacheSize * 2; + new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size); + if (!new_cache) return E_OUTOFMEMORY; + memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen); + + HeapFree(GetProcessHeap(), 0, This->indexCache); + This->indexCache = new_cache; + This->indexCacheSize = new_size; + } + + This->indexCacheLen++; + last_run = &This->indexCache[This->indexCacheLen-1]; + last_run->firstSector = next_sector; + last_run->firstOffset = next_offset; + } + + last_run->lastOffset = next_offset; + + /* Find the next block. */ + next_offset++; + hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector); + if (FAILED(hr)) return hr; + } + + if (This->indexCacheLen) + { + This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset; + This->numBlocks = last_run->lastOffset+1; + } + else + { + This->tailIndex = BLOCK_END_OF_CHAIN; + This->numBlocks = 0; + } + + return S_OK; +} + +/* Locate the nth block in this stream. */ +ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset) +{ + ULONG min_offset = 0, max_offset = This->numBlocks-1; + ULONG min_run = 0, max_run = This->indexCacheLen-1; + + if (offset >= This->numBlocks) + return BLOCK_END_OF_CHAIN; + + while (min_run < max_run) + { + ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset); + if (offset < This->indexCache[run_to_check].firstOffset) + { + max_offset = This->indexCache[run_to_check].firstOffset-1; + max_run = run_to_check-1; + } + else if (offset > This->indexCache[run_to_check].lastOffset) + { + min_offset = This->indexCache[run_to_check].lastOffset+1; + min_run = run_to_check+1; + } + else + /* Block is in this run. */ + min_run = max_run = run_to_check; + } + + return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset; +} + BlockChainStream* BlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, DirRef dirEntry) { BlockChainStream* newStream; - ULONG blockIndex;
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
newStream->parentStorage = parentStorage; newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; newStream->ownerDirEntry = dirEntry; - newStream->lastBlockNoInSequence = 0xFFFFFFFF; - newStream->tailIndex = BLOCK_END_OF_CHAIN; - newStream->numBlocks = 0; - - blockIndex = BlockChainStream_GetHeadOfChain(newStream); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - newStream->numBlocks++; - newStream->tailIndex = blockIndex; - - if(FAILED(StorageImpl_GetNextBlockInChain( - parentStorage, - blockIndex, - &blockIndex))) - { - HeapFree(GetProcessHeap(), 0, newStream); - return NULL; - } + newStream->indexCache = NULL; + newStream->indexCacheLen = 0; + newStream->indexCacheSize = 0; + + if (FAILED(BlockChainStream_UpdateIndexCache(newStream))) + { + HeapFree(GetProcessHeap(), 0, newStream->indexCache); + HeapFree(GetProcessHeap(), 0, newStream); + return NULL; }
return newStream; @@ -5065,6 +5760,8 @@
void BlockChainStream_Destroy(BlockChainStream* This) { + if (This) + HeapFree(GetProcessHeap(), 0, This->indexCache); HeapFree(GetProcessHeap(), 0, This); }
@@ -5105,27 +5802,10 @@ * * Returns the number of blocks that comprises this chain. * This is not the size of the stream as the last block may not be full! - * */ static ULONG BlockChainStream_GetCount(BlockChainStream* This) { - ULONG blockIndex; - ULONG count = 0; - - blockIndex = BlockChainStream_GetHeadOfChain(This); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - count++; - - if(FAILED(StorageImpl_GetNextBlockInChain( - This->parentStorage, - blockIndex, - &blockIndex))) - return 0; - } - - return count; + return This->numBlocks; }
/****************************************************************************** @@ -5146,44 +5826,26 @@ ULONG bytesToReadInBuffer; ULONG blockIndex; BYTE* bufferWalker; + ULARGE_INTEGER stream_size;
TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
/* * Find the first block in the stream that contains part of the buffer. */ - if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || - (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || - (blockNoInSequence < This->lastBlockNoInSequence) ) - { - blockIndex = BlockChainStream_GetHeadOfChain(This); - This->lastBlockNoInSequence = blockNoInSequence; - } + blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence); + + *bytesRead = 0; + + stream_size = BlockChainStream_GetSize(This); + if (stream_size.QuadPart > offset.QuadPart) + size = min(stream_size.QuadPart - offset.QuadPart, size); else - { - ULONG temp = blockNoInSequence; - - blockIndex = This->lastBlockNoInSequenceIndex; - blockNoInSequence -= This->lastBlockNoInSequence; - This->lastBlockNoInSequence = temp; - } - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return STG_E_DOCFILECORRUPT; - blockNoInSequence--; - } - - if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN)) - return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */ - - This->lastBlockNoInSequenceIndex = blockIndex; + return S_OK;
/* * Start reading the buffer. */ - *bytesRead = 0; bufferWalker = buffer;
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) @@ -5221,7 +5883,7 @@ break; }
- return (size == 0) ? S_OK : STG_E_READFAULT; + return S_OK; }
/****************************************************************************** @@ -5245,31 +5907,7 @@ /* * Find the first block in the stream that contains part of the buffer. */ - if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || - (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || - (blockNoInSequence < This->lastBlockNoInSequence) ) - { - blockIndex = BlockChainStream_GetHeadOfChain(This); - This->lastBlockNoInSequence = blockNoInSequence; - } - else - { - ULONG temp = blockNoInSequence; - - blockIndex = This->lastBlockNoInSequenceIndex; - blockNoInSequence -= This->lastBlockNoInSequence; - This->lastBlockNoInSequence = temp; - } - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &blockIndex))) - return STG_E_DOCFILECORRUPT; - blockNoInSequence--; - } - - This->lastBlockNoInSequenceIndex = blockIndex; + blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
/* BlockChainStream_SetSize should have already been called to ensure we have * enough blocks in the chain to write into */ @@ -5330,15 +5968,8 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This, ULARGE_INTEGER newSize) { - ULONG blockIndex, extraBlock; + ULONG blockIndex; ULONG numBlocks; - ULONG count = 1; - - /* - * Reset the last accessed block cache. - */ - This->lastBlockNoInSequence = 0xFFFFFFFF; - This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
/* * Figure out how many blocks are needed to contain the new size @@ -5348,43 +5979,62 @@ if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0) numBlocks++;
- blockIndex = BlockChainStream_GetHeadOfChain(This); - - /* - * Go to the new end of chain - */ - while (count < numBlocks) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &blockIndex))) - return FALSE; - count++; - } - - /* Get the next block before marking the new end */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &extraBlock))) - return FALSE; - - /* Mark the new end of chain */ - StorageImpl_SetNextBlockInChain( - This->parentStorage, - blockIndex, - BLOCK_END_OF_CHAIN); - - This->tailIndex = blockIndex; + if (numBlocks) + { + /* + * Go to the new end of chain + */ + blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1); + + /* Mark the new end of chain */ + StorageImpl_SetNextBlockInChain( + This->parentStorage, + blockIndex, + BLOCK_END_OF_CHAIN); + + This->tailIndex = blockIndex; + } + else + { + if (This->headOfStreamPlaceHolder != 0) + { + *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN; + } + else + { + DirEntry chainEntry; + assert(This->ownerDirEntry != DIRENTRY_NULL); + + StorageImpl_ReadDirEntry( + This->parentStorage, + This->ownerDirEntry, + &chainEntry); + + chainEntry.startingBlock = BLOCK_END_OF_CHAIN; + + StorageImpl_WriteDirEntry( + This->parentStorage, + This->ownerDirEntry, + &chainEntry); + } + + This->tailIndex = BLOCK_END_OF_CHAIN; + } + This->numBlocks = numBlocks;
/* * Mark the extra blocks as free */ - while (extraBlock != BLOCK_END_OF_CHAIN) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock, - &blockIndex))) - return FALSE; - StorageImpl_FreeBigBlock(This->parentStorage, extraBlock); - extraBlock = blockIndex; + while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks) + { + struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1]; + StorageImpl_FreeBigBlock(This->parentStorage, + last_run->firstSector + last_run->lastOffset - last_run->firstOffset); + if (last_run->lastOffset == last_run->firstOffset) + This->indexCacheLen--; + else + last_run->lastOffset--; }
return TRUE; @@ -5497,6 +6147,9 @@ This->tailIndex = blockIndex; This->numBlocks = newNumBlocks; } + + if (FAILED(BlockChainStream_UpdateIndexCache(This))) + return FALSE;
return TRUE; } @@ -5663,6 +6316,9 @@ &buffer, &bytesRead);
+ if (SUCCEEDED(res) && bytesRead != sizeof(DWORD)) + res = STG_E_READFAULT; + if (SUCCEEDED(res)) { StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain); @@ -5734,6 +6390,9 @@ ULONG nextBlockIndex = BLOCK_END_OF_CHAIN; HRESULT res = S_OK; ULONG smallBlocksPerBigBlock; + DirEntry rootEntry; + ULONG blocksRequired; + ULARGE_INTEGER old_size, size_required;
offsetOfBlockInDepot.u.HighPart = 0;
@@ -5754,7 +6413,7 @@ /* * If we run out of space for the small block depot, enlarge it */ - if (SUCCEEDED(res)) + if (SUCCEEDED(res) && bytesRead == sizeof(DWORD)) { StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
@@ -5766,76 +6425,22 @@ ULONG count = BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
- ULONG sbdIndex = This->parentStorage->smallBlockDepotStart; - ULONG nextBlock, newsbdIndex; BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE]; - - nextBlock = sbdIndex; - while (nextBlock != BLOCK_END_OF_CHAIN) - { - sbdIndex = nextBlock; - StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock); - } - - newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); - if (sbdIndex != BLOCK_END_OF_CHAIN) - StorageImpl_SetNextBlockInChain( - This->parentStorage, - sbdIndex, - newsbdIndex); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - newsbdIndex, - BLOCK_END_OF_CHAIN); + ULARGE_INTEGER newSize, offset; + ULONG bytesWritten; + + newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize; + BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
/* * Initialize all the small blocks to free */ memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize); - StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot); - - if (count == 0) - { - /* - * We have just created the small block depot. - */ - DirEntry rootEntry; - ULONG sbStartIndex; - - /* - * Save it in the header - */ - This->parentStorage->smallBlockDepotStart = newsbdIndex; - StorageImpl_SaveFileHeader(This->parentStorage); - - /* - * And allocate the first big block that will contain small blocks - */ - sbStartIndex = - StorageImpl_GetNextFreeBigBlock(This->parentStorage); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - sbStartIndex, - BLOCK_END_OF_CHAIN); - - StorageImpl_ReadDirEntry( - This->parentStorage, - This->parentStorage->base.storageDirEntry, - &rootEntry); - - rootEntry.startingBlock = sbStartIndex; - rootEntry.size.u.HighPart = 0; - rootEntry.size.u.LowPart = This->parentStorage->bigBlockSize; - - StorageImpl_WriteDirEntry( - This->parentStorage, - This->parentStorage->base.storageDirEntry, - &rootEntry); - } - else - StorageImpl_SaveFileHeader(This->parentStorage); + offset.QuadPart = count * This->parentStorage->bigBlockSize; + BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain, + offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten); + + StorageImpl_SaveFileHeader(This->parentStorage); } }
@@ -5847,30 +6452,29 @@ /* * Verify if we have to allocate big blocks to contain small blocks */ - if (blockIndex % smallBlocksPerBigBlock == 0) - { - DirEntry rootEntry; - ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; + blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; + + size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize; + + old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain); + + if (size_required.QuadPart > old_size.QuadPart) + { + BlockChainStream_SetSize( + This->parentStorage->smallBlockRootChain, + size_required);
StorageImpl_ReadDirEntry( This->parentStorage, This->parentStorage->base.storageDirEntry, &rootEntry);
- if (rootEntry.size.u.LowPart < - (blocksRequired * This->parentStorage->bigBlockSize)) - { - rootEntry.size.u.LowPart += This->parentStorage->bigBlockSize; - - BlockChainStream_SetSize( - This->parentStorage->smallBlockRootChain, - rootEntry.size); - - StorageImpl_WriteDirEntry( - This->parentStorage, - This->parentStorage->base.storageDirEntry, - &rootEntry); - } + rootEntry.size = size_required; + + StorageImpl_WriteDirEntry( + This->parentStorage, + This->parentStorage->base.storageDirEntry, + &rootEntry); }
return blockIndex; @@ -5900,11 +6504,20 @@ ULONG blockIndex; ULONG bytesReadFromBigBlockFile; BYTE* bufferWalker; + ULARGE_INTEGER stream_size;
/* * This should never happen on a small block file. */ assert(offset.u.HighPart==0); + + *bytesRead = 0; + + stream_size = SmallBlockChainStream_GetSize(This); + if (stream_size.QuadPart > offset.QuadPart) + size = min(stream_size.QuadPart - offset.QuadPart, size); + else + return S_OK;
/* * Find the first block in the stream that contains part of the buffer. @@ -5922,7 +6535,6 @@ /* * Start reading the buffer. */ - *bytesRead = 0; bufferWalker = buffer;
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) @@ -5956,6 +6568,9 @@ if (FAILED(rc)) return rc;
+ if (!bytesReadFromBigBlockFile) + return STG_E_DOCFILECORRUPT; + /* * Step to the next big block. */ @@ -5969,7 +6584,7 @@ offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize; }
- return (size == 0) ? S_OK : STG_E_READFAULT; + return S_OK; }
/******************************************************************************
Modified: trunk/reactos/dll/win32/ole32/storage32.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/storage32.h... ============================================================================== --- trunk/reactos/dll/win32/ole32/storage32.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/storage32.h [iso-8859-1] Sat May 29 13:34:57 2010 @@ -263,6 +263,7 @@ HRESULT (*StreamReadAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,void*,ULONG*); HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const void*,ULONG*); HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER); + HRESULT (*StreamLink)(StorageBaseImpl*,DirRef,DirRef); };
static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This) @@ -318,6 +319,16 @@ DirRef index, ULARGE_INTEGER newsize) { return This->baseVtbl->StreamSetSize(This, index, newsize); +} + +/* Make dst point to the same stream that src points to. Other stream operations + * will not work properly for entries that point to the same stream, so this + * must be a very temporary state, and only one entry pointing to a given stream + * may be reachable at any given time. */ +static inline HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This, + DirRef dst, DirRef src) +{ + return This->baseVtbl->StreamLink(This, dst, src); }
/**************************************************************************** @@ -513,13 +524,22 @@ * The BlockChainStream class is a utility class that is used to create an * abstraction of the big block chains in the storage file. */ +struct BlockChainRun +{ + /* This represents a range of blocks that happen reside in consecutive sectors. */ + ULONG firstSector; + ULONG firstOffset; + ULONG lastOffset; +}; + struct BlockChainStream { StorageImpl* parentStorage; ULONG* headOfStreamPlaceHolder; DirRef ownerDirEntry; - ULONG lastBlockNoInSequence; - ULONG lastBlockNoInSequenceIndex; + struct BlockChainRun* indexCache; + ULONG indexCacheLen; + ULONG indexCacheSize; ULONG tailIndex; ULONG numBlocks; };
Modified: trunk/reactos/dll/win32/ole32/usrmarshal.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/usrmarshal.... ============================================================================== --- trunk/reactos/dll/win32/ole32/usrmarshal.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ole32/usrmarshal.c [iso-8859-1] Sat May 29 13:34:57 2010 @@ -2761,7 +2761,8 @@ FORMATETC *pFormatetc, STGMEDIUM *pStgmed) { - FIXME(":stub\n"); + TRACE("(%p)->(%p, %p)\n", This, pFormatetc, pStgmed); + IAdviseSink_RemoteOnDataChange_Proxy(This, pFormatetc, pStgmed); }
HRESULT __RPC_STUB IAdviseSink_OnDataChange_Stub( @@ -2769,8 +2770,9 @@ FORMATETC *pFormatetc, ASYNC_STGMEDIUM *pStgmed) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)->(%p, %p)\n", This, pFormatetc, pStgmed); + IAdviseSink_OnDataChange(This, pFormatetc, pStgmed); + return S_OK; }
void CALLBACK IAdviseSink_OnViewChange_Proxy( @@ -2778,7 +2780,8 @@ DWORD dwAspect, LONG lindex) { - FIXME(":stub\n"); + TRACE("(%p)->(%d, %d)\n", This, dwAspect, lindex); + IAdviseSink_RemoteOnViewChange_Proxy(This, dwAspect, lindex); }
HRESULT __RPC_STUB IAdviseSink_OnViewChange_Stub( @@ -2786,64 +2789,73 @@ DWORD dwAspect, LONG lindex) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)->(%d, %d)\n", This, dwAspect, lindex); + IAdviseSink_OnViewChange(This, dwAspect, lindex); + return S_OK; }
void CALLBACK IAdviseSink_OnRename_Proxy( IAdviseSink* This, IMoniker *pmk) { - FIXME(":stub\n"); + TRACE("(%p)->(%p)\n", This, pmk); + IAdviseSink_RemoteOnRename_Proxy(This, pmk); }
HRESULT __RPC_STUB IAdviseSink_OnRename_Stub( IAdviseSink* This, IMoniker *pmk) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, pmk); + IAdviseSink_OnRename(This, pmk); + return S_OK; }
void CALLBACK IAdviseSink_OnSave_Proxy( IAdviseSink* This) { - FIXME(":stub\n"); + TRACE("(%p)\n", This); + IAdviseSink_RemoteOnSave_Proxy(This); }
HRESULT __RPC_STUB IAdviseSink_OnSave_Stub( IAdviseSink* This) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)\n", This); + IAdviseSink_OnSave(This); + return S_OK; }
void CALLBACK IAdviseSink_OnClose_Proxy( IAdviseSink* This) { - FIXME(":stub\n"); + TRACE("(%p)\n", This); + IAdviseSink_RemoteOnClose_Proxy(This); }
HRESULT __RPC_STUB IAdviseSink_OnClose_Stub( IAdviseSink* This) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)\n", This); + IAdviseSink_OnClose(This); + return S_OK; }
void CALLBACK IAdviseSink2_OnLinkSrcChange_Proxy( IAdviseSink2* This, IMoniker *pmk) { - FIXME(":stub\n"); + TRACE("(%p)->(%p)\n", This, pmk); + IAdviseSink2_RemoteOnLinkSrcChange_Proxy(This, pmk); }
HRESULT __RPC_STUB IAdviseSink2_OnLinkSrcChange_Stub( IAdviseSink2* This, IMoniker *pmk) { - FIXME(":stub\n"); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, pmk); + IAdviseSink2_OnLinkSrcChange(This, pmk); + return S_OK; }
HRESULT CALLBACK IDataObject_GetData_Proxy(