2025-04-27 07:49:33 -04:00

945 lines
28 KiB
C++

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// S H L K C A C H E . C P P
//
// HTTP 1.1/DAV 1.0 request handling via ISAPI
//
// Contains all classes that are created in shared memory
// for use with the shared lock cache.
//
// Classes are:
// CInShBytes = allocates bytes in shared memory.
// CInShString = allocates strings in shared memory.
// CInShLockData = handles all the information about
// a particular lock for a resource.
// CInShCacheStatic = holds all static information needed
// to use the shared cache.
// CInShLockCache = holds the hash table for the shared
// memory cache.
//
// Author: EmilyK
// Date: 3/8/2000
//
// Copyright 2000 Microsoft Corporation, All Rights Reserved
//
#include "_shlkcache.h"
#include "shlkcache.h"
#include "smh.h"
#include "pipeline.h"
#include "crc.h"
enum { TOKENBUFFSIZE = (88) + sizeof(TOKEN_USER)};
//=========================================================
// Supporting functions:
//=========================================================
// Figures out if to FILETIMEs are equal or not. Is used below
// to determine if we have all ready checked if a lock has expired
// for a particular time.
//
BOOL TimesEqual(FILETIME ftNow, FILETIME ftRemembered)
{
// If the low part is not equal than the times are not equal.
//
if (ftNow.dwLowDateTime != ftRemembered.dwLowDateTime)
return FALSE;
// If the low part was equal than we need to check if the
// high part is equal.
//
if (ftNow.dwHighDateTime != ftRemembered.dwHighDateTime)
return FALSE;
// If we got here than we know that both parts match
// and we can return true.
//
return TRUE;
}
// ===============================================================
// CInShBytes Class Method Implemenations
// ===============================================================
//
// Constructor for CInShBytes
//
CInShBytes::CInShBytes() : m_HandleToMemory(NULL)
{
}
//
// Destructor for CInShBytes
//
CInShBytes::~CInShBytes()
{
// If we are holding an offset into the shared memory heap
// we need to free the memory at that offset.
//
if (m_HandleToMemory)
{
SMH::Free(m_HandleToMemory);
}
}
//
// GetPtrToBytes without any arguments returns a constant pointer to the data.
// This pointer is only valid as long as this class is alive. It should not
// be used to change the data, only to read the information the class holds.
//
LPCVOID CInShBytes::GetPtrToBytes()
{
LPVOID pRetVal = NULL;
if (m_HandleToMemory)
{
pRetVal = (LPVOID) SMH::PvFromSMBA(m_HandleToMemory);
}
return pRetVal;
}
//
// GetPtrToBytes with a size returns a pointer to the memory controlled by
// this class after allocating the amount of memory requested. It is used
// when we need to copy a sid into shared memory and need to use the CopySid
// function.
//
LPVOID CInShBytes::GetPtrToBytes(LONG i_cbMemory)
{
// Verify we haven't allocated any memory yet.
//
Assert (NULL == m_HandleToMemory);
if (NULL != m_HandleToMemory)
return NULL;
// Only allocate memory if we have been provided with a reasonable size.
//
if (i_cbMemory > 0)
{
return (LPVOID) SMH::PvAlloc(i_cbMemory, &m_HandleToMemory);
}
return NULL;
}
//
// CopyInBytes is used to initially set the memory that this object holds to
// it's correct value. This object is a set once read many object and can not
// have it's data updated once it has been initalized.
//
void CInShBytes::CopyInBytes(LONG i_cbMemory, LPVOID i_pvMemory)
{
if (i_pvMemory != NULL && i_cbMemory > 0)
{
memcpy(GetPtrToBytes(i_cbMemory), i_pvMemory, i_cbMemory);
}
}
// ===============================================================
// CInShLockCache Class Method Implemenations - Public
// ===============================================================
//
// Constructor for CInShLockCache
//
CInShLockCache::CInShLockCache()
: m_dwItemsInCache(0)
{
}
//
// Destructor for CInShLockCache
//
CInShLockCache::~CInShLockCache()
{
// When the table goes away all handles to the shared data it holds
// go away. As long as the shared cache structure is not sorted then
// the handles stored in the collision lists will also go away. If we
// ever start sorting data, or change the order of insert we need to watch
// for the case when one lock data is holding another that is holding the
// first lock data.
//
};
//
// Function will add a lock token to the cache. It will first add
// it to the ID part of the cache and then it will add to the name
// part of the hash.
//
void CInShLockCache::Add(SharedPtr<CInShLockData>& spSharedEntry)
{
// CODEWORK: Cache could hold the end pointer as well as the
// start pointer so we don't end up walking for
// every insert. We could also do a in order list
// that could make looking for the lock easier.
// Note if we change the ordering of the cache insert
// we need to be careful we don't get any circular
// references (see comment in destructor).
//
ShlkTrace("Add lock type is%d\n", spSharedEntry->GetLockType());
// First figure out what the hash index.
//
DWORD dwIndexID = spSharedEntry->GetIDHashCode();
DWORD dwIndexName = spSharedEntry->GetNameHashCode();
// Lock everyone out of the cache so we can write to it.
//
SynchronizedWriteBlock<CSharedMRWLock> blk(m_lock);
m_dwItemsInCache++;
// Prepend the node at the beginning of both ID and Name hask link.
//
spSharedEntry->SetNextHandleByID(m_hIDEntries[dwIndexID]);
m_hIDEntries[dwIndexID] = spSharedEntry.GetHandle();
spSharedEntry->SetNextHandleByName(m_hNameEntries[dwIndexName]);
m_hNameEntries[dwIndexName] = spSharedEntry.GetHandle();
}
//
// Function deletes the lock token from the cache based on it's
// lock id. This function will delete the lock token completely
// from both hash tables (the name hash as well as the id hash)
//
void CInShLockCache::DeleteByID( __int64 i64LockID )
{
// Figure out where the token has been stored.
//
DWORD dwIndexID = GetHashCodeByID(i64LockID);
SharedPtr<CInShLockData> pForEvaluation;
SharedHandle<CInShLockData> shPrev;
// Lock others out of the cache.
//
SynchronizedWriteBlock<CSharedMRWLock> blk(m_lock);
// Setup to start walking through the ID hash's collision
// list looking for matching tokens.
//
SharedHandle<CInShLockData> shCurrent = m_hIDEntries[dwIndexID];
while (pForEvaluation.FBind(shCurrent))
{
if (pForEvaluation->IsEqualByID(i64LockID))
break;
shPrev = shCurrent;
shCurrent = pForEvaluation->GetNextHandleByID();;
// Be ready to bind for the next bind
//
pForEvaluation.Clear();
}
// If we are on an object then we are going to delete the object from
// the cache. Otherwise the lock doesn't exist.
//
if (!pForEvaluation.FIsNull())
{
// We found it for the ID, so we had better drop the name links as well.
//
DeleteByName( pForEvaluation->GetResourceName(),
i64LockID);
DeleteFromIDList(pForEvaluation, shPrev, dwIndexID);
}
// At the end of this routine the handles held by pForEvaluation and hNextData
// are released. They will in return drop the CInShLockData object
// ref counts. It will hit zero and be freed from memory.
// When it frees from memory, it will check if
// it has any file handles and call a release to free them.
}
//
// Evaluates the i64LockID sent in and returns the index into the
// ID hash table that any object represented by this key would be
// stored at.
//
DWORD CInShLockCache::GetHashCodeByID(__int64 i64LockID)
{
Assert (CACHE_SIZE > 0);
// Figuring out what the actual hash ID of the Lock item is.
//
return static_cast<UINT>(i64LockID) % CACHE_SIZE;
}
//
// Evaluates the wszResource sent in and returns the index into the
// name hash table that any object represented by this key would be
// stored at.
//
DWORD CInShLockCache::GetHashCodeByName(LPCWSTR wszResource)
{
Assert (CACHE_SIZE > 0);
// Need to first convert the string to all lower case. Since
// we are not sure who owns the wszResource string we want to make
// a copy of the string before changing it.
//
UINT cb = static_cast<UINT>(wcslen(wszResource)) * sizeof(WCHAR);
CStackBuffer<WCHAR,MAX_PATH> pwszLower;
if (NULL == pwszLower.resize(cb + sizeof(WCHAR)))
return 0xFFFFFFFF;
CopyMemory( pwszLower.get(), wszResource, cb + sizeof(WCHAR) );
_wcslwr( pwszLower.get() );
// Once we have a converted string we can call the computational
// algorithm to get the index into the hash table.
//
return (DwComputeCRC( 0, pwszLower.get(), cb )) % CACHE_SIZE;
}
//
// Finds any lock token in the cache that is represented by this
// lock token ID. If we do not find it plock will be bound to NULL.
//
BOOL CInShLockCache::FLookupByID( __int64 i64LockID
, SharedPtr<CInShLockData>& plock )
{
DWORD dwIndexID = GetHashCodeByID(i64LockID);
SynchronizedReadBlock<CSharedMRWLock> blk(m_lock);
SharedHandle<CInShLockData> shCurrent = m_hIDEntries[dwIndexID];
// FBind will return false if it binds to a handle that does not have a
// valid object under it. Therefore we do not need to call FIsNull to
// check if the handle pointed to an object or not.
//
while (plock.FBind(shCurrent))
{
if (plock->IsEqualByID(i64LockID))
return TRUE;
shCurrent = plock->GetNextHandleByID();
// Be ready for next bind
//
plock.Clear();
};
return FALSE;
}
#ifdef DBG
//
// Used as a debugging function to dump the cache out and see what
// it holds.
//
void CInShLockCache::DumpCache()
{
SharedPtr<CInShLockData> splock;
SharedHandle<CInShLockData> shNext;
for (int i=0; i < CACHE_SIZE; i++)
{
if (splock.FBind(m_hIDEntries[i]))
{
ShlkTrace("%s: LockType: %d ID: %d Name: %d \r\n",
splock->GetResourceName(),
splock->GetLockType(),
splock->GetIDHashCode(),
splock->GetNameHashCode());
// Be ready for next bind
//
shNext = splock->GetNextHandleByID();
splock.Clear();
while (splock.FBind(shNext))
{
ShlkTrace ("%s: LockType: %d ID: %d Name: %d \r\n",
splock->GetResourceName(),
splock->GetLockType(),
splock->GetIDHashCode(),
splock->GetNameHashCode());
// Be ready for next bind
//
shNext = splock->GetNextHandleByID();
splock.Clear();
}
}
}
}
#endif // DBG
//
// Finds all locks for a particular resource (matching a particular
// lock type). If fEmitXML is sent in then it will also use the
// callback function to emit the lock info to the response body.
//
BOOL CInShLockCache::FLookUpAll( LPCWSTR wszResource
, DWORD dwLockType
, BOOL fEmitXML
, LPVOID pContext
, EmitLockInfoDecl* pEmitLockInfo )
{
SharedPtr<CInShLockData> plock;
// Register as a reader of this data.
//
SynchronizedReadBlock<CSharedMRWLock> blk(m_lock);
// Find the starting lock token for this resource.
//
if(FLookupByName(wszResource, dwLockType, plock))
{
Assert (!plock.FIsNull());
if (fEmitXML)
{
SharedHandle<CInShLockData> shNext;
// Walk through the whole list to emit all lock tokens.
//
do
{
pEmitLockInfo(&plock, pContext);
// Be Ready To bind to the next
//
shNext = plock->GetNextHandleByName();
plock.Clear();
} while (plock.FBind(shNext) &&
plock->IsEqualByName(wszResource, dwLockType));
}
return TRUE;
}
return FALSE;
}
//
// Function goes through the whole cache and free's up any locks
// that have out lasted their timeout values.
//
VOID CInShLockCache::ExpireLocks()
{
// Loop through cache and look for any locks that say they have expired.
// For each cache line entry first walk the ID links then the name links.
// If you find one that has expired, drop it from the link list.
// Once it has been dropped from both lists, normal clean up of the object
// should release the file handle and the lock should be gone.
SharedPtr<CInShLockData> pForEvaluation;
SharedHandle<CInShLockData> shCurrent;
SharedHandle<CInShLockData> shPrev;
FILETIME ftNow;
// Get one time to compare all the locks against.This is to avoid calling this
// function per every lock we have. And also to avoid only dropping a lock
// from the Name list and not the ID list because the name list was looked at later.
//
GetSystemTimeAsFileTime( &ftNow );
// For now we are locking for write the entire time we are walking the lock
// cache. This will probably be a nice bottle neck. We need to change this
// to lock in some sort of promotable way.
//
SynchronizedWriteBlock<CSharedMRWLock> blk(m_lock);
// Track the num locks visited so we can stop early if we have found all the locks
// in the cache.
//
if (m_dwItemsInCache > 0)
{
for (DWORD dwIndex = 0; dwIndex < CACHE_SIZE; dwIndex++)
{
shCurrent = m_hIDEntries[dwIndex];
shPrev.Clear();
// Drop the links for the ID list for the cache entry.
//
while (pForEvaluation.FBind(shCurrent))
{
if (pForEvaluation->IsExpired(ftNow))
{
DeleteFromIDList(pForEvaluation, shPrev, dwIndex);
}
else
{
// Only move the previous pointer if we did not
// drop the item from the list.
//
shPrev = shCurrent;
}
// Even though we dropped pForEvaluation from the linked listed we
// still have a handle on him here.
//
shCurrent = pForEvaluation->GetNextHandleByID();
pForEvaluation.Clear();
}
// Drop the links for the ID list for the cache entry.
//
shCurrent = m_hNameEntries[dwIndex];
shPrev.Clear();
while (pForEvaluation.FBind(shCurrent))
{
if (pForEvaluation->IsExpired(ftNow))
{
DeleteFromNameList(pForEvaluation, shPrev, dwIndex);
}
else
{
// Only move the previous pointer if we did not
// drop the item from the list.
//
shPrev = shCurrent;
}
// Even though we dropped pForEvaluation from the linked listed we
// still have a handle on him here.
//
shCurrent = pForEvaluation->GetNextHandleByName();
pForEvaluation.Clear();
}
} // for
}
}
// ===============================================================
// CInShLockCache Class Method Implemenations - Private
// ===============================================================
//
// Function deletes a found lock token from the name hash table.
//
VOID CInShLockCache::DeleteFromNameList(SharedPtr<CInShLockData>& spLockToDelete
, SharedHandle<CInShLockData>& shLockPrev
, DWORD dwIndexInCache)
{
// If we are on an object then we are going to delete the object from the cache.
// Otherwise the lock doesn't exist.
//
if (!spLockToDelete.FIsNull())
{
SharedPtr<CInShLockData> pLockPrev;
if (pLockPrev.FBind(shLockPrev))
{
// If shObjBefore was an empty handle then this binding will return false.
// in that case we are dealing with the first object. otherwise we have
// an object to alter.
//
pLockPrev->SetNextHandleByName (spLockToDelete->GetNextHandleByName());
}
else
{
m_hNameEntries[dwIndexInCache] = spLockToDelete->GetNextHandleByName();
}
}
}
//
// Function deletes a found lock token from the ID hash table.
//
VOID CInShLockCache::DeleteFromIDList(SharedPtr<CInShLockData>& spLockToDelete
, SharedHandle<CInShLockData>& shLockPrev
, DWORD dwIndexInCache)
{
// If we are on an object then we are going to delete the object from the cache.
// Otherwise the lock doesn't exist.
//
if (!spLockToDelete.FIsNull())
{
SharedPtr<CInShLockData> pLockPrev;
if (pLockPrev.FBind(shLockPrev))
{
// if shObjBefore was an empty handle then this binding will return false.
// in that case we are dealing with the first object. otherwise we have
// an object to alter.
//
pLockPrev->SetNextHandleByID (spLockToDelete->GetNextHandleByID());
}
else
{
m_hIDEntries[dwIndexInCache] = spLockToDelete->GetNextHandleByID();
}
// We only record the deletion of an item when it is removed
// from the ID list, this way we don't end up subtracting two
// for each lock removed.
//
m_dwItemsInCache--;
}
}
//
// Function finds and deletes a token from the name hash table.
//
void CInShLockCache::DeleteByName ( LPCWSTR wszResource, __int64 i64LockID)
{
DWORD dwIndex = GetHashCodeByName(wszResource);
SharedPtr<CInShLockData> pForEvaluation;
SharedHandle<CInShLockData> shPrev;
SharedHandle<CInShLockData> shCurrent = m_hNameEntries[dwIndex];
while (pForEvaluation.FBind(shCurrent))
{
// Note because we must compare ID.
// The (resource name, locktype) pair is NOT unique
//
if (pForEvaluation->IsEqualByID(i64LockID))
break;
shPrev = shCurrent;
shCurrent = pForEvaluation->GetNextHandleByName();
// Be ready for next bind
//
pForEvaluation.Clear();
};
DeleteFromNameList(pForEvaluation, shPrev, dwIndex);
}
//
// Function finds a lock token based on name. This function is used
// by LookupAll to find all locks dealing with a particular resource.
// If we do not find an object than plock will be bound to NULL.
//
//$IMPORTANT: this function returns the first lock that match the name
//$IMPORTANT: it's possible more than one lock of same type exists
//$IMPORTANT: on a single resource.
//
BOOL CInShLockCache::FLookupByName( LPCWSTR wszResource, DWORD dwLockType
, SharedPtr<CInShLockData>& plock )
{
#ifdef DBG
// Function should only be called from LookupAll
// Function depends on LookupAll to perform the read locking that scopes this function.
// Debug routine
//
DumpCache();
#endif
DWORD dwIndex = GetHashCodeByName(wszResource);
SharedHandle<CInShLockData> shCurrent = m_hNameEntries[dwIndex];
// FBind will return false if it binds to a handle that does not have a valid object
// under it. Therefore we do not need to call FIsNull to check if the handle pointed
// to an object or not.
//
while (plock.FBind(shCurrent))
{
if (plock->IsEqualByName(wszResource, dwLockType))
return TRUE;
shCurrent = plock->GetNextHandleByName();
// Be ready for next bind
//
plock.Clear();
};
return FALSE;
}
// ===============================================================
// CInShLockData Class Method Implemenations - Public
// ===============================================================
//
// Constructor for CInShLockData
//
CInShLockData::CInShLockData()
: m_dwAccess(0)
, m_dwLockType(0)
, m_dwLockScope(0)
, m_dwNameHash(0)
, m_dwIDHash(0)
, m_dwSecondsTimeout(DEFAULT_LOCK_TIMEOUT)
, m_hDAVProcFileHandle(INVALID_HANDLE_VALUE)
, m_fHasTimedOut(FALSE)
{
// CODEWORK: Review usage of m_fRememberFTnow.
// Need to make sure it makes sense
// and is not wasting perf while trying
// to improve perf.
m_fRememberFtNow.dwLowDateTime = 0;
m_fRememberFtNow.dwHighDateTime = 0;
}
//
// Destructor for CInShLockData
//
CInShLockData::~CInShLockData()
{
// Make sure we tell the DAV Process that this
// file lock should be released.
//
if (m_hDAVProcFileHandle != INVALID_HANDLE_VALUE)
{
PIPELINE::RemoveHandle(m_hDAVProcFileHandle);
}
}
//
// Initialization routine used by the shared lock manager to setup
// a valid new shared lock token with all the information it is
// passed when fslock requests a new lock on a file.
//
HRESULT CInShLockData::Init ( LPCWSTR wszStoragePath
, DWORD dwAccess
, _int64 i64LockID
, LPCWSTR pwszGuid
, DWORD dwLockType
, DWORD dwLockScope
, DWORD dwTimeout
, LPCWSTR wszOwnerComment
, HANDLE hit
)
{
HRESULT hr = S_OK;
m_i64LockID = i64LockID;
WCHAR rgwchBuffer[33];
// Opaquelocktoken format is partially defined by our IETF spec.
// First opaquelocktoken:<our guid>, then our specific lock id.
//
wsprintfW (m_rgwchToken, L"<opaquelocktoken:%ls:%ls>",
pwszGuid,
_i64tow (i64LockID, rgwchBuffer, 10));
// Save the simple information in the new lock token
//
m_dwAccess = dwAccess;
m_dwLockType = dwLockType;
m_dwLockScope = dwLockScope;
if (dwTimeout) m_dwSecondsTimeout = dwTimeout;
// Create a shared memory object to hold the resource name
//
SharedPtr<CInShString> spResourceStr;
if (!spResourceStr.FCreate())
ShlkTrace("Error from spResourceStr.FCreate()\r\n");
else
{
spResourceStr->CopyInString(wszStoragePath);
m_hOffsetToResourceString = spResourceStr.GetHandle();
}
// Create a shared memory object to hold the owner comment.
//
if (wszOwnerComment!=NULL)
{
SharedPtr<CInShString> spOwnerComment;
if (!spOwnerComment.FCreate())
ShlkTrace("Error from spOwnerComment.FCreate()\r\n");
else
{
spOwnerComment->CopyInString(wszOwnerComment);
m_hOffsetToOwnerComment = spOwnerComment.GetHandle();
}
}
// Save the owners sid into the object.
//
hr = SetLockOwnerSID(hit);
if (FAILED(hr))
ShlkTrace("Error setting the SID\r\n");
// Lastly set in the last file time that this was accessed.
//
GetSystemTimeAsFileTime(&m_ftLastAccess);
return hr;
}
//
// Routine determines if the lock token represents a lock on the
// resource of the type specified.
//
BOOL CInShLockData::IsEqualByName(LPCWSTR wszResource, DWORD dwLockType)
{
BOOL fRetVal = FALSE;
// Locks only match if the lock type and the resource name match.
// Check the locktype first to avoid the string compare if we don't
// need to do it.
//
if ((dwLockType & m_dwLockType) && (wcscmp(GetResourceName(), wszResource) == 0))
{
fRetVal = TRUE;
}
return fRetVal;
}
//
// Routine checks if the lock token has expired. It was stolen from
// FExpiredlock in lockmgr.cpp. There are comments there about the
// way this is done.
//
BOOL CInShLockData::IsExpired(FILETIME ftNow)
{
// CODEWORK: passing FILETIME's by pointers instead of value?
// should we be doing it that way?
// This function will be called twice during each ExpiredLocks
// check. The first time it is called we should do the checks
// and set the m_fHasTimedOut call. The second time we want to
// avoid it because we all ready know the answer. By keeping
// track of the ftNow times we are called with we can determine
// if we have all ready done the calculation or not.
// We also know that no matter what once a lock timesout, it should
// remained timed out for it's lifetime.
//
if ((!m_fHasTimedOut) && (!TimesEqual(ftNow, m_fRememberFtNow)))
{
// Based on the time passed in has the lock expired??
//
__int64 i64TimePassed = 0;
DWORD dwTimePassed = 0;
DWORD dwSecondTimeout = GetTimeoutInSecs();
// Do the math to figure out when this lock expires/expired.
//
// First calc how many seconds have passed since this lock
// was last accessed.
// Subtract the filetimes to get the time passed in 100-nanosecond
// increments. (That's how filetimes count.)
// NOTE: Operation bellow is very dangerous on 64 bit platforms,
// as the filetimes need to be alligned on 8 byte boundary. So even
// change in order of current member variables or adding new ones
// can get us in the trouble
//
i64TimePassed = ( (*(__int64*)&ftNow) -
(*(__int64*)&m_ftLastAccess)
);
// Convert our time passed into seconds (10,000,000 100-nanosec incs in a second).
//
dwTimePassed = (DWORD)( i64TimePassed / (__int64)10000000 );
// Compare the timeout from the lock object to the count of seconds.
// If this lock object has expired, remove it.
//
m_fHasTimedOut = dwSecondTimeout < dwTimePassed;
m_fRememberFtNow = ftNow;
}
return m_fHasTimedOut;
}
//
// Routine takes the two hash indexes provided by the shared lock
// manager and saves them as part of the lock token data.
//
void CInShLockData::SetHashes(DWORD dwIDValue, DWORD dwNameValue)
{
m_dwNameHash = dwNameValue;
// Figuring out what the actual hash ID of the lock item is.
//
m_dwIDHash = dwIDValue;
}
//
// Routine creates a valid file handle based on the handle value
// that the DAVProc procedure holds on the file. Handles returned
// from this function should have CloseHandle called on them when
// they are done being used.
//
HRESULT CInShLockData::GetUsableHandle(HANDLE i_hDAVProcess, HANDLE* o_phFile)
{
// CodeWork:: Should not need to pass in the DAVProcess handle here.
// hDAVProcess is the handle to the dav process
// while m_hDAVProcFileHandle is the handle to the file
// in terms of the DAV Process's scope.
//
return DupHandle(i_hDAVProcess, m_hDAVProcFileHandle, o_phFile);
}
// ===============================================================
// CInShLockData Class Method Implemenations - Private
// ===============================================================
//
// Routine copies the SID from the handle passed in, into the
// shared memory location that holds the owner sid for the lock.
//
HRESULT CInShLockData::SetLockOwnerSID(HANDLE hit)
{
BYTE tokenbuff[TOKENBUFFSIZE];
TOKEN_USER *ptu = reinterpret_cast<TOKEN_USER *>(tokenbuff);
ULONG ulcbTok = sizeof(tokenbuff);
DWORD dwErr = 0;
Assert(hit);
// Try to get the SID on this handle.
//
if (GetTokenInformation (hit,
TokenUser,
ptu,
ulcbTok,
&ulcbTok))
{
SID * psid = reinterpret_cast<SID *>(ptu->User.Sid);
DWORD dwLength;
BOOL fSuccess;
// Copy the SID over into the lock object.
//
dwLength = GetSidLengthRequired(psid->SubAuthorityCount);
Assert(dwLength); // MSDN said this call "cannot fail".
SharedPtr<CInShBytes> spSID;
if (!spSID.FCreate())
ShlkTrace("Creating SID Error \r\n");
else
{
fSuccess = CopySid(dwLength, spSID->GetPtrToBytes(dwLength), ptu->User.Sid);
if (!fSuccess)
{
// Fail the method.
//
dwErr = GetLastError();
ShlkTrace ("Dav: Could not copy the SID: %d\n", dwErr);
goto err;
}
m_hOffsetToSidOwner = spSID.GetHandle();
}
ShlkTrace ("CInShLockData::SetLockOwnerSID: ");
}
else
{
dwErr = GetLastError();
ShlkTrace ("Dav: Could not query on impersonation token: %d\n", dwErr);
goto err;
}
err:
return HRESULT_FROM_WIN32(dwErr);
}