📄 davlock.cpp
字号:
m_pLockList = pLock;
return TRUE;
}
void CWebDavFileNode::DeInitAndFreeLock(CWebDavLock *pLockList) {
DebugCheckCacheManagerLocked();
pLockList->DeInitLock();
g_pFileLockManager->FreeFixedLock(pLockList);
}
BOOL CWebDavFileNode::DeleteLock(CWebDavLock *pLockList) {
DebugCheckCacheManagerLocked();
// If another thread is using lock in PUT/MOVE/COPY/... then leave it alone.
if (IsBusy())
return FALSE;
CWebDavLock *pTrav = m_pLockList;
CWebDavLock *pFollow = NULL;
// remove item from linked list
while (pTrav && (pTrav != pLockList)) {
pFollow = pTrav;
pTrav = pTrav->m_pNext;
}
DEBUGCHK(pTrav); // pLockList must be a valid node.
if (pFollow)
pFollow->m_pNext = pTrav->m_pNext;
else {
DEBUGCHK(pLockList == m_pLockList);
m_pLockList = pLockList->m_pNext;
}
DeInitAndFreeLock(pLockList);
return TRUE;
}
void CWebDavFileNode::RemoveTimedOutLocks(FILETIME *pft) {
DebugCheckCacheManagerLocked();
// If another thread is using lock in PUT/MOVE/COPY/... then leave it alone.
if (IsBusy())
return;
CWebDavLock *pTrav = m_pLockList;
CWebDavLock *pFollow = NULL;
while (pTrav) {
CWebDavLock *pNext = pTrav->m_pNext;
if (pTrav->HasLockExpired(pft)) {
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: Lock for file %s, lockID=%I64d has expired, removing\r\n",m_szFileName,pTrav->m_i64LockId));
DeInitAndFreeLock(pTrav);
if (pFollow)
pFollow->m_pNext = pNext;
else {
DEBUGCHK(pTrav == m_pLockList);
m_pLockList = pNext;
}
}
else {
pFollow = pTrav;
}
pTrav = pNext;
}
}
BOOL CWebDavFileNode::HasLockId(__int64 iLockId, CWebDavLock **ppLockMatch) {
DEBUGCHK(m_pLockList); // if list is NULL, *this should've been deleted.
DebugCheckCacheManagerLocked();
CWebDavLock *pLock = m_pLockList;
while (pLock) {
if (pLock->m_i64LockId == iLockId) {
if (ppLockMatch)
*ppLockMatch = pLock;
return TRUE;
}
pLock = pLock->m_pNext;
}
return FALSE;
}
// A client has passed one or more LockIDs to our server. Verify that at least one
// of them corresponds with the lockIDs associated with this file.
BOOL CWebDavFileNode::HasLockIdInArray(LockIdArray *pLockIDs, int numLockIds) {
DebugCheckCacheManagerLocked();
DEBUGCHK(pLockIDs && numLockIds);
for (int i = 0; i < numLockIds; i++) {
if (HasLockId((*pLockIDs)[i]))
return TRUE;
}
return FALSE;
}
//
// Utility
//
unsigned short us_rand (void) {
unsigned short usRes = (unsigned short)rand();
if (rand() > RAND_MAX / 2)
usRes |= 0x8000;
return usRes;
}
typedef int (*CeGenerateGUID_t) (GUID *);
void GenerateGUID (GUID *pGuid) {
HMODULE hLib = LoadLibrary (L"\\windows\\lpcrt.dll");
if (hLib) {
CeGenerateGUID_t CeGenerateGUID = (CeGenerateGUID_t)GetProcAddress (hLib, L"CeGenerateGUID");
int fRet = (CeGenerateGUID && CeGenerateGUID (pGuid) == 0);
FreeLibrary (hLib);
if (fRet)
return;
}
srand (GetTickCount ());
pGuid->Data1 = (us_rand () << 16) | us_rand();
pGuid->Data2 = us_rand();
pGuid->Data3 = us_rand();
for (int i = 0 ; i < 8 ; i += 2) {
unsigned short usRand = us_rand();
pGuid->Data4[i] = (unsigned char)(usRand & 0xff);
pGuid->Data4[i + 1] = (unsigned char)(usRand >> 8);
}
}
//
// CWebDavFileLockManager
//
// start with same LockID as IIS
#define DAV_INITIAL_LOCK_ID ((((__int64)50 << 32)) + 50)
#if defined (DEBUG)
// Debug verification that CWebDavFileLockManager is only instantiated once
// per web server being loaded / unloaded
int cWebDavFileLockManagerInitializations = 0;
#endif
CWebDavFileLockManager::CWebDavFileLockManager() {
#if defined (DEBUG)
DEBUGCHK(cWebDavFileLockManagerInitializations == 0);
cWebDavFileLockManagerInitializations++;
#endif
m_pFileLockList = NULL;
m_iNextLockId = DAV_INITIAL_LOCK_ID;
GUID lockGuid;
GenerateGUID(&lockGuid);
HRESULT hr = StringCchPrintfA(m_szLockGUID,SVSUTIL_ARRLEN(m_szLockGUID),SVSUTIL_GUID_FORMAT_A,SVSUTIL_RGUID_ELEMENTS(lockGuid));
DEBUGCHK(hr == S_OK && (strlen(m_szLockGUID) == SVSUTIL_GUID_STR_LENGTH));
m_pfmdFileNodes = svsutil_AllocFixedMemDescr (sizeof(CWebDavFileNode), 10);
m_pfmdLocks = svsutil_AllocFixedMemDescr (sizeof(CWebDavLock), 10);
m_pFileLockList = NULL;
}
CWebDavFileLockManager::~CWebDavFileLockManager() {
DEBUGCHK(g_fState == SERVICE_STATE_SHUTTING_DOWN || g_fState == SERVICE_STATE_UNLOADING);
Lock();
// remove everything in FileLock List
while (m_pFileLockList) {
CWebDavFileNode *pNext = m_pFileLockList->m_pNext;
DeInitAndFreeFileNode(m_pFileLockList);
m_pFileLockList = pNext;
}
if (m_pfmdFileNodes)
svsutil_ReleaseFixedNonEmpty(m_pfmdFileNodes);
if (m_pfmdLocks)
svsutil_ReleaseFixedNonEmpty (m_pfmdLocks);
Unlock();
}
CWebDavFileNode* CWebDavFileLockManager::GetNodeFromID(__int64 iLockId, CWebDavLock **ppLockMatch) {
DEBUGCHK(IsLocked());
CWebDavFileNode *pFile = m_pFileLockList;
while (pFile) {
if (pFile->HasLockId(iLockId,ppLockMatch))
return pFile;
pFile = pFile->m_pNext;
}
return NULL;
}
CWebDavFileNode * CWebDavFileLockManager::GetNodeFromFileName(WCHAR *szFileName) {
DEBUGCHK(IsLocked());
CWebDavFileNode *pTrav = m_pFileLockList;
while (pTrav) {
if (0 == PathNameCompare(pTrav->m_szFileName,szFileName))
return pTrav;
pTrav = pTrav->m_pNext;
}
return NULL;
}
BOOL CWebDavFileLockManager::IsFileAssociatedWithLockId(WCHAR *szFileName, __int64 iLockId) {
BOOL fRet = FALSE;
Lock();
CWebDavFileNode *pFileNode = GetNodeFromFileName(szFileName);
if (pFileNode)
fRet = pFileNode->HasLockId(iLockId);
Unlock();
#if defined (DEBUG)
if (!fRet)
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: File <%s> is not associated with LockID %I64d\r\n",szFileName,iLockId));
#endif
return fRet;
}
void CWebDavFileLockManager::RemoveTimedOutLocks(void) {
Lock();
FILETIME ft;
GetCurrentFT(&ft);
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: file lock cleanup thread woke up, ft.dwHighDateTime = 0x%08x, ft.dwLowDateTime = 0x%08x\r\n",
ft.dwHighDateTime,ft.dwLowDateTime));
CWebDavFileNode *pTrav = m_pFileLockList;
CWebDavFileNode *pFollow = NULL;
while (pTrav) {
CWebDavFileNode *pNext = pTrav->m_pNext;
pTrav->RemoveTimedOutLocks(&ft);
// if there are no more locks associated with file resource, remove the node.
if (! pTrav->HasLocks()) {
DeInitAndFreeFileNode(pTrav);
if (pFollow)
pFollow->m_pNext = pNext;
else {
DEBUGCHK(pTrav == m_pFileLockList);
m_pFileLockList = pNext;
}
}
else {
pFollow = pTrav;
}
pTrav = pNext;
}
Unlock();
}
void CWebDavFileLockManager::DeInitAndFreeFileNode(CWebDavFileNode *pFileNode) {
DEBUGCHK(IsLocked());
pFileNode->DeInitFileNode();
svsutil_FreeFixed(pFileNode,m_pfmdFileNodes);
}
BOOL CWebDavFileLockManager::CreateLock(CLockParse *pLockParams, CWebDav *pWebDav) {
CWebDavFileNode *pFileNode = NULL;
CWebDavLock *pLock = NULL;
BOOL fRet = FALSE;
HANDLE hFile = INVALID_HANDLE_VALUE;
WCHAR *szFile = pWebDav->m_pRequest->m_wszPath;
DWORD dwTimeout = 0;
BOOL fCreateFileNode = TRUE;
BOOL fFileCreated = FALSE;
CHAR szLockToken[256]; // response header "Lock-token: <opaquelocktoken:GUID:LockID>"
__int64 iLockId;
if (pLockParams->m_lockShareMode == DAV_LOCK_UNKNOWN) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK fails, client did not set <lockscope> to <exclusive> or <shared>\r\n"));
pWebDav->SetStatus(STATUS_BADREQ);
return FALSE;
}
// Get HTTP timeout header. If timeout not set, then no problem (will use default)
// Function will return FALSE on syntax errors
if (!pWebDav->GetLockTimeout(&dwTimeout))
return FALSE;
if (dwTimeout == 0)
dwTimeout = pWebDav->m_pRequest->m_pWebsite->m_dwDavDefaultLockTimeout;
Lock();
if (NULL != (pFileNode = GetNodeFromFileName(szFile))) {
// found the file already has a lock associated with it.
fCreateFileNode = FALSE;
if (pFileNode->IsExclusiveLock() || (pLockParams->m_lockShareMode == DAV_LOCK_EXCLUSIVE)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK attempted to either gain exclusive ownership of an existing lock, or shared ownership of an exclusive lock for file <%s>\r\n",szFile));
pWebDav->SetStatusAndXMLBody(STATUS_LOCKED);
pWebDav->SendLockTags(pFileNode);
goto done;
}
}
if (fCreateFileNode) {
// file does not have a lock associated with it already, create a new one now.
DEBUGCHK(!pFileNode);
if (INVALID_HANDLE_VALUE == (hFile = CreateFile(szFile,DAV_FILE_ACCESS,DAV_SHARE_ACCESS,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK call to CreateFile(%s) failed, GLE=0x%08x\r\n",szFile,GetLastError()));
pWebDav->SetStatus(GLEtoStatus());
goto done;
}
fFileCreated = (GetLastError() != ERROR_ALREADY_EXISTS);
if (NULL == (pFileNode = (CWebDavFileNode*) svsutil_GetFixed(m_pfmdFileNodes))) {
pWebDav->SetStatus(STATUS_INTERNALERR);
goto done;
}
if (! pFileNode->InitFileNode(szFile,pLockParams->m_lockShareMode,hFile)) {
pWebDav->SetStatus(STATUS_INTERNALERR);
goto done;
}
}
iLockId = GetNextID();
if (! pFileNode->AddLock(pLockParams->m_szLockOwner,pLockParams->m_NSList,iLockId,dwTimeout)) {
pWebDav->SetStatus(STATUS_INTERNALERR);
goto done;
}
// after this point no calls that can fail should be added, or if they are
// be sure to cleanup linked list in 'done:' handeling.
if (fCreateFileNode) {
pFileNode->m_pNext = m_pFileLockList;
m_pFileLockList = pFileNode;
}
if (fFileCreated) {
pWebDav->m_pRequest->m_bufRespHeaders.AppendData(cszLocation,ccLocation);
pWebDav->m_pRequest->m_bufRespHeaders.AppendData(" ",1);
pWebDav->BuildBaseURLFromSourceURL(TRUE);
}
WriteOpaqueLockToken(szLockToken,iLockId,TRUE);
pWebDav->m_pRequest->m_bufRespHeaders.AddHeader(cszLockToken,szLockToken,FALSE);
pWebDav->SetStatusAndXMLBody(fFileCreated ? STATUS_CREATED : STATUS_OK);
pWebDav->SendLockTags(pFileNode);
fRet = TRUE;
done:
DEBUGCHK(IsLocked());
if (!fRet) {
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
if (fCreateFileNode && pFileNode)
pFileNode->DeInitFileNode();
}
#if defined (DEBUG)
else
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: LOCK created lock for file %s, lockID=%I64d, timeout=%d seconds\r\n",szFile,iLockId,dwTimeout));
#endif
Unlock();
return fRet;
}
BOOL CWebDavFileLockManager::CanPerformLockedOperation(WCHAR *szFile1, WCHAR *szFile2, LockIdArray *pLockIDs, int numLocks, CWebDavFileNode **ppFileNode1, CWebDavFileNode **ppFileNode2) {
DEBUGCHK(IsLocked());
BOOL fRet = FALSE;
CWebDavFileNode *pFileNode1 = NULL;
CWebDavFileNode *pFileNode2 = NULL;
pFileNode1 = GetNodeFromFileName(szFile1);
if (szFile2)
pFileNode2 = GetNodeFromFileName(szFile2);
if (numLocks == 0) {
if (pFileNode1 || pFileNode2) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: File %s and/or %s require a lock token for access, but none sent by client\r\n",szFile1,szFile2));
goto done;
}
fRet = TRUE;
goto done;
}
if (!pFileNode1 && !pFileNode2) {
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: CanPerformLockedOperation cannot proceed, neither %s nor %s have any locks associated with them\r\n",szFile1,szFile2));
goto done;
}
if (pFileNode1 && !pFileNode1->HasLockIdInArray(pLockIDs,numLocks)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: File %s has lock, but none of client lockIDS match\r\n",szFile1));
goto done;
}
if (pFileNode2 && !pFileNode2->HasLockIdInArray(pLockIDs,numLocks)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: File %s has lock, but none of client lockIDS match\r\n",szFile2));
goto done;
}
fRet = TRUE;
done:
if (ppFileNode1)
*ppFileNode1 = pFileNode1;
if (ppFileNode2)
*ppFileNode2 = pFileNode2;
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: Found mapping between file names (%s,%s) and Lock tokens client sent\r\n",szFile1,szFile2));
return fRet;
}
void CWebDavFileLockManager::RemoveFileNodeFromLinkedList(CWebDavFileNode *pNode) {
DEBUGCHK(IsLocked());
CWebDavFileNode *pTrav = m_pFileLockList;
CWebDavFileNode *pFollow = NULL;
while (pTrav != pNode) {
pFollow = pTrav;
pTrav = pTrav->m_pNext;
}
DEBUGCHK(pTrav); // we know it's in list
if (pFollow)
pFollow->m_pNext = pTrav->m_pNext;
else {
DEBUGCHK(pTrav == m_pFileLockList);
m_pFileLockList = pTrav->m_pNext;
}
}
BOOL CWebDavFileLockManager::DeleteLock(__int64 iLockId) {
CWebDavFileNode *pFileNode;
CWebDavLock *pLock;
BOOL fRet = FALSE;
Lock();
if (NULL == (pFileNode = GetNodeFromID(iLockId,&pLock)))
goto done;
DEBUGCHK(pLock);
if (pFileNode->DeleteLock(pLock)) {
if (! pFileNode->HasLocks()) {
RemoveFileNodeFromLinkedList(pFileNode);
DeInitAndFreeFileNode(pFileNode);
}
fRet = TRUE;
}
done:
Unlock();
return fRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -