WindowsXP-SP1/admin/pchealth/sr/restmap/reslist.cpp
2020-09-30 16:53:49 +02:00

1436 lines
36 KiB
C++

/******************************************************************************
*
* Copyright (c) 1999 Microsoft Corporation
*
* Module Name:
* reslist.cpp
*
* Abstract:
* This file contains the implementation of Restore List.
*
* Revision History:
* Brijesh Krishnaswami (brijeshk) 06/02/00
* created
*
*
******************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include "restmap.h"
#include "reslist.h"
#include "shlwapi.h"
#include "utils.h"
#ifdef THIS_FILE
#undef THIS_FILE
#endif
static char __szTraceSourceFile[] = __FILE__;
#define THIS_FILE __szTraceSourceFile
#include "dbgtrace.h"
// copy acl
void
CopyAcl(CNode *pNode, BYTE *pbAcl, DWORD cbAcl, BOOL fAclInline)
{
if (pbAcl)
{
HEAP_FREE(pNode->m_pbAcl);
pNode->m_pbAcl = (BYTE *) HEAP_ALLOC(cbAcl);
if (pNode->m_pbAcl)
memcpy(pNode->m_pbAcl, pbAcl, cbAcl);
pNode->m_cbAcl = cbAcl;
pNode->m_fAclInline = fAclInline;
}
}
//
// GetReverseOperation : This function will return the reverse operation of the
// current changelog operation.
//
DWORD
GetReverseOperation(
DWORD dwOpr
)
{
DWORD dwRestoreOpr = OPR_UNKNOWN;
switch( dwOpr )
{
case OPR_FILE_DELETE:
dwRestoreOpr = OPR_FILE_ADD;
break;
case OPR_FILE_ADD :
dwRestoreOpr = OPR_FILE_DELETE;
break;
case OPR_FILE_MODIFY:
dwRestoreOpr = OPR_FILE_MODIFY;
break;
case OPR_SETATTRIB:
dwRestoreOpr = OPR_SETATTRIB;
break;
case OPR_FILE_RENAME:
dwRestoreOpr = OPR_FILE_RENAME;
break;
case OPR_DIR_RENAME:
dwRestoreOpr = OPR_DIR_RENAME;
break;
case OPR_DIR_DELETE:
dwRestoreOpr = OPR_DIR_CREATE;
break;
case OPR_DIR_CREATE:
dwRestoreOpr = OPR_DIR_DELETE;
break;
case OPR_SETACL:
dwRestoreOpr = OPR_SETACL;
break;
default:
dwRestoreOpr = OPR_UNKNOWN;
break;
}
return dwRestoreOpr;
}
//
// AllocateNode : allocates a list node
//
CNode *
AllocateNode(
LPWSTR pPath1,
LPWSTR pPath2)
{
CNode * pNode = NULL;
BOOL fRet = FALSE;
if (! pPath1)
{
fRet = TRUE; // BUGBUG - is this a valid case?
goto Exit;
}
pNode = (CNode *) HEAP_ALLOC( sizeof(CNode) );
if (! pNode )
goto Exit;
// all pointers set to NULL
if ( pPath1 )
STRCOPY(pNode->m_pPath1, pPath1);
if ( pPath2 )
STRCOPY(pNode->m_pPath2, pPath2);
pNode->m_dwOperation = OPR_UNKNOWN;
pNode->m_dwAttributes = 0xFFFFFFFF;
pNode->m_pPrev = NULL;
pNode->m_pNext = NULL;
fRet = TRUE;
Exit:
if (! fRet)
{
// something failed, so cleanup
FreeNode(pNode);
pNode = NULL;
}
return pNode;
}
//
// FreeNode : This function frees a list node
//
VOID
FreeNode(
CNode * pNode
)
{
if ( pNode )
{
HEAP_FREE(pNode->m_pPath1);
HEAP_FREE(pNode->m_pPath2);
HEAP_FREE(pNode->m_pszTemp);
HEAP_FREE(pNode->m_pbAcl);
HEAP_FREE(pNode);
}
}
//
// Looks at an existing node and the new operation coming and decides
// if they can be merged or not.
//
BOOL
CanMerge(
DWORD dwExistingOpr,
DWORD dwNewOpr,
DWORD dwFlags
)
{
BOOL fRet = FALSE;
//
// Don't optimize directory renames
//
if ( OPR_DIR_RENAME == dwExistingOpr ||
OPR_DIR_RENAME == dwNewOpr )
goto Exit;
//
// Don't optimize for rename if the node we find is a delete node
// and the current opr is rename. In such cases since rename is
// dependent on deletion to succeed.
// Example : A -> B , Create A should generate Delete A, B -> A
//
if ( IsRename(dwNewOpr) &&
( OPR_DIR_DELETE == dwExistingOpr || OPR_FILE_DELETE == dwExistingOpr )
)
goto Exit;
//
// Also Del A, A->B should not merge this can happen if the file is
// getting renamed out of the directory and back.
//
if ( IsRename(dwExistingOpr) &&
( OPR_DIR_DELETE == dwNewOpr ||
OPR_DIR_CREATE == dwNewOpr ||
OPR_FILE_DELETE == dwNewOpr )
)
goto Exit;
if ( IsRename(dwNewOpr) &&
( OPR_DIR_DELETE == dwExistingOpr ||
OPR_DIR_CREATE == dwExistingOpr )
)
goto Exit;
//
// Dir + File operations don't merge
//
if ( ( OPR_FILE_DELETE == dwExistingOpr ||
OPR_FILE_MODIFY == dwExistingOpr ||
OPR_FILE_ADD == dwExistingOpr ) &&
( OPR_DIR_CREATE == dwNewOpr ||
OPR_DIR_DELETE == dwNewOpr )
)
goto Exit;
if ( ( OPR_FILE_DELETE == dwNewOpr ||
OPR_FILE_ADD == dwNewOpr ||
OPR_FILE_MODIFY == dwNewOpr ) &&
( OPR_DIR_CREATE == dwExistingOpr ||
OPR_DIR_DELETE == dwExistingOpr )
)
goto Exit;
// can merge
fRet = TRUE;
Exit:
return fRet;
}
//
// CRestoreList implementation.
//
CRestoreList::CRestoreList()
{
m_pListHead = m_pListTail = NULL;
}
CRestoreList::~CRestoreList()
{
//
// Destroy the list
//
CNode * pNodeNext = m_pListHead;
CNode * pNode = NULL;
while( pNodeNext )
{
pNode = pNodeNext;
pNodeNext = pNodeNext->m_pNext;
FreeNode( pNode );
}
}
//
// AddNode : Alocates and Adds a tree node to the restore tree.
//
CNode *
CRestoreList::AppendNode(
LPWSTR pPath1,
LPWSTR pPath2)
{
CNode * pNode = NULL;
if ( pPath1 )
{
pNode = AllocateNode( pPath1, pPath2 );
if ( !pNode )
{
goto Exit;
}
if( m_pListHead )
{
CNode * pPrevNode = m_pListTail;
pPrevNode->m_pNext = pNode;
pNode->m_pPrev = pPrevNode;
pNode->m_pNext = NULL;
m_pListTail = pNode;
}
else
{
m_pListHead = pNode;
m_pListTail = pNode;
pNode->m_pPrev = NULL;
pNode->m_pNext = NULL;
}
}
Exit:
return pNode;
}
//
// RemoveNode: Removes a node from the list
//
CNode *
CRestoreList::RemoveNode(
CNode * pNode
)
{
if ( pNode )
{
CNode * pPrevNode = pNode->m_pPrev;
CNode * pNextNode = pNode->m_pNext;
if (pPrevNode)
{
pPrevNode->m_pNext = pNode->m_pNext;
}
if (pNextNode)
{
pNextNode->m_pPrev = pNode->m_pPrev;
}
if ( pNode == m_pListHead )
{
m_pListHead = pNextNode;
}
if ( pNode == m_pListTail )
{
m_pListTail = pPrevNode;
}
pNode->m_pPrev = NULL;
pNode->m_pNext = NULL;
}
return pNode;
}
//
// GetLastNode : finds the most recent candidate to merge
//
CNode *
CRestoreList::GetLastNode(
LPWSTR pPath1,
LPWSTR pPath2,
BOOL fFailOnPrefixMatch
)
{
CNode * pNode = NULL;
pNode = m_pListTail;
while( pNode )
{
//
// If the node has invalid operation skip it.
//
if ( OPR_UNKNOWN == pNode->m_dwOperation )
{
pNode = pNode->m_pPrev;
continue;
}
//
// If node matches, return it
//
if (0 == lstrcmpi(pPath1, pNode->m_pPath1))
goto Exit;
//
// Check for a dependent rename operation, if found we should not
// merge beyond it.
//
if ( pPath1 &&
IsRename(pNode->m_dwOperation) &&
0 == lstrcmpi(pPath1, pNode->m_pPath2) )
{
pNode = NULL;
goto Exit;
}
//
// Check for swap conditions, if so don't do any optimization.
//
if ( pPath2 &&
IsRename(pNode->m_dwOperation) &&
0 == lstrcmpi(pPath2, pNode->m_pPath2) )
{
pNode = NULL;
goto Exit;
}
//
// Check if the entire path matches as a prefix, in such a
// case we should fail search because an operation under that
// directory is found.
//
if ( fFailOnPrefixMatch )
{
//
// Check if entire path matches a prefix that means this
// directory has other operations so don't merge.
//
if (StrStrI(pNode->m_pPath1, pPath1))
{
pNode = NULL;
goto Exit;
}
if ( IsRename(pNode->m_dwOperation) &&
StrStrI(pNode->m_pPath2, pPath1))
{
pNode = NULL;
goto Exit;
}
//
// Check if prefix of the path matches with the full path in
// nodelist, means we are moving across directory's lifespan.
// ToDo: Only check for directory life operations
//
if ( IsRename(pNode->m_dwOperation) ||
OPR_DIR_DELETE == pNode->m_dwOperation ||
OPR_DIR_CREATE == pNode->m_dwOperation )
{
if ( StrStrI(pPath1, pNode->m_pPath1) )
{
pNode = NULL;
goto Exit;
}
if ( IsRename(pNode->m_dwOperation) &&
StrStrI(pPath1, pNode->m_pPath2) )
{
pNode = NULL;
goto Exit;
}
if ( pPath2 )
{
if ( StrStrI(pPath2, pNode->m_pPath1) )
{
pNode = NULL;
goto Exit;
}
if ( IsRename(pNode->m_dwOperation) &&
StrStrI(pPath2, pNode->m_pPath2) )
{
pNode = NULL;
goto Exit;
}
}
}
}
pNode = pNode->m_pPrev;
}
Exit:
//
// We have found a potential merge candidate, now check if this is
// a rename node and dest prefix has any operations on it.
//
if ( pNode && IsRename(pNode->m_dwOperation))
{
CNode * pTmpNode = m_pListTail;
while( pTmpNode && pTmpNode != pNode )
{
if ( IsRename(pTmpNode->m_dwOperation) ||
OPR_DIR_DELETE == pTmpNode->m_dwOperation ||
OPR_DIR_CREATE == pTmpNode->m_dwOperation )
{
if ( StrStrI(pNode->m_pPath2, pTmpNode->m_pPath1) )
{
pNode = NULL;
break;
}
if ( IsRename(pTmpNode->m_dwOperation) &&
StrStrI(pNode->m_pPath2, pTmpNode->m_pPath2) )
{
pNode = NULL;
break;
}
}
pTmpNode = pTmpNode->m_pPrev;
}
}
return pNode;
}
//
// CopyNode : Copies node information, destination opr, copy data, etc.
//
BOOL
CRestoreList::CopyNode(
CNode * pSrcNode,
CNode * pDesNode,
BOOL fReplacePPath2
)
{
BOOL fRet = FALSE;
if (pSrcNode && pDesNode)
{
pSrcNode->m_dwOperation = pDesNode->m_dwOperation ;
pSrcNode->m_dwAttributes = pDesNode->m_dwAttributes;
STRCOPY(pSrcNode->m_pszTemp, pDesNode->m_pszTemp);
CopyAcl(pSrcNode, pDesNode->m_pbAcl, pDesNode->m_cbAcl, pDesNode->m_fAclInline);
if ( IsRename(pDesNode->m_dwOperation) && fReplacePPath2 )
{
HEAP_FREE( pSrcNode->m_pPath2 );
pSrcNode->m_pPath2 = pDesNode->m_pPath2;
pDesNode->m_pPath2 = NULL;
}
fRet = TRUE;
}
return fRet;
}
//
// CreateRestoreNode : Creates appropriate restore node
//
CRestoreList::CreateRestoreNode(
CNode * pNode,
DWORD dwOpr,
DWORD dwAttr,
DWORD dwFlags,
LPWSTR pTmpFile,
LPWSTR pPath1,
LPWSTR pPath2,
BYTE* pbAcl,
DWORD cbAcl,
BOOL fAclInline)
{
BOOL fRet = FALSE;
if (pNode)
{
fRet = TRUE;
DWORD dwRestoreOpr = GetReverseOperation( dwOpr );
//
// If Source / Dest paths are same then remove this just
// added node.
//
if ( IsRename(dwRestoreOpr) &&
0 == lstrcmpi(pNode->m_pPath1,
pNode->m_pPath2) )
{
RemoveNode( pNode );
FreeNode( pNode );
goto Exit;
}
//
// Rename optimizations should not be done for directories.
//
if ( OPR_FILE_RENAME == dwRestoreOpr )
{
//
// Check if the des node already exists in the tree, if so
// copy all the data from that node and delete it. Current
// node effectively represents that node.
//
DWORD dwCurNodeOpr = pNode->m_dwOperation;
CNode *pNodeDes = GetLastNode( pPath2, pPath1, TRUE );
if (pNodeDes &&
OPR_UNKNOWN != pNodeDes->m_dwOperation)
{
//
// Check for Cycle if so remove the current node also
//
if ( OPR_FILE_RENAME == pNodeDes->m_dwOperation &&
!lstrcmpi (pNode->m_pPath1,
pNodeDes->m_pPath2) )
{
//
// The existing node may be a hybrid one so preserve the
// hybrid operations cancel only rename
//
if (! pNodeDes->m_pszTemp &&
pNodeDes->m_dwAttributes == 0xFFFFFFFF &&
pNodeDes->m_pbAcl == NULL)
{
//
// Not a hybrid node - remove it.
//
RemoveNode( pNodeDes );
FreeNode( pNodeDes );
}
else
{
//
// Hybrid Node so change the node to the other
// operations only.
//
HEAP_FREE( pNodeDes->m_pPath1 );
pNodeDes->m_pPath1 = pNodeDes->m_pPath2;
pNodeDes->m_pPath2 = NULL;
pNodeDes->m_dwOperation = OPR_SETATTRIB;
if (pNodeDes->m_pbAcl)
{
pNodeDes->m_dwOperation = OPR_SETACL;
}
if (pNodeDes->m_pszTemp)
{
pNodeDes->m_dwOperation = OPR_FILE_MODIFY;
}
}
//
// Remove the just add node as the operation cancels
// returning false will have that effect
fRet = FALSE;
goto Exit;
}
//
// Remove the matching node from the list
//
RemoveNode( pNodeDes );
//
// Merge the matching node into the current rename node
//
CopyNode( pNode, pNodeDes, TRUE );
//
// Since all the information for modify/attrib/acl is
// copied over, change the opr to rename.
//
if (pNodeDes->m_dwOperation == OPR_SETATTRIB ||
pNodeDes->m_dwOperation == OPR_SETACL ||
pNodeDes->m_dwOperation == OPR_FILE_MODIFY)
{
pNode->m_dwOperation = dwRestoreOpr;
STRCOPY(pNode->m_pPath2, pPath2);
}
//
// If current opr on the node was delete and the newly
// copied operation is create we need to merge these and
// and change the operation to modify
//
// BUGBUG - will this code ever be executed?
// dwCurNodeOpr always seems to be OPR_UNKNOWN
if ( OPR_FILE_ADD == pNodeDes->m_dwOperation &&
OPR_FILE_DELETE == dwCurNodeOpr )
{
pNode->m_dwOperation = OPR_FILE_MODIFY;
}
if ( OPR_DIR_CREATE == pNodeDes->m_dwOperation &&
OPR_DIR_DELETE == dwCurNodeOpr )
{
pNode->m_dwOperation = OPR_SETATTRIB;
}
//
// If the operation is changed from a rename then pPath2 should
// not exist
//
if ( OPR_FILE_RENAME != pNode->m_dwOperation )
{
if ( pNode->m_pPath2 )
{
HEAP_FREE(pNode->m_pPath2);
pNode->m_pPath2 = NULL ;
}
}
FreeNode( pNodeDes );
goto Exit;
}
}
//
// Copy the necessary information into this node.
//
pNode->m_dwOperation = dwRestoreOpr;
pNode->m_dwAttributes = dwAttr;
STRCOPY(pNode->m_pszTemp, pTmpFile);
CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
}
Exit:
return fRet;
}
//
// MergeRestoreNode : Merge the new information into the current retore node
//
BOOL
CRestoreList::MergeRestoreNode(
CNode * pNode,
DWORD dwOpr,
DWORD dwAttr,
DWORD dwFlags,
LPWSTR pTmpFile,
LPWSTR pPath1,
LPWSTR pPath2,
BYTE* pbAcl,
DWORD cbAcl,
BOOL fAclInline)
{
BOOL fRet = FALSE;
if (pNode)
{
DWORD dwRestoreOpr = GetReverseOperation( dwOpr );
// note that dwOpr cannot be a rename operation,
// because we handle that separately in CreateRestoreNode
ASSERT( ! IsRename(dwOpr) );
switch( dwOpr )
{
case OPR_FILE_ADD :
{
//
// If current opr is add and the node already encountered a
// delete opr then remove this node because this is a no-op
//
if ( OPR_FILE_ADD == pNode->m_dwOperation )
{
RemoveNode( pNode );
FreeNode ( pNode );
goto Exit;
}
if ( IsRename(pNode->m_dwOperation) )
{
//
// Change the original node to a delete operation, to
// retain proper order.
//
pNode->m_dwOperation = OPR_FILE_DELETE;
//
// Delete operation should be generated on PPath2
//
if (pNode->m_pPath1)
{
HEAP_FREE( pNode->m_pPath1);
pNode->m_pPath1 = NULL;
}
if (pNode->m_pPath2)
{
pNode->m_pPath1 = pNode->m_pPath2;
pNode->m_pPath2 = NULL;
}
goto Exit;
}
break;
}
case OPR_FILE_DELETE :
{
//
// Delete followd by an add should result in modify
//
if (OPR_FILE_DELETE == pNode->m_dwOperation)
{
pNode->m_dwOperation = OPR_FILE_MODIFY;
pNode->m_dwAttributes = dwAttr;
STRCOPY(pNode->m_pszTemp, pTmpFile);
CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
goto Exit;
}
break;
}
case OPR_FILE_MODIFY:
{
//
// Copy the modified file copy location, don't change
// the current restore operation.
//
if ( OPR_FILE_ADD == pNode->m_dwOperation ||
IsRename(pNode->m_dwOperation) )
{
STRCOPY(pNode->m_pszTemp, pTmpFile);
goto Exit;
}
break;
}
case OPR_SETATTRIB:
{
//
// Don't change the current restore operation just set the attr.
//
if ( OPR_UNKNOWN != pNode->m_dwOperation )
{
pNode->m_dwAttributes = dwAttr;
goto Exit;
}
break;
}
case OPR_SETACL:
{
// setacl followed by any op
// just copy the acl to the new op
if (OPR_UNKNOWN != pNode->m_dwOperation)
{
CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
goto Exit;
}
break;
}
case OPR_DIR_DELETE :
{
//
// if Dir delete followed by a dir create then this
// operation should condense to set attrib + setacl
if ( OPR_DIR_DELETE == pNode->m_dwOperation )
{
//
// Need to change the oprn to set attrib if
// Attribute changed
//
pNode->m_dwOperation = OPR_SETATTRIB;
pNode->m_dwAttributes = dwAttr;
CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
goto Exit;
}
break;
}
case OPR_DIR_CREATE :
{
if ( OPR_DIR_CREATE == pNode->m_dwOperation )
{
RemoveNode( pNode );
FreeNode( pNode );
goto Exit;
}
if ( IsRename(pNode->m_dwOperation) )
{
//
// Check if the existing node has some file operations
// afterwards then don't optimize
//
if ( GetLastNode(
pNode->m_pPath1,
NULL,
TRUE) )
{
//
// Change the last node to a delete operation, to
// retain proper order.
//
pNode->m_dwOperation = OPR_DIR_DELETE;
//
// Delete operation should be generated on PPath2
//
if (pNode->m_pPath1)
{
HEAP_FREE( pNode->m_pPath1);
pNode->m_pPath1 = NULL;
}
if (pNode->m_pPath2)
{
pNode->m_pPath1 = pNode->m_pPath2;
pNode->m_pPath2 = NULL;
}
}
else
{
CNode * pNewNode = NULL;
//
// Create a new dir delete node
//
if (pNewNode = AppendNode(pPath1, pPath2) )
{
fRet = CreateRestoreNode(
pNewNode,
dwOpr,
dwAttr,
dwFlags,
pTmpFile,
pPath1,
pPath2,
pbAcl,
cbAcl,
fAclInline);
}
}
goto Exit;
}
break;
}
}
pNode->m_dwOperation = dwRestoreOpr;
//
// Change the node's attribute only if the new attrib exists
//
if (dwAttr != 0xFFFFFFFF)
pNode->m_dwAttributes = dwAttr;
STRCOPY(pNode->m_pszTemp, pTmpFile);
CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
}
Exit:
return TRUE;
}
BOOL
CRestoreList::CheckIntegrity(
LPWSTR pszDrive,
DWORD dwOpr,
DWORD dwAttr,
DWORD dwFlags,
LPWSTR pTmpFile,
LPWSTR pPath1,
LPWSTR pPath2,
BYTE * pbAcl,
DWORD cbAcl,
BOOL fAclInline)
{
BOOL fRet = TRUE;
WCHAR szPath[MAX_PATH];
// source name MUST be present
if (! pPath1)
{
fRet = FALSE;
goto done;
}
// if acl is present and it's not inline,
// then temp file must exist
if (pbAcl && ! fAclInline)
{
MakeRestorePath(szPath, pszDrive, (LPWSTR) pbAcl);
if (-1 == GetFileAttributes(szPath))
{
fRet = FALSE;
goto done;
}
}
switch (dwOpr)
{
case OPR_FILE_RENAME:
case OPR_DIR_RENAME:
// renames should have dest path and no temp file
if (! pPath2 || pTmpFile)
fRet = FALSE;
break;
case OPR_FILE_MODIFY:
// modify should not have dest path but must have temp file
if (pPath2 || ! pTmpFile)
{
fRet = FALSE;
break;
}
// and the temp file must exist inside the datastore
MakeRestorePath(szPath, pszDrive, pTmpFile);
if (-1 == GetFileAttributes(szPath))
{
fRet = FALSE;
break;
}
break;
case OPR_SETACL:
// acl operation should have acl (either inline or not)
if (! pbAcl)
{
fRet = FALSE;
break;
}
default:
break;
}
done:
return fRet;
}
// AddMergeElement : Adds or merge the current element as appropriate
//
BOOL
CRestoreList::AddMergeElement(
LPWSTR pszDrive,
DWORD dwOpr,
DWORD dwAttr,
DWORD dwFlags,
LPWSTR pTmpFile,
LPWSTR pPath1,
LPWSTR pPath2,
BYTE * pbAcl,
DWORD cbAcl,
BOOL fAclInline)
{
BOOL fRet = FALSE;
CNode * pNode = NULL;
// check to see if the entry is consistent
fRet = CheckIntegrity(pszDrive,
dwOpr,
dwAttr,
dwFlags,
pTmpFile,
pPath1,
pPath2,
pbAcl,
cbAcl,
fAclInline);
if (FALSE == fRet)
{
ASSERT(-1);
goto Exit;
}
if ( pPath1 )
{
if (
//
// Merge for renames are handled inside the Create/Merge funcs
//
! IsRename(dwOpr) &&
//
// Merge should only be allowed within directory life, check
// node paths to see if there are any directory life oprs.
//
( pNode = GetLastNode( pPath1, pPath2, TRUE ) ) &&
CanMerge( pNode->m_dwOperation , dwOpr, dwFlags )
)
{
fRet = MergeRestoreNode(
pNode,
dwOpr,
dwAttr,
dwFlags,
pTmpFile,
pPath1,
pPath2,
pbAcl,
cbAcl,
fAclInline);
if (!fRet)
goto Exit;
}
else
{
if (pNode = AppendNode(pPath1, pPath2) )
{
fRet = CreateRestoreNode(
pNode,
dwOpr,
dwAttr,
dwFlags,
pTmpFile,
pPath1,
pPath2,
pbAcl,
cbAcl,
fAclInline);
if (!fRet)
{
//
// We failed to create the node properly, free this node
//
RemoveNode( pNode );
FreeNode( pNode );
//
// We still want to continue
//
fRet = TRUE;
goto Exit;
}
}
}
}
Exit:
return fRet;
}
//
// GenerateRestoreMap : Walk the tree and generates the restore map.
//
BOOL
CRestoreList::GenerateRestoreMap (
HANDLE hFile
)
{
BOOL fRet = FALSE;
if (hFile)
{
CNode * pNode = m_pListHead;
while (pNode)
{
if (! GenerateOperation( pNode , hFile ))
goto Exit;
pNode = pNode->m_pNext;
}
fRet = TRUE;
}
Exit:
return fRet;
}
//
// GenerateRenameEntry : Callback to write out the renames
//
BOOL
CRestoreList::GenerateRenameEntry(
CNode * pNode ,
HANDLE hFile
)
{
BOOL fRet = FALSE;
if( !pNode || ! IsRename(pNode->m_dwOperation) )
goto Exit;
//
// Check if this rename is no-op , src/des are the same
//
if ( IsRename(pNode->m_dwOperation) &&
lstrcmpi(pNode->m_pPath1, pNode->m_pPath2) == 0)
{
goto SkipMainNodeEntry;
}
// add rename operation
fRet = AppendRestoreMapEntry(
hFile,
pNode->m_dwOperation,
0xFFFFFFFF,
NULL,
pNode->m_pPath1,
pNode->m_pPath2,
NULL,
0,
0);
SkipMainNodeEntry:
// add modify operation if temp file exists
if ( pNode->m_pszTemp )
{
fRet = AppendRestoreMapEntry(
hFile,
OPR_FILE_MODIFY,
0xFFFFFFFF,
pNode->m_pszTemp,
pNode->m_pPath1,
NULL,
NULL,
0,
0);
}
// add setattrib operation if attrib exists
if ( pNode->m_dwAttributes != 0xFFFFFFFF &&
pNode->m_dwAttributes != FILE_ATTRIBUTE_DIRECTORY )
{
fRet = AppendRestoreMapEntry(
hFile,
OPR_SETATTRIB,
pNode->m_dwAttributes,
NULL,
pNode->m_pPath1,
NULL,
NULL,
0,
0);
}
// add setacl operation if acl exists
if ( pNode->m_pbAcl != NULL &&
pNode->m_cbAcl != 0)
{
fRet = AppendRestoreMapEntry(
hFile,
OPR_SETACL,
0xFFFFFFFF,
NULL,
pNode->m_pPath1,
NULL,
pNode->m_pbAcl,
pNode->m_cbAcl,
pNode->m_fAclInline);
}
Exit:
return fRet;
}
BOOL
CRestoreList::GenerateOperation(
CNode * pNode ,
HANDLE hFile
)
{
BOOL fRet = FALSE;
BYTE bData[4096];
RestoreMapEntry * pResEntry = (RestoreMapEntry *)bData;
if( !pNode || OPR_UNKNOWN == pNode->m_dwOperation)
goto Exit;
if (IsRename(pNode->m_dwOperation) )
{
fRet = GenerateRenameEntry( pNode, hFile );
goto Exit;
}
//
// Generate operations for Add/Modify/SetAttrib
//
// ensure that each persisted entry contains only necessary data
// e.g. a setattrib entry will not contain a temp filename, or acl
fRet = AppendRestoreMapEntry(
hFile,
pNode->m_dwOperation,
(pNode->m_dwOperation == OPR_SETATTRIB) ? pNode->m_dwAttributes : 0xFFFFFFFF,
(pNode->m_dwOperation == OPR_FILE_MODIFY ||
pNode->m_dwOperation == OPR_FILE_ADD) ? pNode->m_pszTemp : NULL,
pNode->m_pPath1,
NULL, // pPath2 should matter only for renames, which are handled separately
(pNode->m_dwOperation == OPR_SETACL) ? pNode->m_pbAcl : NULL,
(pNode->m_dwOperation == OPR_SETACL) ? pNode->m_cbAcl : 0,
(pNode->m_dwOperation == OPR_SETACL) ? pNode->m_fAclInline : 0);
//
// Generate an explicit set attrib operation
// entries except set attrib itself and delete.
//
if ( OPR_SETATTRIB != pNode->m_dwOperation &&
OPR_FILE_DELETE != pNode->m_dwOperation &&
OPR_DIR_DELETE != pNode->m_dwOperation &&
pNode->m_dwAttributes != 0xFFFFFFFF &&
pNode->m_dwAttributes != FILE_ATTRIBUTE_DIRECTORY )
{
fRet = AppendRestoreMapEntry(
hFile,
OPR_SETATTRIB,
pNode->m_dwAttributes,
NULL,
pNode->m_pPath1,
NULL,
NULL,
0,
0);
}
//
// Generate an explicit set acl if needed
//
if ( pNode->m_pbAcl != NULL &&
pNode->m_cbAcl != 0 &&
OPR_SETACL != pNode->m_dwOperation &&
OPR_FILE_DELETE != pNode->m_dwOperation &&
OPR_DIR_DELETE != pNode->m_dwOperation)
{
fRet = AppendRestoreMapEntry(
hFile,
OPR_SETACL,
0xFFFFFFFF,
NULL,
pNode->m_pPath1,
NULL,
pNode->m_pbAcl,
pNode->m_cbAcl,
pNode->m_fAclInline);
}
Exit:
return fRet;
}