Author: akhaldi
Date: Fri Oct 3 11:44:27 2014
New Revision: 64491
URL:
http://svn.reactos.org/svn/reactos?rev=64491&view=rev
Log:
[OLE32]
* Sync with Wine 1.7.27.
CORE-8540
Modified:
trunk/reactos/dll/win32/ole32/compobj.c
trunk/reactos/dll/win32/ole32/filelockbytes.c
trunk/reactos/dll/win32/ole32/filemoniker.c
trunk/reactos/dll/win32/ole32/ole2.c
trunk/reactos/dll/win32/ole32/stg_stream.c
trunk/reactos/dll/win32/ole32/storage32.c
trunk/reactos/dll/win32/ole32/storage32.h
trunk/reactos/media/doc/README.WINE
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] Fri Oct 3 11:44:27 2014
@@ -314,7 +314,7 @@
static HKEY classes_root_hkey;
/* create the special HKEY_CLASSES_ROOT key */
-static HKEY create_classes_root_hkey(void)
+static HKEY create_classes_root_hkey(DWORD access)
{
HKEY hkey, ret = 0;
OBJECT_ATTRIBUTES attr;
@@ -327,23 +327,39 @@
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
RtlInitUnicodeString( &name, classes_rootW );
- if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
+ if (create_key( &hkey, access, &attr )) return 0;
TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
- if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey,
0 )))
+ if (!(access & KEY_WOW64_64KEY))
+ {
+ if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey,
hkey, 0 )))
+ ret = hkey;
+ else
+ NtClose( hkey ); /* somebody beat us to it */
+ }
+ else
ret = hkey;
- else
- NtClose( hkey ); /* somebody beat us to it */
return ret;
}
/* map the hkey from special root to normal key if necessary */
-static inline HKEY get_classes_root_hkey( HKEY hkey )
+static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
{
HKEY ret = hkey;
-
- if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
- ret = create_classes_root_hkey();
+ const BOOL is_win64 = sizeof(void*) > sizeof(int);
+ const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
+
+ if (hkey == HKEY_CLASSES_ROOT &&
+ ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
+ ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access &
KEY_WOW64_64KEY));
+ if (force_wow32 && ret && ret == classes_root_hkey)
+ {
+ static const WCHAR wow6432nodeW[] =
{'W','o','w','6','4','3','2','N','o','d','e',0};
+ access &= ~KEY_WOW64_32KEY;
+ if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
+ return 0;
+ ret = hkey;
+ }
return ret;
}
@@ -353,7 +369,7 @@
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW;
- if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+ if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
@@ -371,7 +387,7 @@
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW;
- if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+ if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
attr.Length = sizeof(attr);
attr.RootDirectory = hkey;
@@ -1174,7 +1190,7 @@
return ret;
}
-/* The given OXID must be local to this process:
+/* The given OXID must be local to this process:
*
* The ref parameter is here mostly to ensure people remember that
* they get one, you should normally take a ref for thread safety.
@@ -1639,14 +1655,27 @@
* already been created */
HRESULT apartment_createwindowifneeded(struct apartment *apt)
{
+#ifndef __REACTOS__
+ static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
+#endif
+
if (apt->multi_threaded)
return S_OK;
if (!apt->win)
{
+#ifndef __REACTOS__
+ HWND hwnd;
+
+ InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
+
+ hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
+ HWND_MESSAGE, 0, hProxyDll, NULL);
+#else
HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
0, 0, 0, 0,
HWND_MESSAGE, 0, hProxyDll, NULL);
+#endif
if (!hwnd)
{
ERR("CreateWindow failed with error %d\n", GetLastError());
@@ -2054,7 +2083,11 @@
*/
HRESULT WINAPI CoCreateGuid(GUID *pguid)
{
- DWORD status = UuidCreate(pguid);
+ DWORD status;
+
+ if(!pguid) return E_INVALIDARG;
+
+ status = UuidCreate(pguid);
if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
return HRESULT_FROM_WIN32( status );
}
@@ -2474,6 +2507,28 @@
return CLSIDFromProgID(progid, clsid);
}
+static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID
*pclsid)
+{
+ HKEY hkey;
+ WCHAR value[CHARS_IN_GUID];
+ DWORD len;
+
+ access |= KEY_READ;
+
+ if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
+ return REGDB_E_IIDNOTREG;
+
+ len = sizeof(value);
+ if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value,
&len))
+ return REGDB_E_IIDNOTREG;
+ RegCloseKey(hkey);
+
+ if (CLSIDFromString(value, pclsid) != NOERROR)
+ return REGDB_E_IIDNOTREG;
+
+ return S_OK;
+}
+
/*****************************************************************************
* CoGetPSClsid [OLE32.@]
*
@@ -2483,7 +2538,7 @@
* PARAMS
* riid [I] Interface whose proxy/stub CLSID is to be returned.
* pclsid [O] Where to store returned proxy/stub CLSID.
- *
+ *
* RETURNS
* S_OK
* E_OUTOFMEMORY
@@ -2515,12 +2570,12 @@
static const WCHAR wszInterface[] =
{'I','n','t','e','r','f','a','c','e','\\',0};
static const WCHAR wszPSC[] =
{'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
- WCHAR value[CHARS_IN_GUID];
- LONG len;
- HKEY hkey;
APARTMENT *apt = COM_CurrentApt();
struct registered_psclsid *registered_psclsid;
ACTCTX_SECTION_KEYED_DATA data;
+ HRESULT hr;
+ REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY :
KEY_WOW64_64KEY;
+ BOOL is_wow64;
TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
@@ -2559,31 +2614,17 @@
StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
- /* Open the key.. */
- if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
- {
+ hr = get_ps_clsid_from_registry(path, 0, pclsid);
+ if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
+ (IsWow64Process(GetCurrentProcess(), &is_wow64) &&
is_wow64)))
+ hr = get_ps_clsid_from_registry(path, opposite, pclsid);
+
+ if (hr == S_OK)
+ TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
+ else
WARN("No PSFactoryBuffer object is registered for IID %s\n",
debugstr_guid(riid));
- return REGDB_E_IIDNOTREG;
- }
-
- /* ... Once we have the key, query the registry to get the
- value of CLSID as a string, and convert it into a
- proper CLSID structure to be passed back to the app */
- len = sizeof(value);
- if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
- {
- RegCloseKey(hkey);
- return REGDB_E_IIDNOTREG;
- }
- RegCloseKey(hkey);
-
- /* We have the CLSID we want back from the registry as a string, so
- let's convert it into a CLSID structure */
- if (CLSIDFromString(value, pclsid) != NOERROR)
- return REGDB_E_IIDNOTREG;
-
- TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
- return S_OK;
+
+ return hr;
}
/*****************************************************************************
@@ -2595,7 +2636,7 @@
* PARAMS
* riid [I] Interface whose proxy/stub CLSID is to be registered.
* rclsid [I] CLSID of the proxy/stub.
- *
+ *
* RETURNS
* Success: S_OK
* Failure: E_OUTOFMEMORY
@@ -3159,12 +3200,17 @@
HRESULT hres;
LPCLASSFACTORY lpclf = 0;
APARTMENT *apt;
+ CLSID clsid;
TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n",
debugstr_guid(rclsid),
pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
if (ppv==0)
return E_POINTER;
+
+ hres = CoGetTreatAsClass(rclsid, &clsid);
+ if(FAILED(hres))
+ clsid = *rclsid;
*ppv = 0;
@@ -3181,7 +3227,7 @@
/*
* The Standard Global Interface Table (GIT) object is a process-wide singleton.
*/
- if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
+ if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
{
IGlobalInterfaceTable *git = get_std_git();
hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
@@ -3191,13 +3237,13 @@
return S_OK;
}
- if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
+ if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent))
return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
/*
* Get a class factory to construct the object we want.
*/
- hres = CoGetClassObject(rclsid,
+ hres = CoGetClassObject(&clsid,
dwClsContext,
NULL,
&IID_IClassFactory,
@@ -3214,11 +3260,11 @@
if (FAILED(hres))
{
if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
- FIXME("Class %s does not support aggregation\n",
debugstr_guid(rclsid));
+ FIXME("Class %s does not support aggregation\n",
debugstr_guid(&clsid));
else
FIXME("no instance created for interface %s of class %s, hres is
0x%08x\n",
debugstr_guid(iid),
- debugstr_guid(rclsid),hres);
+ debugstr_guid(&clsid),hres);
}
return hres;
@@ -3321,7 +3367,7 @@
init_multi_qi(count, results);
- /* optionaly get CLSID from a file */
+ /* optionally get CLSID from a file */
if (!rclsid)
{
hr = GetClassFile(filename, &clsid);
@@ -3383,7 +3429,7 @@
init_multi_qi(count, results);
- /* optionaly get CLSID from a file */
+ /* optionally get CLSID from a file */
if (!rclsid)
{
memset(&stat.clsid, 0, sizeof(stat.clsid));
@@ -3577,14 +3623,14 @@
if (!apt) return CO_E_NOTINITIALIZED;
stubmgr = get_stub_manager_from_object(apt, pUnk);
-
+
if (stubmgr)
{
if (fLock)
stub_manager_ext_addref(stubmgr, 1, FALSE);
else
stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
-
+
stub_manager_int_release(stubmgr);
return S_OK;
@@ -3730,7 +3776,8 @@
res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
if (FAILED(res))
goto done;
- if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
+
+ if (IsEqualGUID( clsidOld, clsidNew ))
{
if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size)
&&
CLSIDFromString(auto_treat_as, &id) == S_OK)
@@ -3743,15 +3790,28 @@
}
else
{
- RegDeleteKeyW(hkey, wszTreatAs);
+ if(RegDeleteKeyW(hkey, wszTreatAs))
+ res = REGDB_E_WRITEREGDB;
goto done;
}
}
- else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
- !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
- {
- res = REGDB_E_WRITEREGDB;
- goto done;
+ else
+ {
+ if(IsEqualGUID(clsidNew, &CLSID_NULL)){
+ RegDeleteKeyW(hkey, wszTreatAs);
+ }else{
+ if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
+ WARN("StringFromGUID2 failed\n");
+ res = E_FAIL;
+ goto done;
+ }
+
+ if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) !=
ERROR_SUCCESS){
+ WARN("RegSetValue failed\n");
+ res = REGDB_E_WRITEREGDB;
+ goto done;
+ }
+ }
}
done:
@@ -4037,7 +4097,7 @@
FIXME("(%p, %p): stub\n", pUnk, pvReserved);
return S_OK;
}
-
+
/***********************************************************************
* CoQueryProxyBlanket [OLE32.@]
*
@@ -4987,13 +5047,19 @@
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
hProxyDll = hinstDLL;
+#ifdef __REACTOS__
COMPOBJ_InitProcess();
+#endif
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
release_std_git();
+#ifdef __REACTOS__
COMPOBJ_UninitProcess();
+#else
+ UnregisterClassW( wszAptWinClass, hProxyDll );
+#endif
RPC_UnregisterAllChannelHooks();
COMPOBJ_DllList_Free();
DeleteCriticalSection(&csRegisteredClassList);
Modified: trunk/reactos/dll/win32/ole32/filelockbytes.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/filelockby…
==============================================================================
--- trunk/reactos/dll/win32/ole32/filelockbytes.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/filelockbytes.c [iso-8859-1] Fri Oct 3 11:44:27 2014
@@ -29,7 +29,6 @@
{
ILockBytes ILockBytes_iface;
LONG ref;
- ULARGE_INTEGER filesize;
HANDLE hfile;
DWORD flProtect;
LPWSTR pwcsName;
@@ -88,8 +87,6 @@
This->ILockBytes_iface.lpVtbl = &FileLockBytesImpl_Vtbl;
This->ref = 1;
This->hfile = hFile;
- This->filesize.u.LowPart = GetFileSize(This->hfile,
- &This->filesize.u.HighPart);
This->flProtect = GetProtectMode(openFlags);
if(pwcsName) {
@@ -108,8 +105,6 @@
}
else
This->pwcsName = NULL;
-
- TRACE("file len %u\n", This->filesize.u.LowPart);
*pLockBytes = &This->ILockBytes_iface;
@@ -228,7 +223,6 @@
ULONG* pcbWritten) /* [out] */
{
FileLockBytesImpl* This = impl_from_ILockBytes(iface);
- ULONG size_needed = ulOffset.u.LowPart + cb;
ULONG bytes_left = cb;
const BYTE *writePtr = pv;
BOOL ret;
@@ -246,27 +240,19 @@
if (pcbWritten)
*pcbWritten = 0;
- if (size_needed > This->filesize.u.LowPart)
- {
- ULARGE_INTEGER newSize;
- newSize.u.HighPart = 0;
- newSize.u.LowPart = size_needed;
- ILockBytes_SetSize(iface, newSize);
- }
-
offset.QuadPart = ulOffset.QuadPart;
ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
if (!ret)
- return STG_E_READFAULT;
+ return STG_E_WRITEFAULT;
while (bytes_left)
{
ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
if (!ret)
- return STG_E_READFAULT;
+ return STG_E_WRITEFAULT;
if (pcbWritten)
*pcbWritten += cbWritten;
@@ -296,10 +282,7 @@
HRESULT hr = S_OK;
LARGE_INTEGER newpos;
- if (This->filesize.u.LowPart == newSize.u.LowPart)
- return hr;
-
- TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart);
+ TRACE("new size %u\n", newSize.u.LowPart);
newpos.QuadPart = newSize.QuadPart;
if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
@@ -307,22 +290,82 @@
SetEndOfFile(This->hfile);
}
- This->filesize = newSize;
return hr;
+}
+
+static HRESULT get_lock_error(void)
+{
+ switch (GetLastError())
+ {
+ case ERROR_LOCK_VIOLATION: return STG_E_LOCKVIOLATION; break;
+ case ERROR_ACCESS_DENIED: return STG_E_ACCESSDENIED; break;
+ case ERROR_NOT_SUPPORTED: return STG_E_INVALIDFUNCTION; break;
+ default:
+ FIXME("no mapping for error %d\n", GetLastError());
+ return STG_E_INVALIDFUNCTION;
+ }
}
static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
- FIXME("stub\n");
- return E_NOTIMPL;
+ FileLockBytesImpl* This = impl_from_ILockBytes(iface);
+ OVERLAPPED ol;
+ DWORD lock_flags = LOCKFILE_FAIL_IMMEDIATELY;
+
+ TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart,
dwLockType);
+
+ if (dwLockType & LOCK_WRITE)
+ return STG_E_INVALIDFUNCTION;
+
+ if (dwLockType & (LOCK_EXCLUSIVE|LOCK_ONLYONCE))
+ lock_flags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ ol.hEvent = 0;
+ ol.u.s.Offset = libOffset.u.LowPart;
+ ol.u.s.OffsetHigh = libOffset.u.HighPart;
+
+ if (LockFileEx(This->hfile, lock_flags, 0, cb.u.LowPart, cb.u.HighPart, &ol))
+ return S_OK;
+ return get_lock_error();
+}
+
+HRESULT FileLockBytesImpl_LockRegionSync(ILockBytes* iface,
+ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb)
+{
+ FileLockBytesImpl* This = impl_from_ILockBytes(iface);
+ OVERLAPPED ol;
+
+ if (iface->lpVtbl != &FileLockBytesImpl_Vtbl)
+ return E_NOTIMPL;
+
+ ol.hEvent = 0;
+ ol.u.s.Offset = libOffset.u.LowPart;
+ ol.u.s.OffsetHigh = libOffset.u.HighPart;
+
+ if (LockFileEx(This->hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, cb.u.LowPart,
cb.u.HighPart, &ol))
+ return S_OK;
+ return get_lock_error();
}
static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
- FIXME("stub\n");
- return E_NOTIMPL;
+ FileLockBytesImpl* This = impl_from_ILockBytes(iface);
+ OVERLAPPED ol;
+
+ TRACE("ofs %u count %u flags %x\n", libOffset.u.LowPart, cb.u.LowPart,
dwLockType);
+
+ if (dwLockType & LOCK_WRITE)
+ return STG_E_INVALIDFUNCTION;
+
+ ol.hEvent = 0;
+ ol.u.s.Offset = libOffset.u.LowPart;
+ ol.u.s.OffsetHigh = libOffset.u.HighPart;
+
+ if (UnlockFileEx(This->hfile, 0, cb.u.LowPart, cb.u.HighPart, &ol))
+ return S_OK;
+ return get_lock_error();
}
static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
@@ -341,7 +384,8 @@
pstatstg->pwcsName = NULL;
pstatstg->type = STGTY_LOCKBYTES;
- pstatstg->cbSize = This->filesize;
+
+ pstatstg->cbSize.u.LowPart = GetFileSize(This->hfile,
&pstatstg->cbSize.u.HighPart);
/* FIXME: If the implementation is exported, we'll need to set other fields. */
return S_OK;
Modified: trunk/reactos/dll/win32/ole32/filemoniker.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/filemonike…
==============================================================================
--- trunk/reactos/dll/win32/ole32/filemoniker.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/filemoniker.c [iso-8859-1] Fri Oct 3 11:44:27 2014
@@ -588,22 +588,11 @@
/* get the file name */
IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
- /* verify if the file contains a storage object */
- res=StgIsStorageFile(filePath);
-
- if(res==S_OK){
-
-
res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
-
- if (SUCCEEDED(res)){
-
- *ppvObject=pstg;
-
- IStorage_AddRef(pstg);
-
- return res;
- }
- }
+
res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
+
+ if (SUCCEEDED(res))
+ *ppvObject=pstg;
+
CoTaskMemFree(filePath);
}
else
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] Fri Oct 3 11:44:27 2014
@@ -2179,7 +2179,9 @@
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
{
- OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
+ TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
+ if (trackerInfo->trackingDone) break;
+ OLEDD_TrackStateChange(trackerInfo);
break;
}
case WM_DESTROY:
@@ -2843,6 +2845,8 @@
case VT_LPWSTR:
case VT_FILETIME:
case VT_BLOB:
+ case VT_DISPATCH:
+ case VT_UNKNOWN:
case VT_STREAM:
case VT_STORAGE:
case VT_STREAMED_OBJECT:
@@ -2919,6 +2923,8 @@
case VT_UINT:
case VT_FILETIME:
break;
+ case VT_DISPATCH:
+ case VT_UNKNOWN:
case VT_STREAM:
case VT_STREAMED_OBJECT:
case VT_STORAGE:
@@ -3032,6 +3038,8 @@
case VT_DATE:
case VT_FILETIME:
break;
+ case VT_DISPATCH:
+ case VT_UNKNOWN:
case VT_STREAM:
case VT_STREAMED_OBJECT:
case VT_STORAGE:
Modified: trunk/reactos/dll/win32/ole32/stg_stream.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/stg_stream…
==============================================================================
--- trunk/reactos/dll/win32/ole32/stg_stream.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/stg_stream.c [iso-8859-1] Fri Oct 3 11:44:27 2014
@@ -151,7 +151,7 @@
/*
* Advance the pointer for the number of positions read.
*/
- This->currentPosition.u.LowPart += *pcbRead;
+ This->currentPosition.QuadPart += *pcbRead;
}
TRACE("<-- %08x\n", res);
@@ -232,12 +232,12 @@
/*
* Advance the position pointer for the number of positions written.
*/
- This->currentPosition.u.LowPart += *pcbWritten;
+ This->currentPosition.QuadPart += *pcbWritten;
if (SUCCEEDED(res))
res = StorageBaseImpl_Flush(This->parentStorage);
- TRACE("<-- S_OK, written %u\n", *pcbWritten);
+ TRACE("<-- %08x, written %u\n", res, *pcbWritten);
return res;
}
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] Fri Oct 3 11:44:27 2014
@@ -83,6 +83,7 @@
/* Method definitions for the Storage32InternalImpl class. */
static StorageInternalImpl* StorageInternalImpl_Construct(StorageBaseImpl*
parentStorage,
DWORD openFlags, DirRef
storageDirEntry);
+static HRESULT StorageImpl_Refresh(StorageImpl *This, BOOL new_object, BOOL create);
static void StorageImpl_Destroy(StorageBaseImpl* iface);
static void StorageImpl_Invalidate(StorageBaseImpl* iface);
static HRESULT StorageImpl_Flush(StorageBaseImpl* iface);
@@ -91,8 +92,9 @@
static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG
nextBlock);
static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
static void StorageImpl_SaveFileHeader(StorageImpl* This);
-
-static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
+static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset,
ULARGE_INTEGER cb, DWORD dwLockType);
+
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex, ULONG
depotIndex);
static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
@@ -172,10 +174,31 @@
* Changes are committed to the transacted parent.
*/
StorageBaseImpl *transactedParent;
+
+ /* The transaction signature from when we last committed */
+ ULONG lastTransactionSig;
} TransactedSnapshotImpl;
+typedef struct TransactedSharedImpl
+{
+ struct StorageBaseImpl base;
+
+ /*
+ * Snapshot and uncommitted changes go here.
+ */
+ TransactedSnapshotImpl *scratch;
+
+ /*
+ * Changes are committed to the transacted parent.
+ */
+ StorageBaseImpl *transactedParent;
+
+ /* The transaction signature from when we last committed */
+ ULONG lastTransactionSig;
+} TransactedSharedImpl;
+
/* Generic function to create a transacted wrapper for a direct storage object. */
-static HRESULT Storage_ConstructTransacted(StorageBaseImpl* parent, StorageBaseImpl**
result);
+static HRESULT Storage_ConstructTransacted(StorageBaseImpl* parent, BOOL toplevel,
StorageBaseImpl** result);
/* OLESTREAM memory structure to use for Get and Put Routines */
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
@@ -311,9 +334,9 @@
** Block Functions
*/
-static ULONG StorageImpl_GetBigBlockOffset(StorageImpl* This, ULONG index)
-{
- return (index+1) * This->bigBlockSize;
+static ULONGLONG StorageImpl_GetBigBlockOffset(StorageImpl* This, ULONG index)
+{
+ return (ULONGLONG)(index+1) * This->bigBlockSize;
}
/************************************************************************
@@ -647,7 +670,7 @@
{
if (grfMode & STGM_TRANSACTED)
{
- res = Storage_ConstructTransacted(&newStorage->base,
&newTransactedStorage);
+ res = Storage_ConstructTransacted(&newStorage->base, FALSE,
&newTransactedStorage);
if (FAILED(res))
{
@@ -1280,8 +1303,7 @@
/*
* initialize the size used by the directory stream
*/
- newSize.u.HighPart = 0;
- newSize.u.LowPart = storage->bigBlockSize * blockCount;
+ newSize.QuadPart = (ULONGLONG)storage->bigBlockSize * blockCount;
/*
* add a block to the directory stream
@@ -2560,7 +2582,6 @@
if (FAILED(hr)) return hr;
/* Grow the stream if necessary */
- newSize.QuadPart = 0;
newSize.QuadPart = offset.QuadPart + size;
if (newSize.QuadPart > data.size.QuadPart)
@@ -2617,6 +2638,108 @@
hr = StorageImpl_WriteDirEntry(This, dst, &dst_data);
}
+
+ return hr;
+}
+
+static HRESULT StorageImpl_GetTransactionSig(StorageBaseImpl *base,
+ ULONG* result, BOOL refresh)
+{
+ StorageImpl *This = (StorageImpl*)base;
+ HRESULT hr=S_OK;
+ DWORD oldTransactionSig = This->transactionSig;
+
+ if (refresh)
+ {
+ ULARGE_INTEGER offset;
+ ULONG bytes_read;
+ BYTE data[4];
+
+ offset.u.HighPart = 0;
+ offset.u.LowPart = OFFSET_TRANSACTIONSIG;
+ hr = StorageImpl_ReadAt(This, offset, data, 4, &bytes_read);
+
+ if (SUCCEEDED(hr))
+ {
+ StorageUtl_ReadDWord(data, 0, &This->transactionSig);
+
+ if (oldTransactionSig != This->transactionSig)
+ {
+ /* Someone else wrote to this, so toss all cached information. */
+ TRACE("signature changed\n");
+
+ hr = StorageImpl_Refresh(This, FALSE, FALSE);
+ }
+
+ if (FAILED(hr))
+ This->transactionSig = oldTransactionSig;
+ }
+ }
+
+ *result = This->transactionSig;
+
+ return hr;
+}
+
+static HRESULT StorageImpl_SetTransactionSig(StorageBaseImpl *base,
+ ULONG value)
+{
+ StorageImpl *This = (StorageImpl*)base;
+
+ This->transactionSig = value;
+ StorageImpl_SaveFileHeader(This);
+
+ return S_OK;
+}
+
+static HRESULT StorageImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ StorageImpl *This = (StorageImpl*)base;
+ HRESULT hr;
+ ULARGE_INTEGER offset, cb;
+
+ if (write)
+ {
+ /* Synchronous grab of second priority range, the commit lock, and the
+ * lock-checking lock. */
+ offset.QuadPart = RANGELOCK_TRANSACTION_FIRST;
+ cb.QuadPart = RANGELOCK_TRANSACTION_LAST - RANGELOCK_TRANSACTION_FIRST + 1;
+ }
+ else
+ {
+ offset.QuadPart = RANGELOCK_COMMIT;
+ cb.QuadPart = 1;
+ }
+
+ hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE);
+
+ if (hr == STG_E_INVALIDFUNCTION)
+ hr = S_OK;
+
+ return hr;
+}
+
+static HRESULT StorageImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ StorageImpl *This = (StorageImpl*)base;
+ HRESULT hr;
+ ULARGE_INTEGER offset, cb;
+
+ if (write)
+ {
+ offset.QuadPart = RANGELOCK_TRANSACTION_FIRST;
+ cb.QuadPart = RANGELOCK_TRANSACTION_LAST - RANGELOCK_TRANSACTION_FIRST + 1;
+ }
+ else
+ {
+ offset.QuadPart = RANGELOCK_COMMIT;
+ cb.QuadPart = 1;
+ }
+
+ hr = ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
+
+ if (hr == STG_E_INVALIDFUNCTION)
+ hr = S_OK;
return hr;
}
@@ -2721,69 +2844,163 @@
StorageImpl_StreamReadAt,
StorageImpl_StreamWriteAt,
StorageImpl_StreamSetSize,
- StorageImpl_StreamLink
+ StorageImpl_StreamLink,
+ StorageImpl_GetTransactionSig,
+ StorageImpl_SetTransactionSig,
+ StorageImpl_LockTransaction,
+ StorageImpl_UnlockTransaction
};
-static HRESULT StorageImpl_Construct(
- HANDLE hFile,
- LPCOLESTR pwcsName,
- ILockBytes* pLkbyt,
- DWORD openFlags,
- BOOL fileBased,
- BOOL create,
- ULONG sector_size,
- StorageImpl** result)
-{
- StorageImpl* This;
- HRESULT hr = S_OK;
+static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset,
+ ULARGE_INTEGER cb, DWORD dwLockType)
+{
+ HRESULT hr;
+ int delay = 0;
+
+ /* if it's a FileLockBytesImpl use LockFileEx in blocking mode */
+ if (SUCCEEDED(FileLockBytesImpl_LockRegionSync(This->lockBytes, offset, cb)))
+ return S_OK;
+
+ /* otherwise we have to fake it based on an async lock */
+ do
+ {
+ hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, dwLockType);
+
+ if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
+ {
+ Sleep(delay);
+ if (delay < 150) delay++;
+ }
+ } while (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION);
+
+ return hr;
+}
+
+static HRESULT StorageImpl_CheckLockRange(StorageImpl *This, ULONG start,
+ ULONG end, HRESULT fail_hr)
+{
+ HRESULT hr;
+ ULARGE_INTEGER offset, cb;
+
+ offset.QuadPart = start;
+ cb.QuadPart = 1 + end - start;
+
+ hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
+ if (SUCCEEDED(hr)) ILockBytes_UnlockRegion(This->lockBytes, offset, cb,
LOCK_ONLYONCE);
+
+ if (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION)
+ return fail_hr;
+ else
+ return S_OK;
+}
+
+static HRESULT StorageImpl_LockOne(StorageImpl *This, ULONG start, ULONG end)
+{
+ HRESULT hr=S_OK;
+ int i, j;
+ ULARGE_INTEGER offset, cb;
+
+ cb.QuadPart = 1;
+
+ for (i=start; i<=end; i++)
+ {
+ offset.QuadPart = i;
+ hr = ILockBytes_LockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
+ if (hr != STG_E_ACCESSDENIED && hr != STG_E_LOCKVIOLATION)
+ break;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ for (j=0; j<sizeof(This->locked_bytes)/sizeof(This->locked_bytes[0]);
j++)
+ {
+ if (This->locked_bytes[j] == 0)
+ {
+ This->locked_bytes[j] = i;
+ break;
+ }
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT StorageImpl_GrabLocks(StorageImpl *This, DWORD openFlags)
+{
+ HRESULT hr;
+ ULARGE_INTEGER offset;
+ ULARGE_INTEGER cb;
+ DWORD share_mode = STGM_SHARE_MODE(openFlags);
+
+ if (openFlags & STGM_NOSNAPSHOT)
+ {
+ /* STGM_NOSNAPSHOT implies deny write */
+ if (share_mode == STGM_SHARE_DENY_READ) share_mode = STGM_SHARE_EXCLUSIVE;
+ else if (share_mode != STGM_SHARE_EXCLUSIVE) share_mode = STGM_SHARE_DENY_WRITE;
+ }
+
+ /* Wrap all other locking inside a single lock so we can check ranges safely */
+ offset.QuadPart = RANGELOCK_CHECKLOCKS;
+ cb.QuadPart = 1;
+ hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE);
+
+ /* If the ILockBytes doesn't support locking that's ok. */
+ if (FAILED(hr)) return S_OK;
+
+ hr = S_OK;
+
+ /* First check for any conflicting locks. */
+ if (SUCCEEDED(hr) && (openFlags & STGM_PRIORITY) == STGM_PRIORITY)
+ hr = StorageImpl_CheckLockRange(This, RANGELOCK_COMMIT, RANGELOCK_COMMIT,
STG_E_LOCKVIOLATION);
+
+ if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_WRITE))
+ hr = StorageImpl_CheckLockRange(This, RANGELOCK_DENY_READ_FIRST,
RANGELOCK_DENY_READ_LAST, STG_E_SHAREVIOLATION);
+
+ if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_READ))
+ hr = StorageImpl_CheckLockRange(This, RANGELOCK_DENY_WRITE_FIRST,
RANGELOCK_DENY_WRITE_LAST, STG_E_SHAREVIOLATION);
+
+ if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_READ || share_mode ==
STGM_SHARE_EXCLUSIVE))
+ hr = StorageImpl_CheckLockRange(This, RANGELOCK_READ_FIRST, RANGELOCK_READ_LAST,
STG_E_LOCKVIOLATION);
+
+ if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_WRITE || share_mode ==
STGM_SHARE_EXCLUSIVE))
+ hr = StorageImpl_CheckLockRange(This, RANGELOCK_WRITE_FIRST,
RANGELOCK_WRITE_LAST, STG_E_LOCKVIOLATION);
+
+ /* Then grab our locks. */
+ if (SUCCEEDED(hr) && (openFlags & STGM_PRIORITY) == STGM_PRIORITY)
+ {
+ hr = StorageImpl_LockOne(This, RANGELOCK_PRIORITY1_FIRST,
RANGELOCK_PRIORITY1_LAST);
+ if (SUCCEEDED(hr))
+ hr = StorageImpl_LockOne(This, RANGELOCK_PRIORITY2_FIRST,
RANGELOCK_PRIORITY2_LAST);
+ }
+
+ if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_WRITE))
+ hr = StorageImpl_LockOne(This, RANGELOCK_READ_FIRST, RANGELOCK_READ_LAST);
+
+ if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_READ))
+ hr = StorageImpl_LockOne(This, RANGELOCK_WRITE_FIRST, RANGELOCK_WRITE_LAST);
+
+ if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_READ || share_mode ==
STGM_SHARE_EXCLUSIVE))
+ hr = StorageImpl_LockOne(This, RANGELOCK_DENY_READ_FIRST,
RANGELOCK_DENY_READ_LAST);
+
+ if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_WRITE || share_mode ==
STGM_SHARE_EXCLUSIVE))
+ hr = StorageImpl_LockOne(This, RANGELOCK_DENY_WRITE_FIRST,
RANGELOCK_DENY_WRITE_LAST);
+
+ if (SUCCEEDED(hr) && (openFlags & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT)
+ hr = StorageImpl_LockOne(This, RANGELOCK_NOSNAPSHOT_FIRST,
RANGELOCK_NOSNAPSHOT_LAST);
+
+ offset.QuadPart = RANGELOCK_CHECKLOCKS;
+ cb.QuadPart = 1;
+ ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
+
+ return hr;
+}
+
+static HRESULT StorageImpl_Refresh(StorageImpl *This, BOOL new_object, BOOL create)
+{
+ HRESULT hr=S_OK;
DirEntry currentEntry;
DirRef currentEntryRef;
-
- if ( FAILED( validateSTGM(openFlags) ))
- return STG_E_INVALIDFLAG;
-
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
- if (!This)
- return E_OUTOFMEMORY;
-
- memset(This, 0, sizeof(StorageImpl));
-
- list_init(&This->base.strmHead);
-
- list_init(&This->base.storageHead);
-
- This->base.IStorage_iface.lpVtbl = &Storage32Impl_Vtbl;
- This->base.IPropertySetStorage_iface.lpVtbl = &IPropertySetStorage_Vtbl;
- This->base.IDirectWriterLock_iface.lpVtbl = &DirectWriterLockVtbl;
- This->base.baseVtbl = &StorageImpl_BaseVtbl;
- This->base.openFlags = (openFlags & ~STGM_CREATE);
- This->base.ref = 1;
- This->base.create = create;
-
- if (openFlags == (STGM_DIRECT_SWMR|STGM_READWRITE|STGM_SHARE_DENY_WRITE))
- This->base.lockingrole = SWMR_Writer;
- else if (openFlags == (STGM_DIRECT_SWMR|STGM_READ|STGM_SHARE_DENY_NONE))
- This->base.lockingrole = SWMR_Reader;
- else
- This->base.lockingrole = SWMR_None;
-
- This->base.reverted = FALSE;
-
- /*
- * Initialize the big block cache.
- */
- This->bigBlockSize = sector_size;
- This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
- if (hFile)
- hr = FileLockBytesImpl_Construct(hFile, openFlags, pwcsName,
&This->lockBytes);
- else
- {
- This->lockBytes = pLkbyt;
- ILockBytes_AddRef(pLkbyt);
- }
-
- if (FAILED(hr))
- goto end;
+ BlockChainStream *blockChainStream;
if (create)
{
@@ -2809,7 +3026,7 @@
This->rootStartBlock = 1;
This->smallBlockLimit = LIMIT_TO_USE_SMALL_BLOCK;
This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
- if (sector_size == 4096)
+ if (This->bigBlockSize == 4096)
This->bigBlockSizeBits = MAX_BIG_BLOCK_SIZE_BITS;
else
This->bigBlockSizeBits = MIN_BIG_BLOCK_SIZE_BITS;
@@ -2843,7 +3060,7 @@
if (FAILED(hr))
{
- goto end;
+ return hr;
}
}
@@ -2870,8 +3087,7 @@
This->extBigBlockDepotLocations = HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) *
cache_size);
if (!This->extBigBlockDepotLocations)
{
- hr = E_OUTOFMEMORY;
- goto end;
+ return E_OUTOFMEMORY;
}
This->extBigBlockDepotLocationsSize = cache_size;
@@ -2881,8 +3097,7 @@
if (current_block == BLOCK_END_OF_CHAIN)
{
WARN("File has too few extended big block depot blocks.\n");
- hr = STG_E_DOCFILECORRUPT;
- goto end;
+ return STG_E_DOCFILECORRUPT;
}
This->extBigBlockDepotLocations[i] = current_block;
current_block = Storage32Impl_GetNextExtendedBlock(This, current_block);
@@ -2897,20 +3112,24 @@
/*
* Create the block chain abstractions.
*/
- if(!(This->rootBlockChain =
+ if(!(blockChainStream =
BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL)))
{
- hr = STG_E_READFAULT;
- goto end;
- }
-
- if(!(This->smallBlockDepotChain =
+ return STG_E_READFAULT;
+ }
+ if (!new_object)
+ BlockChainStream_Destroy(This->rootBlockChain);
+ This->rootBlockChain = blockChainStream;
+
+ if(!(blockChainStream =
BlockChainStream_Construct(This, &This->smallBlockDepotStart,
DIRENTRY_NULL)))
{
- hr = STG_E_READFAULT;
- goto end;
- }
+ return STG_E_READFAULT;
+ }
+ if (!new_object)
+ BlockChainStream_Destroy(This->smallBlockDepotChain);
+ This->smallBlockDepotChain = blockChainStream;
/*
* Write the root storage entry (memory only)
@@ -2963,20 +3182,96 @@
if (FAILED(hr))
{
- hr = STG_E_READFAULT;
- goto end;
+ return STG_E_READFAULT;
}
/*
* Create the block chain abstraction for the small block root chain.
*/
- if(!(This->smallBlockRootChain =
+ if(!(blockChainStream =
BlockChainStream_Construct(This, NULL, This->base.storageDirEntry)))
{
- hr = STG_E_READFAULT;
- }
-
-end:
+ return STG_E_READFAULT;
+ }
+ if (!new_object)
+ BlockChainStream_Destroy(This->smallBlockRootChain);
+ This->smallBlockRootChain = blockChainStream;
+
+ if (!new_object)
+ {
+ int i;
+ for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
+ {
+ BlockChainStream_Destroy(This->blockChainCache[i]);
+ This->blockChainCache[i] = NULL;
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT StorageImpl_Construct(
+ HANDLE hFile,
+ LPCOLESTR pwcsName,
+ ILockBytes* pLkbyt,
+ DWORD openFlags,
+ BOOL fileBased,
+ BOOL create,
+ ULONG sector_size,
+ StorageImpl** result)
+{
+ StorageImpl* This;
+ HRESULT hr = S_OK;
+
+ if ( FAILED( validateSTGM(openFlags) ))
+ return STG_E_INVALIDFLAG;
+
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+ if (!This)
+ return E_OUTOFMEMORY;
+
+ memset(This, 0, sizeof(StorageImpl));
+
+ list_init(&This->base.strmHead);
+
+ list_init(&This->base.storageHead);
+
+ This->base.IStorage_iface.lpVtbl = &Storage32Impl_Vtbl;
+ This->base.IPropertySetStorage_iface.lpVtbl = &IPropertySetStorage_Vtbl;
+ This->base.IDirectWriterLock_iface.lpVtbl = &DirectWriterLockVtbl;
+ This->base.baseVtbl = &StorageImpl_BaseVtbl;
+ This->base.openFlags = (openFlags & ~STGM_CREATE);
+ This->base.ref = 1;
+ This->base.create = create;
+
+ if (openFlags == (STGM_DIRECT_SWMR|STGM_READWRITE|STGM_SHARE_DENY_WRITE))
+ This->base.lockingrole = SWMR_Writer;
+ else if (openFlags == (STGM_DIRECT_SWMR|STGM_READ|STGM_SHARE_DENY_NONE))
+ This->base.lockingrole = SWMR_Reader;
+ else
+ This->base.lockingrole = SWMR_None;
+
+ This->base.reverted = FALSE;
+
+ /*
+ * Initialize the big block cache.
+ */
+ This->bigBlockSize = sector_size;
+ This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
+ if (hFile)
+ hr = FileLockBytesImpl_Construct(hFile, openFlags, pwcsName,
&This->lockBytes);
+ else
+ {
+ This->lockBytes = pLkbyt;
+ ILockBytes_AddRef(pLkbyt);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = StorageImpl_GrabLocks(This, openFlags);
+
+ if (SUCCEEDED(hr))
+ hr = StorageImpl_Refresh(This, TRUE, create);
+
if (FAILED(hr))
{
IStorage_Release(&This->base.IStorage_iface);
@@ -3018,6 +3313,17 @@
for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
BlockChainStream_Destroy(This->blockChainCache[i]);
+
+ for (i=0; i<sizeof(This->locked_bytes)/sizeof(This->locked_bytes[0]); i++)
+ {
+ ULARGE_INTEGER offset, cb;
+ cb.QuadPart = 1;
+ if (This->locked_bytes[i] != 0)
+ {
+ offset.QuadPart = This->locked_bytes[i];
+ ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
+ }
+ }
if (This->lockBytes)
ILockBytes_Release(This->lockBytes);
@@ -3092,7 +3398,7 @@
/*
* Add a block depot.
*/
- Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+ Storage32Impl_AddBlockDepot(This, depotBlockIndexPos, depotIndex);
This->bigBlockDepotCount++;
This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
@@ -3135,7 +3441,7 @@
/*
* Add a block depot and mark it in the extended block.
*/
- Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+ Storage32Impl_AddBlockDepot(This, depotBlockIndexPos, depotIndex);
This->bigBlockDepotCount++;
Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
@@ -3200,14 +3506,24 @@
* This will create a depot block, essentially it is a block initialized
* to BLOCK_UNUSEDs.
*/
-static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex, ULONG
depotIndex)
{
BYTE blockBuffer[MAX_BIG_BLOCK_SIZE];
+ ULONG rangeLockIndex = RANGELOCK_FIRST / This->bigBlockSize - 1;
+ ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
+ ULONG rangeLockDepot = rangeLockIndex / blocksPerDepot;
/*
* Initialize blocks as free
*/
memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+
+ /* Reserve the range lock sector */
+ if (depotIndex == rangeLockDepot)
+ {
+ ((ULONG*)blockBuffer)[rangeLockIndex % blocksPerDepot] = BLOCK_END_OF_CHAIN;
+ }
+
StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
}
@@ -3504,6 +3820,13 @@
assert(depotBlockCount < This->bigBlockDepotCount);
assert(blockIndex != nextBlock);
+ if (blockIndex == (RANGELOCK_FIRST / This->bigBlockSize) - 1)
+ /* This should never happen (storage file format spec forbids it), but
+ * older versions of Wine may have generated broken files. We don't want to
+ * assert and potentially lose data, but we do want to know if this ever
+ * happens in a newly-created file. */
+ ERR("Using range lock page\n");
+
if (depotBlockCount < COUNT_BBDEPOTINHEADER)
{
depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
@@ -3592,6 +3915,11 @@
StorageUtl_ReadDWord(
headerBigBlock,
+ OFFSET_TRANSACTIONSIG,
+ &This->transactionSig);
+
+ StorageUtl_ReadDWord(
+ headerBigBlock,
OFFSET_SMALLBLOCKLIMIT,
&This->smallBlockLimit);
@@ -3750,6 +4078,11 @@
StorageUtl_WriteDWord(
headerBigBlock,
+ OFFSET_TRANSACTIONSIG,
+ This->transactionSig);
+
+ StorageUtl_WriteDWord(
+ headerBigBlock,
OFFSET_SMALLBLOCKLIMIT,
This->smallBlockLimit);
@@ -3801,8 +4134,7 @@
HRESULT hr;
ULONG bytesRead;
- offset.u.HighPart = 0;
- offset.u.LowPart = index * RAW_DIRENTRY_SIZE;
+ offset.QuadPart = (ULONGLONG)index * RAW_DIRENTRY_SIZE;
hr = BlockChainStream_ReadAt(
This->rootBlockChain,
@@ -3829,8 +4161,7 @@
ULARGE_INTEGER offset;
ULONG bytesRead;
- offset.u.HighPart = 0;
- offset.u.LowPart = index * RAW_DIRENTRY_SIZE;
+ offset.QuadPart = (ULONGLONG)index * RAW_DIRENTRY_SIZE;
return BlockChainStream_WriteAt(
This->rootBlockChain,
@@ -3912,6 +4243,11 @@
buffer,
OFFSET_PS_SIZE,
newData->size.u.LowPart);
+
+ StorageUtl_WriteDWord(
+ buffer,
+ OFFSET_PS_SIZE_HIGH,
+ newData->size.u.HighPart);
}
/******************************************************************************
@@ -3995,7 +4331,10 @@
OFFSET_PS_SIZE,
&buffer->size.u.LowPart);
- buffer->size.u.HighPart = 0;
+ StorageUtl_ReadDWord(
+ currentEntry,
+ OFFSET_PS_SIZE_HIGH,
+ &buffer->size.u.HighPart);
}
return readRes;
@@ -4026,8 +4365,7 @@
DWORD read=0;
HRESULT hr;
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
hr = StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
@@ -4052,9 +4390,8 @@
DWORD read;
DWORD tmp;
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
- ulOffset.u.LowPart += offset;
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
+ ulOffset.QuadPart += offset;
StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
*value = lendian32toh(tmp);
@@ -4069,8 +4406,7 @@
ULARGE_INTEGER ulOffset;
DWORD wrote;
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
return (wrote == This->bigBlockSize);
@@ -4085,9 +4421,8 @@
ULARGE_INTEGER ulOffset;
DWORD wrote;
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
- ulOffset.u.LowPart += offset;
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
+ ulOffset.QuadPart += offset;
value = htole32(value);
StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
@@ -4342,6 +4677,106 @@
return hr;
}
+static HRESULT StorageBaseImpl_DupStorageTree(
+ StorageBaseImpl *dst, DirRef *dst_entry,
+ StorageBaseImpl *src, DirRef src_entry)
+{
+ HRESULT hr;
+ DirEntry data;
+ BOOL has_stream=FALSE;
+
+ if (src_entry == DIRENTRY_NULL)
+ {
+ *dst_entry = DIRENTRY_NULL;
+ return S_OK;
+ }
+
+ hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &data);
+ if (SUCCEEDED(hr))
+ {
+ has_stream = (data.stgType == STGTY_STREAM && data.size.QuadPart != 0);
+ data.startingBlock = BLOCK_END_OF_CHAIN;
+ data.size.QuadPart = 0;
+
+ hr = StorageBaseImpl_DupStorageTree(dst, &data.leftChild, src, data.leftChild);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_DupStorageTree(dst, &data.rightChild, src,
data.rightChild);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_DupStorageTree(dst, &data.dirRootEntry, src,
data.dirRootEntry);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_CreateDirEntry(dst, &data, dst_entry);
+
+ if (SUCCEEDED(hr) && has_stream)
+ hr = StorageBaseImpl_CopyStream(dst, *dst_entry, src, src_entry);
+
+ return hr;
+}
+
+static HRESULT StorageBaseImpl_CopyStorageTree(
+ StorageBaseImpl *dst, DirRef dst_entry,
+ StorageBaseImpl *src, DirRef src_entry)
+{
+ HRESULT hr;
+ DirEntry src_data, dst_data;
+ DirRef new_root_entry;
+
+ hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &src_data);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StorageBaseImpl_DupStorageTree(dst, &new_root_entry, src,
src_data.dirRootEntry);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StorageBaseImpl_ReadDirEntry(dst, dst_entry, &dst_data);
+ dst_data.clsid = src_data.clsid;
+ dst_data.ctime = src_data.ctime;
+ dst_data.mtime = src_data.mtime;
+ dst_data.dirRootEntry = new_root_entry;
+ }
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_WriteDirEntry(dst, dst_entry, &dst_data);
+
+ return hr;
+}
+
+static HRESULT StorageBaseImpl_DeleteStorageTree(StorageBaseImpl *This, DirRef entry,
BOOL include_siblings)
+{
+ HRESULT hr;
+ DirEntry data;
+ ULARGE_INTEGER zero;
+
+ if (entry == DIRENTRY_NULL)
+ return S_OK;
+
+ zero.QuadPart = 0;
+
+ hr = StorageBaseImpl_ReadDirEntry(This, entry, &data);
+
+ if (SUCCEEDED(hr) && include_siblings)
+ hr = StorageBaseImpl_DeleteStorageTree(This, data.leftChild, TRUE);
+
+ if (SUCCEEDED(hr) && include_siblings)
+ hr = StorageBaseImpl_DeleteStorageTree(This, data.rightChild, TRUE);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_DeleteStorageTree(This, data.dirRootEntry, TRUE);
+
+ if (SUCCEEDED(hr) && data.stgType == STGTY_STREAM)
+ hr = StorageBaseImpl_StreamSetSize(This, entry, zero);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_DestroyDirEntry(This, entry);
+
+ return hr;
+}
+
static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
{
DirRef result=This->firstFreeEntry;
@@ -4696,6 +5131,7 @@
DirEntry data;
ULARGE_INTEGER zero;
HRESULT hr;
+ ULONG transactionSig;
zero.QuadPart = 0;
@@ -4705,89 +5141,116 @@
if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
return STG_E_ACCESSDENIED;
- /* To prevent data loss, we create the new structure in the file before we
- * delete the old one, so that in case of errors the old data is intact. We
- * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
- * needed in the rare situation where we have just enough free disk space to
- * overwrite the existing data. */
-
- root_entry = &This->entries[This->base.storageDirEntry];
-
- if (!root_entry->read)
- return S_OK;
-
- hr = TransactedSnapshotImpl_CopyTree(This);
- if (FAILED(hr)) return hr;
-
- if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
- dir_root_ref = DIRENTRY_NULL;
- else
- dir_root_ref =
This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
-
- hr = StorageBaseImpl_Flush(This->transactedParent);
-
- /* Update the storage to use the new data in one step. */
+ hr = StorageBaseImpl_LockTransaction(This->transactedParent, TRUE);
+ if (hr == E_NOTIMPL) hr = S_OK;
if (SUCCEEDED(hr))
- hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
- root_entry->transactedParentEntry, &data);
-
- if (SUCCEEDED(hr))
- {
- 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);
- }
-
- /* Try to flush after updating the root storage, but if the flush fails, keep
- * going, on the theory that it'll either succeed later or the subsequent
- * writes will fail. */
- StorageBaseImpl_Flush(This->transactedParent);
-
- if (SUCCEEDED(hr))
- {
- /* Destroy the old now-orphaned data. */
- for (i=0; i<This->entries_size; i++)
- {
- TransactedDirEntry *entry = &This->entries[i];
- if (entry->inuse)
+ {
+ hr = StorageBaseImpl_GetTransactionSig(This->transactedParent,
&transactionSig, TRUE);
+ if (SUCCEEDED(hr))
+ {
+ if (transactionSig != This->lastTransactionSig)
{
- if (entry->deleted)
+ ERR("file was externally modified\n");
+ hr = STG_E_NOTCURRENT;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ This->lastTransactionSig = transactionSig+1;
+ hr = StorageBaseImpl_SetTransactionSig(This->transactedParent,
This->lastTransactionSig);
+ }
+ }
+ else if (hr == E_NOTIMPL)
+ hr = S_OK;
+
+ if (FAILED(hr)) goto end;
+
+ /* To prevent data loss, we create the new structure in the file before we
+ * delete the old one, so that in case of errors the old data is intact. We
+ * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
+ * needed in the rare situation where we have just enough free disk space to
+ * overwrite the existing data. */
+
+ root_entry = &This->entries[This->base.storageDirEntry];
+
+ if (!root_entry->read)
+ goto end;
+
+ hr = TransactedSnapshotImpl_CopyTree(This);
+ if (FAILED(hr)) goto end;
+
+ if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
+ dir_root_ref = DIRENTRY_NULL;
+ else
+ dir_root_ref =
This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
+
+ hr = StorageBaseImpl_Flush(This->transactedParent);
+
+ /* Update the storage to use the new data in one step. */
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
+ root_entry->transactedParentEntry, &data);
+
+ if (SUCCEEDED(hr))
+ {
+ 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);
+ }
+
+ /* Try to flush after updating the root storage, but if the flush fails, keep
+ * going, on the theory that it'll either succeed later or the subsequent
+ * writes will fail. */
+ StorageBaseImpl_Flush(This->transactedParent);
+
+ if (SUCCEEDED(hr))
+ {
+ /* Destroy the old now-orphaned data. */
+ for (i=0; i<This->entries_size; i++)
+ {
+ TransactedDirEntry *entry = &This->entries[i];
+ if (entry->inuse)
{
- 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)
+ if (entry->deleted)
+ {
+ StorageBaseImpl_StreamSetSize(This->transactedParent,
+ entry->transactedParentEntry, zero);
StorageBaseImpl_DestroyDirEntry(This->transactedParent,
entry->transactedParentEntry);
- if (entry->stream_dirty)
+ memset(entry, 0, sizeof(TransactedDirEntry));
+ This->firstFreeEntry = min(i, This->firstFreeEntry);
+ }
+ else if (entry->read && entry->transactedParentEntry !=
entry->newTransactedParentEntry)
{
- StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry,
zero);
- StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
- entry->stream_dirty = FALSE;
+ 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 = FALSE;
+ }
+ entry->dirty = FALSE;
+ entry->transactedParentEntry = entry->newTransactedParentEntry;
}
- entry->dirty = FALSE;
- entry->transactedParentEntry = entry->newTransactedParentEntry;
}
}
}
- }
- else
- {
- TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
- }
-
- if (SUCCEEDED(hr))
- hr = StorageBaseImpl_Flush(This->transactedParent);
+ else
+ {
+ TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_Flush(This->transactedParent);
+end:
+ StorageBaseImpl_UnlockTransaction(This->transactedParent, TRUE);
+ }
return hr;
}
@@ -5080,6 +5543,28 @@
dst_entry->data.size = src_entry->data.size;
return S_OK;
+}
+
+static HRESULT TransactedSnapshotImpl_GetTransactionSig(StorageBaseImpl *base,
+ ULONG* result, BOOL refresh)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSnapshotImpl_SetTransactionSig(StorageBaseImpl *base,
+ ULONG value)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSnapshotImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSnapshotImpl_UnlockTransaction(StorageBaseImpl *base, BOOL
write)
+{
+ return E_NOTIMPL;
}
static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
@@ -5117,7 +5602,11 @@
TransactedSnapshotImpl_StreamReadAt,
TransactedSnapshotImpl_StreamWriteAt,
TransactedSnapshotImpl_StreamSetSize,
- TransactedSnapshotImpl_StreamLink
+ TransactedSnapshotImpl_StreamLink,
+ TransactedSnapshotImpl_GetTransactionSig,
+ TransactedSnapshotImpl_SetTransactionSig,
+ TransactedSnapshotImpl_LockTransaction,
+ TransactedSnapshotImpl_UnlockTransaction
};
static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
@@ -5143,6 +5632,9 @@
(*result)->base.ref = 1;
(*result)->base.openFlags = parentStorage->openFlags;
+
+ /* This cannot fail, except with E_NOTIMPL in which case we don't care */
+ StorageBaseImpl_GetTransactionSig(parentStorage,
&(*result)->lastTransactionSig, FALSE);
/* Create a new temporary storage to act as the scratch file. */
hr = StgCreateDocfile(NULL,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_DELETEONRELEASE,
@@ -5182,14 +5674,360 @@
return E_OUTOFMEMORY;
}
+static void TransactedSharedImpl_Invalidate(StorageBaseImpl* This)
+{
+ if (!This->reverted)
+ {
+ TRACE("Storage invalidated (stg=%p)\n", This);
+
+ This->reverted = TRUE;
+
+ StorageBaseImpl_DeleteAll(This);
+ }
+}
+
+static void TransactedSharedImpl_Destroy( StorageBaseImpl *iface)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) iface;
+
+ TransactedSharedImpl_Invalidate(&This->base);
+ IStorage_Release(&This->transactedParent->IStorage_iface);
+ IStorage_Release(&This->scratch->base.IStorage_iface);
+ HeapFree(GetProcessHeap(), 0, This);
+}
+
+static HRESULT TransactedSharedImpl_Flush(StorageBaseImpl* iface)
+{
+ /* We only need to flush when committing. */
+ return S_OK;
+}
+
+static HRESULT TransactedSharedImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) iface;
+
+ return StorageBaseImpl_GetFilename(This->transactedParent, result);
+}
+
+static HRESULT TransactedSharedImpl_CreateDirEntry(StorageBaseImpl *base,
+ const DirEntry *newData, DirRef *index)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_CreateDirEntry(&This->scratch->base,
+ newData, index);
+}
+
+static HRESULT TransactedSharedImpl_WriteDirEntry(StorageBaseImpl *base,
+ DirRef index, const DirEntry *data)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_WriteDirEntry(&This->scratch->base,
+ index, data);
+}
+
+static HRESULT TransactedSharedImpl_ReadDirEntry(StorageBaseImpl *base,
+ DirRef index, DirEntry *data)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_ReadDirEntry(&This->scratch->base,
+ index, data);
+}
+
+static HRESULT TransactedSharedImpl_DestroyDirEntry(StorageBaseImpl *base,
+ DirRef index)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_DestroyDirEntry(&This->scratch->base,
+ index);
+}
+
+static HRESULT TransactedSharedImpl_StreamReadAt(StorageBaseImpl *base,
+ DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_StreamReadAt(&This->scratch->base,
+ index, offset, size, buffer, bytesRead);
+}
+
+static HRESULT TransactedSharedImpl_StreamWriteAt(StorageBaseImpl *base,
+ DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG
*bytesWritten)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_StreamWriteAt(&This->scratch->base,
+ index, offset, size, buffer, bytesWritten);
+}
+
+static HRESULT TransactedSharedImpl_StreamSetSize(StorageBaseImpl *base,
+ DirRef index, ULARGE_INTEGER newsize)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_StreamSetSize(&This->scratch->base,
+ index, newsize);
+}
+
+static HRESULT TransactedSharedImpl_StreamLink(StorageBaseImpl *base,
+ DirRef dst, DirRef src)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*) base;
+
+ return StorageBaseImpl_StreamLink(&This->scratch->base,
+ dst, src);
+}
+
+static HRESULT TransactedSharedImpl_GetTransactionSig(StorageBaseImpl *base,
+ ULONG* result, BOOL refresh)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSharedImpl_SetTransactionSig(StorageBaseImpl *base,
+ ULONG value)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSharedImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT TransactedSharedImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TransactedSharedImpl_Commit(
+ IStorage* iface,
+ DWORD grfCommitFlags) /* [in] */
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*)impl_from_IStorage(iface);
+ DirRef new_storage_ref, prev_storage_ref;
+ DirEntry src_data, dst_data;
+ HRESULT hr;
+ ULONG transactionSig;
+
+ TRACE("(%p,%x)\n", iface, grfCommitFlags);
+
+ /* Cannot commit a read-only transacted storage */
+ if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
+ return STG_E_ACCESSDENIED;
+
+ hr = StorageBaseImpl_LockTransaction(This->transactedParent, TRUE);
+ if (hr == E_NOTIMPL) hr = S_OK;
+ if (SUCCEEDED(hr))
+ {
+ hr = StorageBaseImpl_GetTransactionSig(This->transactedParent,
&transactionSig, TRUE);
+ if (SUCCEEDED(hr))
+ {
+ if ((grfCommitFlags & STGC_ONLYIFCURRENT) && transactionSig !=
This->lastTransactionSig)
+ hr = STG_E_NOTCURRENT;
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_SetTransactionSig(This->transactedParent,
transactionSig+1);
+ }
+ else if (hr == E_NOTIMPL)
+ hr = S_OK;
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_ReadDirEntry(&This->scratch->base,
This->scratch->base.storageDirEntry, &src_data);
+
+ /* FIXME: If we're current, we should be able to copy only the changes in
scratch. */
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_DupStorageTree(This->transactedParent,
&new_storage_ref, &This->scratch->base, src_data.dirRootEntry);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_Flush(This->transactedParent);
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
This->transactedParent->storageDirEntry, &dst_data);
+
+ if (SUCCEEDED(hr))
+ {
+ prev_storage_ref = dst_data.dirRootEntry;
+ dst_data.dirRootEntry = new_storage_ref;
+ dst_data.clsid = src_data.clsid;
+ dst_data.ctime = src_data.ctime;
+ dst_data.mtime = src_data.mtime;
+ hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
This->transactedParent->storageDirEntry, &dst_data);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ /* Try to flush after updating the root storage, but if the flush fails, keep
+ * going, on the theory that it'll either succeed later or the subsequent
+ * writes will fail. */
+ StorageBaseImpl_Flush(This->transactedParent);
+
+ hr = StorageBaseImpl_DeleteStorageTree(This->transactedParent, prev_storage_ref,
TRUE);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = StorageBaseImpl_Flush(This->transactedParent);
+
+ StorageBaseImpl_UnlockTransaction(This->transactedParent, TRUE);
+
+ if (SUCCEEDED(hr))
+ hr = IStorage_Commit(&This->scratch->base.IStorage_iface, STGC_DEFAULT);
+
+ if (SUCCEEDED(hr))
+ {
+ This->lastTransactionSig = transactionSig+1;
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI TransactedSharedImpl_Revert(
+ IStorage* iface)
+{
+ TransactedSharedImpl* This = (TransactedSharedImpl*)impl_from_IStorage(iface);
+
+ TRACE("(%p)\n", iface);
+
+ /* Destroy the open objects. */
+ StorageBaseImpl_DeleteAll(&This->base);
+
+ return IStorage_Revert(&This->scratch->base.IStorage_iface);
+}
+
+static const IStorageVtbl TransactedSharedImpl_Vtbl =
+{
+ StorageBaseImpl_QueryInterface,
+ StorageBaseImpl_AddRef,
+ StorageBaseImpl_Release,
+ StorageBaseImpl_CreateStream,
+ StorageBaseImpl_OpenStream,
+ StorageBaseImpl_CreateStorage,
+ StorageBaseImpl_OpenStorage,
+ StorageBaseImpl_CopyTo,
+ StorageBaseImpl_MoveElementTo,
+ TransactedSharedImpl_Commit,
+ TransactedSharedImpl_Revert,
+ StorageBaseImpl_EnumElements,
+ StorageBaseImpl_DestroyElement,
+ StorageBaseImpl_RenameElement,
+ StorageBaseImpl_SetElementTimes,
+ StorageBaseImpl_SetClass,
+ StorageBaseImpl_SetStateBits,
+ StorageBaseImpl_Stat
+};
+
+static const StorageBaseImplVtbl TransactedSharedImpl_BaseVtbl =
+{
+ TransactedSharedImpl_Destroy,
+ TransactedSharedImpl_Invalidate,
+ TransactedSharedImpl_Flush,
+ TransactedSharedImpl_GetFilename,
+ TransactedSharedImpl_CreateDirEntry,
+ TransactedSharedImpl_WriteDirEntry,
+ TransactedSharedImpl_ReadDirEntry,
+ TransactedSharedImpl_DestroyDirEntry,
+ TransactedSharedImpl_StreamReadAt,
+ TransactedSharedImpl_StreamWriteAt,
+ TransactedSharedImpl_StreamSetSize,
+ TransactedSharedImpl_StreamLink,
+ TransactedSharedImpl_GetTransactionSig,
+ TransactedSharedImpl_SetTransactionSig,
+ TransactedSharedImpl_LockTransaction,
+ TransactedSharedImpl_UnlockTransaction
+};
+
+static HRESULT TransactedSharedImpl_Construct(StorageBaseImpl *parentStorage,
+ TransactedSharedImpl** result)
+{
+ HRESULT hr;
+
+ *result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedSharedImpl));
+ if (*result)
+ {
+ IStorage *scratch;
+
+ (*result)->base.IStorage_iface.lpVtbl = &TransactedSharedImpl_Vtbl;
+
+ /* This is OK because the property set storage functions use the IStorage functions.
*/
+ (*result)->base.IPropertySetStorage_iface.lpVtbl =
parentStorage->IPropertySetStorage_iface.lpVtbl;
+ (*result)->base.baseVtbl = &TransactedSharedImpl_BaseVtbl;
+
+ list_init(&(*result)->base.strmHead);
+
+ list_init(&(*result)->base.storageHead);
+
+ (*result)->base.ref = 1;
+
+ (*result)->base.openFlags = parentStorage->openFlags;
+
+ hr = StorageBaseImpl_LockTransaction(parentStorage, FALSE);
+
+ if (SUCCEEDED(hr))
+ {
+ STGOPTIONS stgo;
+
+ /* This cannot fail, except with E_NOTIMPL in which case we don't care */
+ StorageBaseImpl_GetTransactionSig(parentStorage,
&(*result)->lastTransactionSig, FALSE);
+
+ stgo.usVersion = 1;
+ stgo.reserved = 0;
+ stgo.ulSectorSize = 4096;
+ stgo.pwcsTemplateFile = NULL;
+
+ /* Create a new temporary storage to act as the scratch file. */
+ hr = StgCreateStorageEx(NULL,
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_DELETEONRELEASE|STGM_TRANSACTED,
+ STGFMT_DOCFILE, 0, &stgo, NULL, &IID_IStorage, (void**)&scratch);
+ (*result)->scratch = (TransactedSnapshotImpl*)impl_from_IStorage(scratch);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StorageBaseImpl_CopyStorageTree(&(*result)->scratch->base,
(*result)->scratch->base.storageDirEntry,
+ parentStorage, parentStorage->storageDirEntry);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IStorage_Commit(scratch, STGC_DEFAULT);
+
+ (*result)->base.storageDirEntry =
(*result)->scratch->base.storageDirEntry;
+ (*result)->transactedParent = parentStorage;
+ }
+
+ if (FAILED(hr))
+ IStorage_Release(scratch);
+ }
+
+ StorageBaseImpl_UnlockTransaction(parentStorage, FALSE);
+ }
+
+ if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, *result);
+
+ return hr;
+ }
+ else
+ return E_OUTOFMEMORY;
+}
+
static HRESULT Storage_ConstructTransacted(StorageBaseImpl *parentStorage,
- StorageBaseImpl** result)
-{
- static int fixme=0;
-
- if (parentStorage->openFlags & (STGM_NOSCRATCH|STGM_NOSNAPSHOT) &&
!fixme++)
- {
+ BOOL toplevel, StorageBaseImpl** result)
+{
+ static int fixme_flags=STGM_NOSCRATCH|STGM_NOSNAPSHOT;
+
+ if (parentStorage->openFlags & fixme_flags)
+ {
+ fixme_flags &= ~parentStorage->openFlags;
FIXME("Unimplemented flags %x\n", parentStorage->openFlags);
+ }
+
+ if (toplevel && !(parentStorage->openFlags & STGM_NOSNAPSHOT)
&&
+ STGM_SHARE_MODE(parentStorage->openFlags) != STGM_SHARE_DENY_WRITE &&
+ STGM_SHARE_MODE(parentStorage->openFlags) != STGM_SHARE_EXCLUSIVE)
+ {
+ /* Need to create a temp file for the snapshot */
+ return TransactedSharedImpl_Construct(parentStorage,
(TransactedSharedImpl**)result);
}
return TransactedSnapshotImpl_Construct(parentStorage,
@@ -5215,7 +6053,7 @@
if (openFlags & STGM_TRANSACTED)
{
- hr = Storage_ConstructTransacted(&newStorage->base,
&newTransactedStorage);
+ hr = Storage_ConstructTransacted(&newStorage->base, TRUE,
&newTransactedStorage);
if (FAILED(hr))
IStorage_Release(&newStorage->base.IStorage_iface);
else
@@ -5339,6 +6177,28 @@
return StorageBaseImpl_StreamLink(This->parentStorage,
dst, src);
+}
+
+static HRESULT StorageInternalImpl_GetTransactionSig(StorageBaseImpl *base,
+ ULONG* result, BOOL refresh)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT StorageInternalImpl_SetTransactionSig(StorageBaseImpl *base,
+ ULONG value)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT StorageInternalImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT StorageInternalImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
+{
+ return E_NOTIMPL;
}
/******************************************************************************
@@ -5691,7 +6551,11 @@
StorageInternalImpl_StreamReadAt,
StorageInternalImpl_StreamWriteAt,
StorageInternalImpl_StreamSetSize,
- StorageInternalImpl_StreamLink
+ StorageInternalImpl_StreamLink,
+ StorageInternalImpl_GetTransactionSig,
+ StorageInternalImpl_SetTransactionSig,
+ StorageInternalImpl_LockTransaction,
+ StorageInternalImpl_UnlockTransaction
};
/******************************************************************************
@@ -6145,8 +7009,8 @@
void* buffer,
ULONG* bytesRead)
{
- ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
- ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize;
+ ULONG blockNoInSequence = offset.QuadPart / This->parentStorage->bigBlockSize;
+ ULONG offsetInBlock = offset.QuadPart % This->parentStorage->bigBlockSize;
ULONG bytesToReadInBuffer;
ULONG blockIndex;
BYTE* bufferWalker;
@@ -6193,8 +7057,7 @@
if (!cachedBlock)
{
/* Not in cache, and we're going to read past the end of the block. */
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage,
blockIndex) +
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This->parentStorage,
blockIndex) +
offsetInBlock;
StorageImpl_ReadAt(This->parentStorage,
@@ -6243,8 +7106,8 @@
const void* buffer,
ULONG* bytesWritten)
{
- ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
- ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize;
+ ULONG blockNoInSequence = offset.QuadPart / This->parentStorage->bigBlockSize;
+ ULONG offsetInBlock = offset.QuadPart % This->parentStorage->bigBlockSize;
ULONG bytesToWrite;
ULONG blockIndex;
const BYTE* bufferWalker;
@@ -6278,8 +7141,7 @@
if (!cachedBlock)
{
/* Not in cache, and we're going to write past the end of the block. */
- ulOffset.u.HighPart = 0;
- ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage,
blockIndex) +
+ ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This->parentStorage,
blockIndex) +
offsetInBlock;
StorageImpl_WriteAt(This->parentStorage,
@@ -6331,9 +7193,9 @@
/*
* Figure out how many blocks are needed to contain the new size
*/
- numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
-
- if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
+ numBlocks = newSize.QuadPart / This->parentStorage->bigBlockSize;
+
+ if ((newSize.QuadPart % This->parentStorage->bigBlockSize) != 0)
numBlocks++;
if (numBlocks)
@@ -6462,9 +7324,9 @@
/*
* Figure out how many blocks are needed to contain this stream
*/
- newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
-
- if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
+ newNumBlocks = newSize.QuadPart / This->parentStorage->bigBlockSize;
+
+ if ((newSize.QuadPart % This->parentStorage->bigBlockSize) != 0)
newNumBlocks++;
/*
@@ -6539,10 +7401,10 @@
{
ULARGE_INTEGER size = BlockChainStream_GetSize(This);
- if (newSize.u.LowPart == size.u.LowPart)
+ if (newSize.QuadPart == size.QuadPart)
return TRUE;
- if (newSize.u.LowPart < size.u.LowPart)
+ if (newSize.QuadPart < size.QuadPart)
{
BlockChainStream_Shrink(This, newSize);
}
@@ -6584,10 +7446,8 @@
* size of them
*/
ULARGE_INTEGER result;
- result.u.HighPart = 0;
-
- result.u.LowPart =
- BlockChainStream_GetCount(This) *
+ result.QuadPart =
+ (ULONGLONG)BlockChainStream_GetCount(This) *
This->parentStorage->bigBlockSize;
return result;
@@ -6672,8 +7532,7 @@
*nextBlockInChain = BLOCK_END_OF_CHAIN;
- offsetOfBlockInDepot.u.HighPart = 0;
- offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
+ offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
/*
* Read those bytes in the buffer from the small block file.
@@ -6714,8 +7573,7 @@
DWORD buffer;
ULONG bytesWritten;
- offsetOfBlockInDepot.u.HighPart = 0;
- offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
+ offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
@@ -6770,7 +7628,7 @@
*/
while (nextBlockIndex != BLOCK_UNUSED)
{
- offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
+ offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
res = BlockChainStream_ReadAt(
This->parentStorage->smallBlockDepotChain,
@@ -6798,14 +7656,14 @@
ULARGE_INTEGER newSize, offset;
ULONG bytesWritten;
- newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize;
+ newSize.QuadPart = (ULONGLONG)(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);
- offset.QuadPart = count * This->parentStorage->bigBlockSize;
+ offset.QuadPart = (ULONGLONG)count * This->parentStorage->bigBlockSize;
BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
offset, This->parentStorage->bigBlockSize, smallBlockDepot,
&bytesWritten);
@@ -6823,7 +7681,7 @@
*/
blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
- size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize;
+ size_required.QuadPart = (ULONGLONG)blocksRequired *
This->parentStorage->bigBlockSize;
old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
@@ -6917,11 +7775,10 @@
/*
* Calculate the offset of the small block in the small block file.
*/
- offsetInBigBlockFile.u.HighPart = 0;
- offsetInBigBlockFile.u.LowPart =
- blockIndex * This->parentStorage->smallBlockSize;
-
- offsetInBigBlockFile.u.LowPart += offsetInBlock;
+ offsetInBigBlockFile.QuadPart =
+ (ULONGLONG)blockIndex * This->parentStorage->smallBlockSize;
+
+ offsetInBigBlockFile.QuadPart += offsetInBlock;
/*
* Read those bytes in the buffer from the small block file.
@@ -7013,11 +7870,10 @@
/*
* Calculate the offset of the small block in the small block file.
*/
- offsetInBigBlockFile.u.HighPart = 0;
- offsetInBigBlockFile.u.LowPart =
- blockIndex * This->parentStorage->smallBlockSize;
-
- offsetInBigBlockFile.u.LowPart += offsetInBlock;
+ offsetInBigBlockFile.QuadPart =
+ (ULONGLONG)blockIndex * This->parentStorage->smallBlockSize;
+
+ offsetInBigBlockFile.QuadPart += offsetInBlock;
/*
* Write those bytes in the buffer to the small block file.
@@ -7034,9 +7890,9 @@
/*
* Step to the next big block.
*/
- if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
- &blockIndex)))
- return FALSE;
+ res = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
+ if (FAILED(res))
+ return res;
bufferWalker += bytesWrittenToBigBlockFile;
size -= bytesWrittenToBigBlockFile;
*bytesWritten += bytesWrittenToBigBlockFile;
@@ -7378,20 +8234,13 @@
/*
* Interpret the STGM value grfMode
*/
- shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ shareMode = GetShareModeFromSTGM(grfMode);
accessMode = GetAccessModeFromSTGM(grfMode);
if (grfMode & STGM_DELETEONRELEASE)
fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
else
fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
-
- if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE))
- {
- static int fixme;
- if (!fixme++)
- FIXME("Storage share mode not implemented.\n");
- }
*ppstgOpen = 0;
@@ -7633,13 +8482,6 @@
return STG_E_INVALIDFLAG;
grfMode &= ~0xf0; /* remove the existing sharing mode */
grfMode |= STGM_SHARE_DENY_NONE;
-
- /* STGM_PRIORITY stops other IStorage objects on the same file from
- * committing until the STGM_PRIORITY IStorage is closed. it also
- * stops non-transacted mode StgOpenStorage calls with write access from
- * succeeding. obviously, both of these cannot be achieved through just
- * file share flags */
- FIXME("STGM_PRIORITY mode not implemented correctly\n");
}
/*
@@ -8074,6 +8916,10 @@
case STGM_SHARE_DENY_WRITE:
case STGM_SHARE_EXCLUSIVE:
break;
+ case 0:
+ if (!(stgm & STGM_TRANSACTED))
+ return E_FAIL;
+ break;
default:
return E_FAIL;
}
@@ -8129,14 +8975,16 @@
{
switch (STGM_SHARE_MODE(stgm))
{
+ case 0:
+ assert(stgm & STGM_TRANSACTED);
+ /* fall-through */
case STGM_SHARE_DENY_NONE:
return FILE_SHARE_READ | FILE_SHARE_WRITE;
case STGM_SHARE_DENY_READ:
return FILE_SHARE_WRITE;
case STGM_SHARE_DENY_WRITE:
+ case STGM_SHARE_EXCLUSIVE:
return FILE_SHARE_READ;
- case STGM_SHARE_EXCLUSIVE:
- return 0;
}
ERR("Invalid share mode!\n");
assert(0);
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] Fri Oct 3 11:44:27 2014
@@ -42,6 +42,7 @@
static const ULONG OFFSET_DIRSECTORCOUNT = 0x00000028;
static const ULONG OFFSET_BBDEPOTCOUNT = 0x0000002C;
static const ULONG OFFSET_ROOTSTARTBLOCK = 0x00000030;
+static const ULONG OFFSET_TRANSACTIONSIG = 0x00000034;
static const ULONG OFFSET_SMALLBLOCKLIMIT = 0x00000038;
static const ULONG OFFSET_SBDEPOTSTART = 0x0000003C;
static const ULONG OFFSET_SBDEPOTCOUNT = 0x00000040;
@@ -61,6 +62,7 @@
static const ULONG OFFSET_PS_MTIMEHIGH = 0x00000070;
static const ULONG OFFSET_PS_STARTBLOCK = 0x00000074;
static const ULONG OFFSET_PS_SIZE = 0x00000078;
+static const ULONG OFFSET_PS_SIZE_HIGH = 0x0000007C;
static const WORD DEF_BIG_BLOCK_SIZE_BITS = 0x0009;
static const WORD MIN_BIG_BLOCK_SIZE_BITS = 0x0009;
static const WORD MAX_BIG_BLOCK_SIZE_BITS = 0x000c;
@@ -146,6 +148,8 @@
};
HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName,
ILockBytes **pLockBytes) DECLSPEC_HIDDEN;
+
+HRESULT FileLockBytesImpl_LockRegionSync(ILockBytes* iface, ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb) DECLSPEC_HIDDEN;
/*************************************************************************
* Ole Convert support
@@ -237,6 +241,10 @@
HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const
void*,ULONG*);
HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER);
HRESULT (*StreamLink)(StorageBaseImpl*,DirRef,DirRef);
+ HRESULT (*GetTransactionSig)(StorageBaseImpl*,ULONG*,BOOL);
+ HRESULT (*SetTransactionSig)(StorageBaseImpl*,ULONG);
+ HRESULT (*LockTransaction)(StorageBaseImpl*,BOOL);
+ HRESULT (*UnlockTransaction)(StorageBaseImpl*,BOOL);
};
static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This)
@@ -312,6 +320,28 @@
DirRef dst, DirRef src)
{
return This->baseVtbl->StreamLink(This, dst, src);
+}
+
+static inline HRESULT StorageBaseImpl_GetTransactionSig(StorageBaseImpl *This,
+ ULONG* result, BOOL refresh)
+{
+ return This->baseVtbl->GetTransactionSig(This, result, refresh);
+}
+
+static inline HRESULT StorageBaseImpl_SetTransactionSig(StorageBaseImpl *This,
+ ULONG value)
+{
+ return This->baseVtbl->SetTransactionSig(This, value);
+}
+
+static inline HRESULT StorageBaseImpl_LockTransaction(StorageBaseImpl *This, BOOL write)
+{
+ return This->baseVtbl->LockTransaction(This, write);
+}
+
+static inline HRESULT StorageBaseImpl_UnlockTransaction(StorageBaseImpl *This, BOOL
write)
+{
+ return This->baseVtbl->UnlockTransaction(This, write);
}
/****************************************************************************
@@ -350,6 +380,7 @@
ULONG extBigBlockDepotLocationsSize;
ULONG extBigBlockDepotCount;
ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
+ ULONG transactionSig;
ULONG extBlockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
ULONG indexExtBlockDepotCached;
@@ -373,6 +404,8 @@
UINT blockChainToEvict;
ILockBytes* lockBytes;
+
+ ULONG locked_bytes[8];
};
HRESULT StorageImpl_ReadRawDirEntry(
@@ -457,6 +490,54 @@
StorageBaseImpl* parentStorage,
DWORD grfMode,
DirRef dirEntry) DECLSPEC_HIDDEN;
+
+
+/* Range lock constants.
+ *
+ * The storage format reserves the region from 0x7fffff00-0x7fffffff for
+ * locking and synchronization. Unfortunately, the spec doesn't say which bytes
+ * within that range are used, and for what. These are guesses based on testing.
+ * In particular, ends of ranges may be wrong.
+
+ 0x0 through 0x57: Unknown. Causes read-only exclusive opens to fail.
+ 0x58 through 0x6b: Priority mode.
+ 0x6c through 0x7f: No snapshot mode.
+ 0x80: Commit lock.
+ 0x81 through 0x91: Priority mode, again. Not sure why it uses two regions.
+ 0x92: Lock-checking lock. Held while opening so ranges can be tested without
+ causing spurious failures if others try to grab or test those ranges at the
+ same time.
+ 0x93 through 0xa6: Read mode.
+ 0xa7 through 0xba: Write mode.
+ 0xbb through 0xce: Deny read.
+ 0xcf through 0xe2: Deny write.
+ 0xe2 through 0xff: Unknown. Causes read-only exclusive opens to fail.
+*/
+
+#define RANGELOCK_UNK1_FIRST 0x7fffff00
+#define RANGELOCK_UNK1_LAST 0x7fffff57
+#define RANGELOCK_PRIORITY1_FIRST 0x7fffff58
+#define RANGELOCK_PRIORITY1_LAST 0x7fffff6b
+#define RANGELOCK_NOSNAPSHOT_FIRST 0x7fffff6c
+#define RANGELOCK_NOSNAPSHOT_LAST 0x7fffff7f
+#define RANGELOCK_COMMIT 0x7fffff80
+#define RANGELOCK_PRIORITY2_FIRST 0x7fffff81
+#define RANGELOCK_PRIORITY2_LAST 0x7fffff91
+#define RANGELOCK_CHECKLOCKS 0x7fffff92
+#define RANGELOCK_READ_FIRST 0x7fffff93
+#define RANGELOCK_READ_LAST 0x7fffffa6
+#define RANGELOCK_WRITE_FIRST 0x7fffffa7
+#define RANGELOCK_WRITE_LAST 0x7fffffba
+#define RANGELOCK_DENY_READ_FIRST 0x7fffffbb
+#define RANGELOCK_DENY_READ_LAST 0x7fffffce
+#define RANGELOCK_DENY_WRITE_FIRST 0x7fffffcf
+#define RANGELOCK_DENY_WRITE_LAST 0x7fffffe2
+#define RANGELOCK_UNK2_FIRST 0x7fffffe3
+#define RANGELOCK_UNK2_LAST 0x7fffffff
+#define RANGELOCK_TRANSACTION_FIRST RANGELOCK_COMMIT
+#define RANGELOCK_TRANSACTION_LAST RANGELOCK_CHECKLOCKS
+#define RANGELOCK_FIRST RANGELOCK_UNK1_FIRST
+#define RANGELOCK_LAST RANGELOCK_UNK2_LAST
/******************************************************************************
Modified: trunk/reactos/media/doc/README.WINE
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=…
==============================================================================
--- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original)
+++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Fri Oct 3 11:44:27 2014
@@ -150,7 +150,7 @@
reactos/dll/win32/objsel # Synced to Wine-1.7.17
reactos/dll/win32/odbc32 # Synced to Wine-1.7.17. Depends on port of Linux
ODBC.
reactos/dll/win32/odbccp32 # Synced to Wine-1.7.17
-reactos/dll/win32/ole32 # Synced to Wine-1.7.17
+reactos/dll/win32/ole32 # Synced to Wine-1.7.27
reactos/dll/win32/oleacc # Synced to Wine-1.7.17
reactos/dll/win32/oleaut32 # Synced to Wine-1.7.17
reactos/dll/win32/olecli32 # Synced to Wine-1.7.17