/*++

Copyright (c) 2000-2001  Microsoft Corporation

Module Name:

    hardlink.cpp

Abstract:

    The class that manages hardlinks for one volume.  Assumes one class object
    will be created per volume.

Author:

    Stefan R. Steiner   [ssteiner]        3-30-2000

Revision History:

--*/

#include "stdafx.h"
#include "hardlink.h"
 
VOID
CFsdHardLinkListEntry::AddFile(
    IN const CBsString& cwsDirPath,
    IN const CBsString& cwsFileName
    )
{
    SFsdHLFileName sFileName;
    sFileName.cwsDirPath  = cwsDirPath;
    sFileName.cwsFileName = cwsFileName;
    m_cFilesLinkedTogetherList.AddTail( sFileName );
}

VOID 
CFsdHardLinkListEntry::PrintEntry(
    IN FILE *fpOut,
    IN INT cVolMountPointOffset
    )
{
    fwprintf( fpOut, L"\tLinks to file: %u, links found: %u %s\n", m_sExtendedInfo.lNumberOfLinks,
        m_cFilesLinkedTogetherList.Size(), 
        m_sExtendedInfo.lNumberOfLinks == (LONG)m_cFilesLinkedTogetherList.Size() ? L"" : L" - MISMATCH" );

    SFsdHLFileName sFileName;

    CVssDLListIterator< SFsdHLFileName > cListEntryIter( m_cFilesLinkedTogetherList );
    while( cListEntryIter.GetNext( sFileName ) )
        fwprintf( fpOut, L"\t\t%s%s\n", sFileName.cwsDirPath.c_str() + cVolMountPointOffset, 
            sFileName.cwsFileName.c_str() );
}


CFsdHardLinkManager::~CFsdHardLinkManager()
{
    //
    //  Need to delete all CFsdHardLinkListEntry objects
    //
    ULONGLONG ullFileIndex;
    CFsdHardLinkListEntry *pcListEntry;

    m_cHardLinkFilesList.StartEnum();
    while ( m_cHardLinkFilesList.GetNextEnum( &ullFileIndex, &pcListEntry ) )
    {
        delete pcListEntry;
    }    
    m_cHardLinkFilesList.EndEnum();
}

VOID 
CFsdHardLinkManager::PrintHardLinkInfo()
{
    //
    //  Need to iterate through all hard link entries
    //
    ULONGLONG ullFileIndex;
    CFsdHardLinkListEntry *pcListEntry;

    m_cHardLinkFilesList.StartEnum();
    while ( m_cHardLinkFilesList.GetNextEnum( &ullFileIndex, &pcListEntry ) )
    {
        pcListEntry->PrintEntry( m_pcParams->GetDumpFile(), m_cVolMountPointOffset );
    }    
    m_cHardLinkFilesList.EndEnum();
}


BOOL 
CFsdHardLinkManager::IsHardLinkInList(
    IN ULONGLONG ullFileIndex,
    IN const CBsString& cwsDirPath,
    IN const CBsString& cwsFileName,
    OUT WIN32_FILE_ATTRIBUTE_DATA *psFileAttributeData,
    OUT SFileExtendedInfo *psExtendedInfo
    )
{
    //
    //  Search the hard link list to see if the file index is already in
    //  the list.
    //
    CFsdHardLinkListEntry *pcLinkEntry;
    
    if ( m_cHardLinkFilesList.Find( ullFileIndex, &pcLinkEntry ) )
    {
        //
        //  Found it.  Add file name to the entry and get the stored attributes.
        //
        pcLinkEntry->AddFile( cwsDirPath, cwsFileName );
        pcLinkEntry->GetAttributes( psFileAttributeData, psExtendedInfo );

        if ( m_pcParams->m_bPrintDebugInfo )
            wprintf( L"IsHardLinkInList: FOUND ullFileIndex: %016I64x, file '%s%s', num in list: %u, num lnks: %d\n",
                ullFileIndex, cwsDirPath.c_str(), cwsFileName.c_str(), pcLinkEntry->m_cFilesLinkedTogetherList.Size(), 
                psExtendedInfo->lNumberOfLinks );

        return TRUE;
    }
    
    return FALSE;
}


VOID 
CFsdHardLinkManager::AddHardLinkToList(
    IN ULONGLONG ullFileIndex,
    IN const CBsString& cwsDirPath,
    IN const CBsString& cwsFileName,
    IN WIN32_FILE_ATTRIBUTE_DATA *psFileAttributeData,
    IN SFileExtendedInfo *psExtendedInfo
    )
{
    CFsdHardLinkListEntry *pcLinkEntry;

    //
    //  Add it.  Create a new entry and add the entry to the list
    //
    pcLinkEntry = new CFsdHardLinkListEntry( 
                        cwsDirPath, 
                        cwsFileName, 
                        psFileAttributeData, 
                        psExtendedInfo );
    if ( pcLinkEntry == NULL )
        throw E_OUTOFMEMORY;
    
    if ( m_cHardLinkFilesList.Insert( ullFileIndex, pcLinkEntry ) != BSHASHMAP_NO_ERROR )
        m_pcParams->ErrPrint( L"CFsdHardLinkManager::AddHardLinkToList - Error adding to hard-link file list" );

    if ( m_pcParams->m_bPrintDebugInfo )
        wprintf( L"  AddHardLinkToList: ullFileIndex: %016I64x, file '%s%s', num lnks: %d\n",
            ullFileIndex, cwsDirPath.c_str(), cwsFileName.c_str(), psExtendedInfo->lNumberOfLinks );
}