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.…
==============================================================================
--- 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?r…
==============================================================================
--- 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?…
==============================================================================
--- 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/compositem…
==============================================================================
--- 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/defaulthan…
==============================================================================
--- 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/hglobalstr…
==============================================================================
--- 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=…
==============================================================================
--- 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?…
==============================================================================
--- 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?…
==============================================================================
--- 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.…
==============================================================================
--- 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.…
==============================================================================
--- 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(