⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 davlock.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			*szEndOfUrl = CLOSE_URI;

			MyFreeNZ(wszPhysicalPath);

			wszPhysicalPath = m_pRequest->m_pWebsite->m_pVroots->URLAtoPathW((CHAR*)urlBuf.pBuffer);
			szTrav = szEndOfUrl+1;  // skip past the URI and the '>'
		}
//		fFirstPass = FALSE;

		svsutil_SkipWhiteSpace(szTrav);

		if (*szTrav != OPEN_LIST) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send a statement, got %c when expecting %c\r\n",*szTrav,OPEN_LIST));
			SetStatus(STATUS_BADREQ);
			goto done;
		}
		szTrav++; // skip '('
		svsutil_SkipWhiteSpace(szTrav);

		if (NULL == (szEndOfStatement = strchr(szTrav,CLOSE_LIST))) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement ')' character\r\n"));
			SetStatus(STATUS_BADREQ);
			goto done;
		}
		*szEndOfStatement = 0;

		while (szTrav < szEndOfStatement) {
			// A list has one or more state-tokens and/or entity tags.  Parse these now.
			// There are two types of "failure" conditions we can hit during parsing: 
			// an out and out parse error (for instance not closing '>'), which should cause
			// request to fail, send 400.  However we can also have case where a lock doesn't match
			// what we were requested, but this is allowed if it's preceeded by a "NOT" token.

			BOOL fNot;
			BOOL fSuccess = FALSE;

			// NOT statement's scope is for the immediatly proceeding state-token/entity tag.
			if (0 == _strnicmp(szTrav,cszNot,ccNot)) {
				fNot = TRUE;
				szTrav += ccNot;
				svsutil_SkipWhiteSpace(szTrav);
			}
			else 
				fNot = FALSE;

			if (*szTrav == OPEN_LOCK_TOKEN) {
				PSTR szEndToken;
				if (NULL == (szEndToken = strchr(szTrav,CLOSE_LOCK_TOKEN))) {
					DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement '>' character\r\n"));
					SetStatus(STATUS_BADREQ);
					goto done;
				}

				*szEndToken = 0;
				fSuccess = CheckTokenExpression(++szTrav,wszPhysicalPath);
				*szEndToken = CLOSE_LOCK_TOKEN;
				szTrav = szEndToken+1;
			}
			else if (*szTrav == OPEN_ETAG) {
				PSTR szEndEtag;
				if (NULL == (szEndEtag = strchr(szTrav,CLOSE_ETAG))) {
					DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement ']' character\r\n"));
					SetStatus(STATUS_BADREQ);
					goto done;
				}

				*szEndEtag = 0;
				fSuccess = CheckETagExpression(++szTrav,wszPhysicalPath);
				*szEndEtag = CLOSE_ETAG;
				szTrav = szEndEtag+1;
			}
			else {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav \"If:\" headers did not set '<' or '[' inside statement, invalid statement\r\n"));
				SetStatus(STATUS_BADREQ);
				goto done;
			}

			// Either we successfully matched a token but we shouldn't have (NOT before rule)
			// or we didn't match a token and there was not a "NOT" string.
			if ((fSuccess && fNot) || (!fSuccess && !fNot)) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: DAV parsing \"If:\" headers failed, condition not met\r\n"));
				SetStatus(STATUS_PRECONDITION_FAILED);
				goto done;
			}

			svsutil_SkipWhiteSpace(szTrav);
		}

		*szEndOfStatement = CLOSE_LIST;
		szTrav = szEndOfStatement + 1;
		szEndOfStatement  = NULL;

		svsutil_SkipWhiteSpace(szTrav);
	}
	DEBUGCHK((szTrav-szLockHeader) == (int)strlen(szLockHeader));
	
	fRet = TRUE;
done:
	DebugCheckCacheManagerNotLocked();
	MyFreeNZ(szLockHeader);
	MyFreeNZ(wszPhysicalPath);

	if (szEndOfStatement)
		*szEndOfStatement = CLOSE_LIST;
		
	return fRet;
}


// Checks contetns of <...> statement in an "if:" lock header

// Note: Don't set error in here or in helper functions because if "Not"
// prepends the string then failure is expected.
BOOL CWebDav::CheckTokenExpression(PSTR szToken, WCHAR *szPath) {
	svsutil_SkipWhiteSpace(szToken);
	__int64 iLockId;

	if (*szToken == '\"' || *szToken == '<')
		szToken++;

	if (0 == (iLockId = GetLockIDFromOpaqueHeader(szToken)))
		return FALSE;

	if (szPath && ! g_pFileLockManager->IsFileAssociatedWithLockId(szPath,iLockId))
		return FALSE;

	// store the lockId for possible later use during the request.
	if (! m_lockIds.SRealloc(m_nLockTokens+1))
		return FALSE;

	m_lockIds[m_nLockTokens++] = iLockId;
	return TRUE;
}

// Don't set error here because if "not" prepends string then failure is expected.
BOOL CWebDav::CheckETagExpression(PSTR szToken, WCHAR *szPath) {
	svsutil_SkipWhiteSpace(szToken);

	WIN32_FILE_ATTRIBUTE_DATA w32Data;
	WIN32_FILE_ATTRIBUTE_DATA *pData;

	CHAR szETag[MAX_PATH];

	// If szPath is known use it, otherwise default to 
	if (szPath) {
		if (! GetFileAttributesEx(szPath,GetFileExInfoStandard,&w32Data)) {
			DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: GetFileAttributesEx(%s) failed, GLE=0x%08x\r\n",szPath,GetLastError()));
			return FALSE;
		}
		pData = &w32Data;
	}
	else {
		if (! DavGetFileAttributesEx())
			return FALSE;

		pData = &m_fileAttribs;
	}

	GetETagFromFiletime(&pData->ftLastWriteTime,pData->dwFileAttributes,szETag);

	szToken = SkipWeakTagIfNeeded(szToken);
	return (0 == (strcmp(szToken,szETag)));
}

// looks at 'if-match' and 'if-not-match' fields to determine whether to continue processing.
BOOL CWebDav::CheckIfHeaders(void) {
	PSTR szHeader;
	CHAR szETag[256];

	if (IsNull()) {
		// If file doesn't exist, "If-match" headers are invalid.
		if (m_pRequest->FindHttpHeader(cszIf_Match,ccIf_Match)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: resource %s is not existant, so \"if-match\" headers sent cause request to fail\r\n",m_pRequest->m_wszPath));
			SetStatus(STATUS_PRECONDITION_FAILED);
			return FALSE;
		}
		return TRUE;
	}

	if (! DavGetFileAttributesEx()) {
		DEBUGCHK(0);  // resource should be NULL in this case.
		return FALSE;
	}

	GetETagFromFiletime(&m_fileAttribs.ftLastWriteTime,m_fileAttribs.dwFileAttributes,szETag);

	if (szHeader = m_pRequest->FindHttpHeader(cszIf_Match,ccIf_Match)) {
		if (! ETagEqualsHeader(szHeader,szETag)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV request fails because if-match header doesn't match, required etag=%s\r\n",szETag));
			SetStatus(STATUS_PRECONDITION_FAILED);
			return FALSE;
		}
	}

	if (szHeader = m_pRequest->FindHttpHeader(cszIf_None_Match,ccIf_None_Match)) {
		if (ETagEqualsHeader(szHeader,szETag)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV request fails because if-not-match header matches etag=%s\r\n",szETag));
			SetStatus(STATUS_PRECONDITION_FAILED);
			return FALSE;
		}
	}

	return TRUE;
}

// prints out information about lock(s) associated with a file.
BOOL CWebDav::SendLockTags(CWebDavFileNode *pLockedNode, BOOL fPrintPropTag) {
	DebugCheckCacheManagerLocked();
	CHAR szBuf[256];

	BOOL fRet = FALSE;

	CWebDavLock *pLock = pLockedNode->m_pLockList;
	PCSTR szScope = pLockedNode->IsSharedLock() ? cszShared : cszExclusive;

	if (fPrintPropTag) {
		if (! m_bufResp.StartTagNoEncode(cszPropNS,ccPropNS))
			goto done;
	}

	while (pLock) {
		WriteOpaqueLockToken(szBuf,pLock->m_i64LockId,FALSE);

		if (! m_bufResp.StartTag(cszLockDiscovery)    ||
		    ! m_bufResp.StartTag(cszActiveLock)       ||
		    ! m_bufResp.StartTag(cszLockType)         ||
		    ! m_bufResp.SetEmptyElement(cszWrite)     || // spec only supports <write> locks currently
		    ! m_bufResp.EndTag(cszLockType)           ||
		    ! m_bufResp.StartTag(cszLockScope)        ||
		    ! m_bufResp.SetEmptyElement(szScope)      ||
		    ! m_bufResp.EndTag(cszLockScope)          ||
		    ! m_bufResp.StartTag(cszLockTokenTag)     ||
		    ! m_bufResp.StartTag(cszHref)             ||
		    ! m_bufResp.Encode(szBuf)                 ||
		    ! m_bufResp.EndTag(cszHref)               ||
		    ! m_bufResp.EndTag(cszLockTokenTag)) 
		{
			goto done;
		}

		if (pLock->m_szOwner) {
			if (! m_bufResp.BeginBrace()  ||
			    ! m_bufResp.Append(cszOwner,ccOwner)) {
				goto done;
			}

			if (pLock->m_szOwnerNSTags) {
				if (! m_bufResp.AppendCHAR(' ') ||
				    ! m_bufResp.Append(pLock->m_szOwnerNSTags,pLock->m_ccOwnerNSTags)) {
					goto done;
				}
			}

			if (! m_bufResp.CloseBrace() ||
			    ! m_bufResp.Append(pLock->m_szOwner,pLock->m_ccOwner)    ||
			    ! m_bufResp.EndTag(cszOwner)) 
			{
				goto done;
			}
		}

		sprintf(szBuf,"%s%d",cszSecond,pLock->m_dwBaseTimeout);

		if ( !m_bufResp.StartTag(cszDepthTag)                   ||
		     !m_bufResp.Append(csz0,cc0)  ||
		     !m_bufResp.EndTag(cszDepthTag)                     ||
		     !m_bufResp.StartTag(cszTimeoutTag)                 ||
		     !m_bufResp.Encode(szBuf)                           ||
		     !m_bufResp.EndTag(cszTimeoutTag))
		{
			goto done;
		}

		if (! m_bufResp.EndTag(cszActiveLock)          ||
		    ! m_bufResp.EndTag(cszLockDiscovery))
		{
			goto done;
		}

		pLock = pLock->m_pNext;
	}

	if (fPrintPropTag) {
		if (! m_bufResp.EndTag(cszProp))
			goto done;
	}

	fRet = TRUE;
done:
	return fRet;
}

// Certain VERBs want STATUS_CONFLICT on a not found, or can also handle LOCKed.
void CWebDav::SendLockedConflictOrErr(WCHAR *szPath, WCHAR *szAlternatPath) {
	if (SendLockErrorInfoIfNeeded(szPath))
		return;

	if (szAlternatPath && IsFileLocked(szAlternatPath)) {
		SetMultiStatusErrorFromURL(STATUS_LOCKED,m_pRequest->m_pszURL);
		return;
	}

	DWORD dwErr = GetLastError();

	if (dwErr == ERROR_PATH_NOT_FOUND)
		SetStatus(STATUS_CONFLICT);
	else
		SetStatus(GLEtoStatus(dwErr));
}

BOOL CWebDav::IsFileLocked(const WCHAR *szPath) {
	BOOL fRet = FALSE;

	if (IsGLELocked()) {
		g_pFileLockManager->Lock();

		if (g_pFileLockManager->GetNodeFromFileName((WCHAR*)szPath))
			fRet = TRUE;

		g_pFileLockManager->Unlock();
	}
	return fRet;
}

// If a file is locked and we have lock info about it, then send this to the client.
// If we're not locked, return FALSE so that the calling function can set its own error.
BOOL CWebDav::SendLockErrorInfoIfNeeded(WCHAR *szPath) {
	BOOL fRet = FALSE;

	if (IsGLELocked()) {
		g_pFileLockManager->Lock();
		CWebDavFileNode *pFileNode = g_pFileLockManager->GetNodeFromFileName(szPath);
		if (pFileNode) {
			SetStatusAndXMLBody(STATUS_LOCKED);
			SendLockTags(pFileNode);
			fRet = TRUE;
		}
		g_pFileLockManager->Unlock();
	}

	return fRet;
}

//  *********************************************************
//  Implementation of Lock cache manager
//  *********************************************************

static const char cszXMLNS[] = "xmlns:";
static const DWORD ccXMLNS   = SVSUTIL_CONSTSTRLEN(cszXMLNS);

//
//  CWebDavLock
//
BOOL CWebDavLock::InitLock(PSTR szOwner, CNameSpaceMap *pNSMap, __int64 iLockId, DWORD dwBaseTimeout) {
	// m_szOwner is allowed to be NULL, not a required field.
	m_pNext         = NULL;
	m_szOwner = m_szOwnerNSTags = NULL;

	if (szOwner && (NULL == (m_szOwner = MySzDupA(szOwner))))
		return FALSE;

	if (m_szOwner)
		m_ccOwner = strlen(m_szOwner);
	else
		m_ccOwner = 0;

	// Setup NameSpace prefix->URI tags that are put in <owner> XML tag.
	if (m_szOwner && pNSMap) {
		CNameSpaceMap *pTrav = pNSMap;
		int iLenRequired = 0;
		int iOffset      = 0;

		while (pTrav) {
			iLenRequired += MyW2UTF8(pTrav->m_szPrefix,0,0) + MyW2UTF8(pTrav->m_szURI,0,0) + ccXMLNS + 15;
			pTrav = pTrav->m_pNext;
		}

		if (NULL == (m_szOwnerNSTags = MySzAllocA(iLenRequired)))
			return FALSE;

		pTrav = pNSMap;

		while (pTrav) {
			// If there are multiple URI's with the same Namespace, use the last one
			// put into the list for the URI.
			CNameSpaceMap *pNode = pTrav;
			while (pNode->m_pChild)
				pNode = pNode->m_pChild;
			
			
			// The code below is effectively doing this sprintf.  Don't use sprintf
			// because we want UTF8 conversion if it's available, sprintf does CP_ACP on %S.
			// iOffset += sprintf(m_szOwnerNSTags+iOffset," %s%S=\"%S\"",cszXMLNS,pTrav->m_szPrefix,pNode->m_szURI);

			// don't spit out ' ' on 1st pass.
			if (iOffset != 0)
				m_szOwnerNSTags[iOffset++] = ' ';

			strcpy(m_szOwnerNSTags+iOffset,cszXMLNS);
			iOffset += ccXMLNS;

			iOffset += MyW2UTF8(pTrav->m_szPrefix,m_szOwnerNSTags+iOffset,iLenRequired-iOffset) - 1;
			m_szOwnerNSTags[iOffset++] = '=';
			m_szOwnerNSTags[iOffset++] = '\"';

			iOffset += MyW2UTF8(pNode->m_szURI,m_szOwnerNSTags+iOffset,iLenRequired-iOffset) - 1;
			m_szOwnerNSTags[iOffset++] = '\"';

			pTrav = pTrav->m_pNext;
		}
		m_szOwnerNSTags[iOffset++] = 0;

		m_ccOwnerNSTags = strlen(m_szOwnerNSTags);
		DEBUGCHK(m_ccOwnerNSTags < (DWORD)iLenRequired);
	}
	else {
		m_ccOwnerNSTags = 0;
	}

	m_i64LockId     = iLockId;
	SetTimeout(dwBaseTimeout);

	return TRUE;
}

void CWebDavLock::SetTimeout(DWORD dwSecondsToLive) {
	DEBUGCHK(dwSecondsToLive != 0);

	__int64 ft;
	GetCurrentFT((FILETIME*)&ft);
	m_ftExpires = ft + (dwSecondsToLive*1000*FILETIME_TO_MILLISECONDS);
	m_dwBaseTimeout = dwSecondsToLive;
}

void CWebDavLock::DeInitLock(void) {
	MyFreeNZ(m_szOwner);
	MyFreeNZ(m_szOwnerNSTags);
}

//
//  CWebDavFileNode
//
BOOL CWebDavFileNode::InitFileNode(WCHAR *szFile, DAV_LOCK_SHARE_MODE lockShareMode, HANDLE hFile) {
	DebugCheckCacheManagerLocked();
	DEBUGCHK(IsValidLockState(lockShareMode));
	DEBUGCHK(hFile != INVALID_HANDLE_VALUE);

	if (NULL == (m_szFileName = MySzDupW(szFile)))
		return FALSE;

	m_lockShareMode  = lockShareMode;
	m_hFile          = hFile;
	m_pNext          = NULL;
	m_pLockList      = NULL;
	m_fBusy          = FALSE;
	return TRUE;
}

void CWebDavFileNode::DeInitFileNode(void) {
	DebugCheckCacheManagerLocked();
	CWebDavLock *pNext;

	while (m_pLockList) {
		pNext = m_pLockList->m_pNext;
		DeInitAndFreeLock(m_pLockList);
		m_pLockList = pNext;
	}

	MyFreeNZ(m_szFileName);
	MyCloseHandle(m_hFile);
}

BOOL CWebDavFileNode::AddLock(PSTR szOwner, CNameSpaceMap *pNSMap, __int64 iLockId, DWORD dwBaseTimeout) {
	CWebDavLock *pLock = g_pFileLockManager->AllocFixedLock();
	if (!pLock)
		return FALSE;

	if (! pLock->InitLock(szOwner,pNSMap,iLockId,dwBaseTimeout)) {
		g_pFileLockManager->FreeFixedLock(pLock);
		return FALSE;
	}

	pLock->m_pNext = m_pLockList;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -