mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-19 15:48:53 +00:00
ole32: Initial implementation of transaction locking.
This commit is contained in:
parent
b4ade51a84
commit
4f0d36d9a0
|
@ -110,6 +110,7 @@ static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const
|
|||
static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
|
||||
static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
|
||||
static void StorageImpl_SaveFileHeader(StorageImpl* This);
|
||||
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);
|
||||
|
@ -191,6 +192,9 @@ typedef struct TransactedSnapshotImpl
|
|||
* Changes are committed to the transacted parent.
|
||||
*/
|
||||
StorageBaseImpl *transactedParent;
|
||||
|
||||
/* The transaction signature from when we last committed */
|
||||
ULONG lastTransactionSig;
|
||||
} TransactedSnapshotImpl;
|
||||
|
||||
/* Generic function to create a transacted wrapper for a direct storage object. */
|
||||
|
@ -2640,6 +2644,81 @@ static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst,
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT StorageImpl_GetTransactionSig(StorageBaseImpl *base,
|
||||
ULONG* result, BOOL refresh)
|
||||
{
|
||||
StorageImpl *This = (StorageImpl*)base;
|
||||
HRESULT hr=S_OK;
|
||||
|
||||
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))
|
||||
{
|
||||
/* FIXME: Throw out everything and reload the file if this changed. */
|
||||
StorageUtl_ReadDWord(data, 0, &This->transactionSig);
|
||||
}
|
||||
}
|
||||
|
||||
*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)
|
||||
{
|
||||
StorageImpl *This = (StorageImpl*)base;
|
||||
HRESULT hr;
|
||||
ULARGE_INTEGER offset, cb;
|
||||
|
||||
/* Synchronous grab of both priority ranges, the commit lock, and the
|
||||
* lock-checking lock. */
|
||||
offset.QuadPart = RANGELOCK_TRANSACTION_FIRST;
|
||||
cb.QuadPart = RANGELOCK_TRANSACTION_LAST - RANGELOCK_TRANSACTION_FIRST + 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)
|
||||
{
|
||||
StorageImpl *This = (StorageImpl*)base;
|
||||
HRESULT hr;
|
||||
ULARGE_INTEGER offset, cb;
|
||||
|
||||
offset.QuadPart = RANGELOCK_TRANSACTION_FIRST;
|
||||
cb.QuadPart = RANGELOCK_TRANSACTION_LAST - RANGELOCK_TRANSACTION_FIRST + 1;
|
||||
|
||||
hr = ILockBytes_UnlockRegion(This->lockBytes, offset, cb, LOCK_ONLYONCE);
|
||||
|
||||
if (hr == STG_E_INVALIDFUNCTION)
|
||||
hr = S_OK;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT StorageImpl_GetFilename(StorageBaseImpl* iface, LPWSTR *result)
|
||||
{
|
||||
StorageImpl *This = (StorageImpl*) iface;
|
||||
|
@ -2740,7 +2819,11 @@ static const StorageBaseImplVtbl StorageImpl_BaseVtbl =
|
|||
StorageImpl_StreamReadAt,
|
||||
StorageImpl_StreamWriteAt,
|
||||
StorageImpl_StreamSetSize,
|
||||
StorageImpl_StreamLink
|
||||
StorageImpl_StreamLink,
|
||||
StorageImpl_GetTransactionSig,
|
||||
StorageImpl_SetTransactionSig,
|
||||
StorageImpl_LockTransaction,
|
||||
StorageImpl_UnlockTransaction
|
||||
};
|
||||
|
||||
static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset,
|
||||
|
@ -3774,6 +3857,11 @@ static HRESULT StorageImpl_LoadFileHeader(
|
|||
OFFSET_ROOTSTARTBLOCK,
|
||||
&This->rootStartBlock);
|
||||
|
||||
StorageUtl_ReadDWord(
|
||||
headerBigBlock,
|
||||
OFFSET_TRANSACTIONSIG,
|
||||
&This->transactionSig);
|
||||
|
||||
StorageUtl_ReadDWord(
|
||||
headerBigBlock,
|
||||
OFFSET_SMALLBLOCKLIMIT,
|
||||
|
@ -3932,6 +4020,11 @@ static void StorageImpl_SaveFileHeader(
|
|||
OFFSET_ROOTSTARTBLOCK,
|
||||
This->rootStartBlock);
|
||||
|
||||
StorageUtl_WriteDWord(
|
||||
headerBigBlock,
|
||||
OFFSET_TRANSACTIONSIG,
|
||||
This->transactionSig);
|
||||
|
||||
StorageUtl_WriteDWord(
|
||||
headerBigBlock,
|
||||
OFFSET_SMALLBLOCKLIMIT,
|
||||
|
@ -4880,6 +4973,7 @@ static HRESULT WINAPI TransactedSnapshotImpl_Commit(
|
|||
DirEntry data;
|
||||
ULARGE_INTEGER zero;
|
||||
HRESULT hr;
|
||||
ULONG transactionSig;
|
||||
|
||||
zero.QuadPart = 0;
|
||||
|
||||
|
@ -4889,6 +4983,27 @@ static HRESULT WINAPI TransactedSnapshotImpl_Commit(
|
|||
if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
|
||||
return STG_E_ACCESSDENIED;
|
||||
|
||||
hr = StorageBaseImpl_LockTransaction(This->transactedParent);
|
||||
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))
|
||||
{
|
||||
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
|
||||
|
@ -4898,10 +5013,10 @@ static HRESULT WINAPI TransactedSnapshotImpl_Commit(
|
|||
root_entry = &This->entries[This->base.storageDirEntry];
|
||||
|
||||
if (!root_entry->read)
|
||||
return S_OK;
|
||||
goto end;
|
||||
|
||||
hr = TransactedSnapshotImpl_CopyTree(This);
|
||||
if (FAILED(hr)) return hr;
|
||||
if (FAILED(hr)) goto end;
|
||||
|
||||
if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
|
||||
dir_root_ref = DIRENTRY_NULL;
|
||||
|
@ -4972,6 +5087,9 @@ static HRESULT WINAPI TransactedSnapshotImpl_Commit(
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = StorageBaseImpl_Flush(This->transactedParent);
|
||||
end:
|
||||
StorageBaseImpl_UnlockTransaction(This->transactedParent);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -5266,6 +5384,28 @@ static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base,
|
|||
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)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT TransactedSnapshotImpl_UnlockTransaction(StorageBaseImpl *base)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
|
||||
{
|
||||
StorageBaseImpl_QueryInterface,
|
||||
|
@ -5301,7 +5441,11 @@ static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl =
|
|||
TransactedSnapshotImpl_StreamReadAt,
|
||||
TransactedSnapshotImpl_StreamWriteAt,
|
||||
TransactedSnapshotImpl_StreamSetSize,
|
||||
TransactedSnapshotImpl_StreamLink
|
||||
TransactedSnapshotImpl_StreamLink,
|
||||
TransactedSnapshotImpl_GetTransactionSig,
|
||||
TransactedSnapshotImpl_SetTransactionSig,
|
||||
TransactedSnapshotImpl_LockTransaction,
|
||||
TransactedSnapshotImpl_UnlockTransaction
|
||||
};
|
||||
|
||||
static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
|
||||
|
@ -5328,6 +5472,9 @@ static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
|
|||
|
||||
(*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,
|
||||
0, &scratch);
|
||||
|
@ -5525,6 +5672,28 @@ static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base,
|
|||
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)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT StorageInternalImpl_UnlockTransaction(StorageBaseImpl *base)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Storage32InternalImpl_Commit
|
||||
|
@ -5875,7 +6044,11 @@ static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl =
|
|||
StorageInternalImpl_StreamReadAt,
|
||||
StorageInternalImpl_StreamWriteAt,
|
||||
StorageInternalImpl_StreamSetSize,
|
||||
StorageInternalImpl_StreamLink
|
||||
StorageInternalImpl_StreamLink,
|
||||
StorageInternalImpl_GetTransactionSig,
|
||||
StorageInternalImpl_SetTransactionSig,
|
||||
StorageInternalImpl_LockTransaction,
|
||||
StorageInternalImpl_UnlockTransaction
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -7810,13 +7983,6 @@ HRESULT WINAPI StgOpenStorage(
|
|||
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");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,6 +51,7 @@ static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
|
|||
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;
|
||||
|
@ -246,6 +247,10 @@ struct StorageBaseImplVtbl {
|
|||
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*);
|
||||
HRESULT (*UnlockTransaction)(StorageBaseImpl*);
|
||||
};
|
||||
|
||||
static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This)
|
||||
|
@ -323,6 +328,28 @@ static inline HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This,
|
|||
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)
|
||||
{
|
||||
return This->baseVtbl->LockTransaction(This);
|
||||
}
|
||||
|
||||
static inline HRESULT StorageBaseImpl_UnlockTransaction(StorageBaseImpl *This)
|
||||
{
|
||||
return This->baseVtbl->UnlockTransaction(This);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* StorageBaseImpl stream list handlers
|
||||
*/
|
||||
|
@ -359,6 +386,7 @@ struct StorageImpl
|
|||
ULONG extBigBlockDepotLocationsSize;
|
||||
ULONG extBigBlockDepotCount;
|
||||
ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
|
||||
ULONG transactionSig;
|
||||
|
||||
ULONG extBlockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
|
||||
ULONG indexExtBlockDepotCached;
|
||||
|
|
|
@ -3491,7 +3491,7 @@ static void test_transacted_shared(void)
|
|||
|
||||
/* commit fails because we're out of date */
|
||||
r = IStorage_Commit(stgrw, STGC_ONLYIFCURRENT);
|
||||
todo_wine ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
|
||||
ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
|
||||
|
||||
/* unless we force it */
|
||||
r = IStorage_Commit(stgrw, STGC_DEFAULT);
|
||||
|
@ -3515,7 +3515,7 @@ static void test_transacted_shared(void)
|
|||
|
||||
/* and committing fails forever */
|
||||
r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
|
||||
todo_wine ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
|
||||
ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
|
||||
|
||||
IStream_Release(stm);
|
||||
|
||||
|
|
Loading…
Reference in a new issue