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?r... ============================================================================== --- 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/filelockbyt... ============================================================================== --- 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/filemoniker... ============================================================================== --- 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.c... ============================================================================== --- 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.h... ============================================================================== --- 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=6... ============================================================================== --- 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