📄 davimpl.cpp
字号:
RESPONSESTATUS rs = STATUS_INTERNALERR;
BOOL fRet = FALSE;
authGranted = m_pRequest->DeterminePermissionGranted(pVRoot->wszUserList,m_pRequest->m_AuthLevelGranted);
if (authGranted < pVRoot->AuthLevel) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: MOVE/COPY fails, destination root requires auth level (%d), user only has access (%d)\r\n",
pVRoot->AuthLevel,authGranted));
rs = STATUS_UNAUTHORIZED;
goto done;
}
if (! (pVRoot->dwPermissions & HSE_URL_FLAGS_WRITE)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: MOVE/COPY fails, virtual root of destination does not support writing\r\n"));
rs = STATUS_FORBIDDEN;
goto done;
}
if ( (!(pVRoot->dwPermissions & HSE_URL_FLAGS_SCRIPT_SOURCE)) && IsPathScript(szPath,pVRoot->ScriptType)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: MOVE/COPY fails, attempting to write to a script resource but no HSE_URL_FLAGS_SCRIPT_SOURCE flags\r\n"));
rs = STATUS_FORBIDDEN;
goto done;
}
fRet = TRUE;
done:
if (! fRet) {
DEBUGCHK(rs != STATUS_INTERNALERR);
SetMultiStatusErrorFromURL(rs,szDestURL);
}
return fRet;
}
BOOL RemoveDirVisitFcn(CWebDav *pThis, WIN32_FIND_DATA *pFindData, DWORD dwContext, WCHAR *szTraversalPath, BOOL fRootDir) {
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav removing empty directories after move operation\r\n"));
DEBUGMSG_VISIT_FCN("RemoveDirVisitFcn");
// When we're doing a move of a collection, run through directory tree
// (depth first) and remove directories of source. Note that we don't delete
// files and RemoveDirectory will fail if files are in sub-dir; this is by
// design because source files may not be legitamitly moved due to error and
// we wouldn't delete them in this case.
if (IsDirectory(pFindData->dwFileAttributes)) {
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav RemoveDirectory(%s) on cleanup from move\r\n",szTraversalPath));
// don't use ZONE_ERROR because it's legit to fail here
if (! RemoveDirectory(szTraversalPath))
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav RemoveDirectory(%s) failed, GLE=0x%08x\r\n",szTraversalPath,GetLastError()));
}
return TRUE;
}
BOOL CWebDav::MoveCopyCollection(CMoveCopyContext *pcContext) {
BOOL fRet = FALSE;
DEBUGCHK(m_pRequest->m_rs == STATUS_OK);
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calls CreateDirectory(%s)\r\n",pcContext->wszDestPath));
if (!CreateDirectory(pcContext->wszDestPath,NULL)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: CreateDirectory(%s) failed, GLE=0x%08x\r\n",pcContext->wszDestPath,GetLastError()));
SetMultiStatusErrorFromURL(GLEtoStatus(),pcContext->szDestURL);
return TRUE;
}
fRet = RecursiveVisitDirs(m_pRequest->m_wszPath,(DWORD)pcContext,::MoveCopyVisitFcn,FALSE);
if (pcContext->fDeleteSrc) {
DEBUGCHK(m_Depth == DEPTH_INFINITY);
// Recursively delete source directories now that we're through.
if (RecursiveVisitDirs(m_pRequest->m_wszPath,0,::RemoveDirVisitFcn,TRUE))
RemoveDirectory(m_pRequest->m_wszPath);
}
return fRet;
}
BOOL DeleteFileAndFileLock(WCHAR *szFile, CWebDavFileNode *pFileNode) {
DEBUGCHK(g_pFileLockManager->IsLocked());
if (pFileNode) {
g_pFileLockManager->RemoveFileNodeFromLinkedList(pFileNode);
g_pFileLockManager->DeInitAndFreeFileNode(pFileNode);
}
if (DeleteFile(szFile))
return TRUE;
DEBUGMSG(ZONE_ERROR,(L"HTTPD: DeleteFile(%s) fails, GLE=0x%08x\r\n",szFile,GetLastError()));
return FALSE;
}
BOOL CWebDav::MoveCopyFile(BOOL fDeleteSrc, WCHAR *wszSrcPath, WCHAR *wszDestPath) {
BOOL fRet;
CWebDavFileNode *pSrcNode = NULL;
CWebDavFileNode *pDestNode = NULL;
HANDLE hSrc = INVALID_HANDLE_VALUE;
HANDLE hDest = INVALID_HANDLE_VALUE;
BOOL fCloseSrc = FALSE;
BOOL fCloseDest = FALSE;
CHAR szBuf[MINBUFSIZE*3];
DWORD dwRead;
DWORD dwDummy;
if (fDeleteSrc) {
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calls MoveFile(%s,%s)\r\n",wszSrcPath,wszDestPath));
fRet = MoveFile(wszSrcPath,wszDestPath);
}
else {
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calls CopyFile(%s,%s,%d)\r\n",wszSrcPath,wszDestPath,(m_Overwrite & OVERWRITE_YES)));
fRet = CopyFile(wszSrcPath,wszDestPath,(m_Overwrite & OVERWRITE_YES) ? FALSE : TRUE);
}
if (fRet)
return TRUE;
// If initial move/copy didn't work, perhaps it's because the file is LOCKED.
// If client sent correct lock tokens along, unlock now.
if (!CheckLockTokens())
goto done;
g_pFileLockManager->Lock();
if (! g_pFileLockManager->CanPerformLockedOperation(wszSrcPath,wszDestPath,&m_lockIds,m_nLockTokens,&pSrcNode,&pDestNode)) {
g_pFileLockManager->Unlock();
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: Client sent lock tokens, but they didn't correspond to file names %s and/or %s, move/copy failed\r\n",wszSrcPath,wszDestPath));
goto done;
}
DEBUGCHK(g_pFileLockManager->IsLocked()); // on success, function leaves manager lockes to ensure pSrcNode and pDestNode are still valid.
DEBUGCHK(pSrcNode || pDestNode); // at least one should be non-NULL on CanPerformLockedOperation() success.
// It's possible that both files aren't lock. If we don't get handle to file from
// an existing lock, create it here.
if (pSrcNode) {
hSrc = pSrcNode->m_hFile;
pSrcNode->SetBusy(TRUE);
}
else {
fCloseSrc = TRUE;
if (INVALID_HANDLE_VALUE == (hSrc = CreateFile(wszSrcPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0))) {
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: CreateFile(%s) on src file during move/copy failed, GLE = 0x%08x\r\n",wszSrcPath,GetLastError()));
goto doneInCS;
}
}
if (pDestNode) {
hDest = pDestNode->m_hFile;
pDestNode->SetBusy(TRUE);
}
else {
fCloseDest = TRUE;
if (INVALID_HANDLE_VALUE == (hDest = CreateFile(wszDestPath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0))) {
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: CreateFile(%s) on dest file during move/copy failed, GLE = 0x%08x\r\n",wszSrcPath,GetLastError()));
goto doneInCS;
}
}
// Since we could be copying megabytes, don't hold lock all this time.
g_pFileLockManager->Unlock();
SetFilePointer(hSrc,0,NULL,FILE_BEGIN);
SetFilePointer(hDest,0,NULL,FILE_BEGIN);
fRet = TRUE;
while (ReadFile(hSrc, szBuf, sizeof(szBuf), &dwRead, 0) && dwRead) {
if (! WriteFile(hDest,szBuf,dwRead,&dwDummy,NULL)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WriteFile(%s) during locked move/copy failed, GLE=0x%08x\r\n",wszDestPath,GetLastError()));
fRet = FALSE;
break;
}
}
SetEndOfFile(hDest);
g_pFileLockManager->Lock();
doneInCS:
DEBUGCHK(g_pFileLockManager->IsLocked());
if (pSrcNode)
pSrcNode->SetBusy(FALSE);
if (pDestNode)
pDestNode->SetBusy(FALSE);
if (fCloseSrc)
MyCloseHandle(hSrc);
if (fCloseDest)
MyCloseHandle(hDest);
if (fRet && fDeleteSrc)
DeleteFileAndFileLock(wszSrcPath,pSrcNode);
g_pFileLockManager->Unlock();
done:
DEBUGCHK(! g_pFileLockManager->IsLocked());
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Failed move/copy %s-->%s, GLE=0x%08x\r\n",wszSrcPath,wszDestPath,GetLastError()));
return fRet;
}
// MoveCopyVisitFcn is called by RecursiveVisitDirs when copying or moving a directory tree.
// It is responsible for creating directories that don't exist, checking to make sure
// if a file is a script that we have permission to access it, and doing copy/move itself.
// szTraversalPath is the path of the directory of the source that we're currently visiting,
// pFindData->cFileName is file name in the source (except when source is a directory
// itself, in which case szTraversalPath contains complete path).
// Per the DAV spec, even if a specific operation fails for whatever reason, we
// keep trying the move/copy.
BOOL CWebDav::MoveCopyVisitFcn(WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szTraversalPath, BOOL fRootDir) {
CMoveCopyContext *pContext = (CMoveCopyContext *)dwContext;
WCHAR szSource[MAX_PATH*2];
WCHAR szDestination[MAX_PATH*2];
DWORD ccWritten;
DWORD ccRelativePath;
BOOL fSuccess = FALSE;
RESPONSESTATUS rs = STATUS_MAX;
DEBUGCHK(! URLHasTrailingSlashW(szTraversalPath));
DEBUGCHK(! URLHasTrailingSlashW(pContext->wszDestPath));
// Node we're visiting must be a subdirectory of the m_wszPath, which is source to do move/copy from.
DEBUGCHK(0 == wcsncmp(szTraversalPath,m_pRequest->m_wszPath,m_pRequest->m_ccWPath));
DEBUGMSG_VISIT_FCN("MoveCopyVisitFcn");
// Buildup the destination path by concatinating the base directory of the
// destination, the part of the current src path we're in (not including its
// base directory).
// tack on relative portion of src dir
ccRelativePath = wcslen(szTraversalPath) - pContext->ccSrcPath;
DEBUGCHK(((int)ccRelativePath >= 0));
// Verify that we're not being requested to overflow szDestination's buffer.
// +2 for up to two '\', +1 for NULL.
DWORD ccMaxOutputRequired = wcslen(pContext->wszDestPath) + ccRelativePath + 2 +
wcslen(pFindData->cFileName) + 1;
if (ccMaxOutputRequired >= SVSUTIL_ARRLEN(szDestination)) {
DEBUGCHK(0); // Calls above us should have caught this sooner.
SetMultiStatusErrorFromDestinationPath(STATUS_INTERNALERR,pFindData,szTraversalPath,fRootDir,
pContext->szDestURL);
return TRUE;
}
// root of dest dir
wcscpy(szDestination,pContext->wszDestPath);
ccWritten = pContext->ccDestPath;
if (ccRelativePath) {
szDestination[ccWritten++] = L'\\';
wcscpy(szDestination+ccWritten,szTraversalPath+pContext->ccSrcPath);
ccWritten += ccRelativePath;
}
if (IsDirectory(pFindData->dwFileAttributes)) {
szDestination[ccWritten++] = L'\\';
wcscpy(szDestination+ccWritten,pFindData->cFileName);
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calls CreateDirectory(%s)\r\n",szDestination));
if (! CreateDirectory(szDestination,NULL)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: CreateDirectory(%s) failed during recursive move/copy operation, GLE=0x%08x\r\n",szDestination,GetLastError()));
SetMultiStatusErrorFromDestinationPath(GLEtoStatus(),pFindData,szTraversalPath,fRootDir,
pContext->szDestURL);
return TRUE;
}
return TRUE;
}
if (( !(pContext->dwSrcPermFlags & HSE_URL_FLAGS_SCRIPT_SOURCE) || !(pContext->dwDestPermFlags & HSE_URL_FLAGS_SCRIPT_SOURCE)) &&
IsPathScript(pFindData->cFileName))
{
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Attempting to access script in recursive move/copy but script access not allowed, ACCESS DENIED\r\n"));
SetMultiStatusErrorFromDestinationPath(STATUS_FORBIDDEN,pFindData,szTraversalPath,fRootDir);
return TRUE;
}
// Add file name to destination.
DEBUGCHK(! URLHasTrailingSlashW(szDestination));
szDestination[ccWritten++] = L'\\';
wcscpy(szDestination+ccWritten,pFindData->cFileName);
DEBUGCHK(wcslen(szDestination) < SVSUTIL_ARRLEN(szDestination));
// Buildup src path
BuildFileName(szSource,szTraversalPath,pFindData->cFileName);
DEBUGCHK(wcslen(szSource) < SVSUTIL_ARRLEN(szSource));
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calls %a on (%s --> %s)\r\n",pContext->fDeleteSrc ? "MOVE" : "COPY",
szSource,szDestination));
if (IsFileNameTooLongForFilesys(szSource) || IsFileNameTooLongForFilesys(szDestination))
rs = STATUS_REQUEST_TOO_LARGE;
else
fSuccess = MoveCopyFile(pContext->fDeleteSrc,szSource,szDestination);
if (!fSuccess) {
PCSTR szURL = pContext->szDestURL;
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav %a on (%s --> %s) fails, GLE=0x%08x\r\n",pContext->fDeleteSrc ? "MOVE" : "COPY",
szSource,szDestination,GetLastError()));
// Check to see if the file is locked, and also which file it is.
if (rs == STATUS_MAX) {
if (IsGLELocked()) {
g_pFileLockManager->Lock();
if (g_pFileLockManager->GetNodeFromFileName(szSource)) {
szURL = m_pRequest->m_pszURL;
rs = STATUS_LOCKED;
}
else if (g_pFileLockManager->GetNodeFromFileName(szDestination)) {
rs = STATUS_LOCKED;
}
g_pFileLockManager->Unlock();
}
else
rs = GLEtoStatus();
}
SetMultiStatusErrorFromDestinationPath(rs,pFindData,szTraversalPath,fRootDir,
szURL);
}
return TRUE;
}
//
// Wrap Filesystem API calls
//
BOOL CWebDav::DavDeleteFile(WCHAR *szFile) {
BOOL fRet = FALSE;
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav calling DeleteFile(%s)\r\n",szFile));
if (DeleteFile(szFile))
return TRUE;
// If delete failed because we have file locked and client sent lock tokens, try
// going through lock manager.
if (CheckLockTokens()) {
CWebDavFileNode *pFileNode;
g_pFileLockManager->Lock();
if (g_pFileLockManager->CanPerformLockedOperation(szFile,NULL,&m_lockIds,m_nLockTokens,&pFileNode,NULL)) {
// client sent a lock-token associated with the file. Delete the lock token, and then the file
fRet = DeleteFileAndFileLock(szFile,pFileNode);
g_pFileLockManager->Unlock();
return fRet;
}
g_pFileLockManager->Unlock();
}
DEBUGCHK(! g_pFileLockManager->IsLocked());
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Failed deleting file %s, GLE=0x%08x\r\n",szFile,GetLastError()));
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -