//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1998 - 2000.
//
//  File:       CatCnfg.cxx
//
//  Contents:   Support for adding catalogs during setup.
//
//  History:    13-May-1998   KyleP   Added copyright
//
//--------------------------------------------------------------------------

#include "pch.cxx"
#pragma hdrstop

#include <ciregkey.hxx>
#include "catcnfg.hxx"


//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::CCatalogConfig
//
//  Synopsis:   Constructor
//
//  History:    9-10-97  mohamedn
//
//--------------------------------------------------------------------------

CCatalogConfig::CCatalogConfig(CError & Err) :
    _Err( Err ),
    _cDrive( 0 ),
    _pwszCatalogDrive( 0 ),
    _cIncludedScopes( 0 ), _xaIncludedScopes( 10 ),
    _cExcludedScopes( 0 ), _xaExcludedScopes( 10 )
{
    RtlZeroMemory( _DriveList, sizeof _DriveList );
}

//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::InitDriveList, public
//
//  Synopsis:   Initialize drive list with local drive names, types, and
//              available/free space.
//
//  Arguments:  none
//
//  Returns:    ERROR_SUCCESS upon sucess,
//              none zero upon failure.
//
//  History:    6-27-97     mohamedn  created
//              9/10/97     mohamedn  rewritten catalog configuration
//
//--------------------------------------------------------------------------

BOOL CCatalogConfig::InitDriveList()
{
    // 26 drive letters * 4 characters per drive + terminating NULL.
    const DWORD dwSize = MAX_DRIVES * CHARS_PER_DRIVE + 1;
    WCHAR       wszListOfAllDrives[ dwSize ];
    unsigned    iDriveNumber   = 0;
    DWORD       dwRetVal       = 0;

    RtlZeroMemory( wszListOfAllDrives, sizeof wszListOfAllDrives );

    dwRetVal = GetLogicalDriveStrings(dwSize, wszListOfAllDrives);
    if ( dwRetVal == 0 ||  dwRetVal > dwSize )
    {
        DWORD dwErr = GetLastError();
        isDebugOut(( "GetLogicalDriveStrings Failed: dwRetVal: %d, GetLastError(): %d\n",
                     dwRetVal, dwErr ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dwErr );

        return FALSE;
    }

    for ( WCHAR *pwszTmp = wszListOfAllDrives;
          *pwszTmp;
          pwszTmp += CHARS_PER_DRIVE )
    {
        switch (GetDriveType(pwszTmp))
        {
        case DRIVE_FIXED:         // The disk cannot be removed from the drive.
            break;

        default:
            isDebugOut(( "InitDriveList: Unexpected drive type %d\n",
                         GetDriveType(pwszTmp) ));

        case 0:                 // The drive type cannot be determined.
        case 1:                 // The root directory does not exist.
        case DRIVE_REMOVABLE:   // The media can be removed from the drive.
        case DRIVE_REMOTE:      // The drive is a remote (network) drive.
        case DRIVE_CDROM:       // drive is a CD-ROM drive.
        case DRIVE_RAMDISK:     // The drive is a RAM disk.
            continue;
        }

        _DriveList[iDriveNumber].SetDriveName(pwszTmp);

        if ( ! _DriveList[iDriveNumber].SetDriveInfo( ) )
        {
            continue;
        }
        else
        {
            iDriveNumber++;
        }
    }

    _cDrive = iDriveNumber;

    ReservePageFileData();

    return ( _cDrive > 0 ? TRUE : FALSE );
}


//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::ReservePageFileData, private
//
//  Synopsis:   Reserve unallocated space for page files.
//
//  Arguments:  none
//
//  Returns:    TRUE upon sucess, FALSE upon failure.
//
//  History:    26 Oct 1998    AlanwW    Created
//
//--------------------------------------------------------------------------

const WCHAR wszPagingFileKey[] =
    L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management";
const WCHAR wszPagingFileValueName[] = L"PagingFiles";

BOOL CCatalogConfig::ReservePageFileData()
{
    WCHAR awcPagingFiles[2000];
    awcPagingFiles[0] = L'\0';

    //
    //  Get the original page file info from
    //  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessonManager
    //
    CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wszPagingFileKey );

    if ( ! reg.Get( wszPagingFileValueName,
                    awcPagingFiles,
                    sizeof awcPagingFiles/sizeof awcPagingFiles[0] ) )
        return FALSE;

    //
    // Iterate through all paging files, reserve any difference between
    // the max size and currently allocated size.
    //
    WCHAR * pwsz = &awcPagingFiles[0];
    while ( *pwsz )
    {
        WCHAR *pwszPageFile = pwsz;
        pwsz = wcschr(pwsz, L' ');
        if ( ! pwsz )
            break;

        *pwsz++ = L'\0';
        ULONG ulMinAlloc = _wtoi( pwsz );

        WCHAR *pwsz2 = wcschr(pwsz, L' ');

        ULONG ulMaxAlloc = ulMinAlloc + MAXOVERMINFACTOR;
        if ( pwsz2 )
            ulMaxAlloc = _wtoi( pwsz2 );

        while ( *pwsz )
            pwsz++;
        pwsz++;

        CDriveInformation * pDriveInfo = GetDriveInfo( pwszPageFile );
        if ( !pDriveInfo )
            continue;

        //
        //  For some reason, GetFileAttributesEx will get a sharing violation
        //  on an open paging file.  FindFirstFile will work to get the very
        //  same information.
        //
        HANDLE hFind;
        WIN32_FIND_DATA FindData;

        if ( (hFind = FindFirstFile(pwszPageFile, &FindData)) ==
             INVALID_HANDLE_VALUE )
        {
            isDebugOut(( "ReservePageFileData: FindFirstFile %ws failed: %x\n",
                         pwszPageFile,
                         GetLastError() ));
            continue;
        }
        FindClose(hFind);

        ULARGE_INTEGER ullFileSize;
        ullFileSize.LowPart =  FindData.nFileSizeLow;
        ullFileSize.HighPart = FindData.nFileSizeHigh;

        pDriveInfo->ReservePagingData( ulMaxAlloc * ONE_MB,
                                       ullFileSize.QuadPart );
    }
    return TRUE;
}


//+-------------------------------------------------------------------------
//
//  Member:     CDriveInformation::GetDriveInfo, public
//
//  Synopsis:   Returns pointer to drive information structure.
//
//  Arguments:  [pwszPath] - path name to be looked up
//
//  Returns:    CDriveInformation* - pointer to drive information; 0 if not found
//
//  History:    29 Oct 1998     AlanW     Created
//
//--------------------------------------------------------------------------

CDriveInformation * CCatalogConfig::GetDriveInfo(WCHAR const * pwszPath)
{
    WCHAR       wcDriveLetter = (WCHAR)toupper( *pwszPath );

    for (unsigned i = 0; i < _cDrive; i++ )
    {
        if (toupper( _DriveList[i].GetDriveLetter() ) == wcDriveLetter )
            return &_DriveList[i];
    }

    return 0;
}

//+-------------------------------------------------------------------------
//
//  Member:     CDriveInformation::SetDriveInfo, public
//
//  Synopsis:   Obtains drive info
//
//  Arguments:  [none]
//
//  Returns:    TRUE upon success, False upon failure.
//
//  History:    6-27-97        mohamedn  created
//              26 Oct 1998    AlanwW    Enhanced and made a CDriveInfo method.
//
//--------------------------------------------------------------------------

static WCHAR pwszBootFile1[] = L"x:\\NTLDR";                      // x86
static WCHAR pwszBootFile2[] = L"x:\\OS\\WINNT50\\OSLOADER.EXE";  // risc

static WCHAR * apwszBootFiles[] = {
    pwszBootFile1,
    pwszBootFile2,
};


BOOL CDriveInformation::SetDriveInfo()
{
    Win4Assert( 0 != GetDriveLetter() );
    _cbFreeSpace = _cbTotalSpace = _cbReservedSpace = 0;

    ULARGE_INTEGER  cbFreeBytesToCaller;
    ULARGE_INTEGER  cbTotalNumberOfBytes;
    ULARGE_INTEGER  cbTotalNumberOfFreeBytes;

    cbFreeBytesToCaller.QuadPart        = 0;
    cbTotalNumberOfBytes.QuadPart       = 0;
    cbTotalNumberOfFreeBytes.QuadPart   = 0;

    //
    // returns 0 upon failure, none-zero upon success.
    //
    BOOL fSuccess = GetDiskFreeSpaceEx( _wszDriveName,
                                        &cbFreeBytesToCaller,
                                        &cbTotalNumberOfBytes,
                                        &cbTotalNumberOfFreeBytes );
    if (!fSuccess)
    {
         isDebugOut(( "SetDriveInfo: GetDiskFreeSapceEx %ws failed: %x\n",
                      _wszDriveName,
                      GetLastError() ));
         return fSuccess;
    }

    _cbFreeSpace= cbTotalNumberOfFreeBytes.QuadPart;
    _cbTotalSpace= cbTotalNumberOfBytes.QuadPart;

    //
    // Determine if the volume supports security (i.e., if it's NTFS)
    //
    fSuccess = GetVolumeInformationW( _wszDriveName,
                                      0, 0,           // volume name
                                      0,              // volume serial number
                                      0,              // max filename length
                                      &_dwFileSystemFlags,
                                      0, 0 );         // file system name

    if (!fSuccess)
    {
         isDebugOut(( "SetDriveInfo: GetFileSystemInfo failed: %x\n",GetLastError() ));
         return fSuccess;
    }

    for (unsigned i=0; i < NUMELEM( apwszBootFiles ); i++)
    {
        if (Exists(apwszBootFiles[i]))
        {
            _fIsBootDrive = TRUE;
            break;
        }
    }

    return fSuccess;
}

//+-------------------------------------------------------------------------
//
//  Member:     CDriveInformation::Exists, public
//
//  Synopsis:   Determines if a file or directory exists
//
//  Arguments:  [pwszPath]   - path name of the file to check
//
//  Notes:      The [pwszPath] must be a full path name starting with a
//              drive letter.  The drive letter is overwritten by this
//              method.
//
//  Returns:    TRUE if the file exists, FALSE upon failure or non-existance.
//
//  History:    26 Oct 1998     AlanW     Created
//
//--------------------------------------------------------------------------

BOOL CDriveInformation::Exists(WCHAR * pwszPath)
{
    *pwszPath = GetDriveLetter();

    DWORD attr = GetFileAttributes( pwszPath );

    // If we couldn't determine file's attributes, don't consider it found
    // unless the error code indirectly indicates that it exists.

    if ( 0xffffffff == attr )
    {
        isDebugOut(( DEB_TRACE, "Exists: GetFileAttributes( %ws ) Failed: %d\n",
                      pwszPath, GetLastError() ));

        if (GetLastError() == ERROR_SHARING_VIOLATION)
            return TRUE;        // It must exist

        return FALSE;
    }

    return TRUE;
}

//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::ConfigureDefaultCatalog
//
//  Synopsis:   Creates a single default catalog if sufficient disk space
//              exists on one drive.
//
//  Arguments:  [wszPrimaryScope] -- Path name of primary indexed directory
//
//  Returns:    TRUE upon success, FALSE upon Failure,
//
//  History:    9-10-97  mohamedn
//
//--------------------------------------------------------------------------

static WCHAR wszUpgradeDir[] = L"x:\\$WIN_NT$.~LS";

BOOL CCatalogConfig::ConfigureDefaultCatalog(
    WCHAR const * pwszPrimaryScope )
{
    {
        //
        // Reserve space for a net upgrade of the OS if we're not currently
        // doing one (in which case the space for it will already be in use).
        // Because we will preferably use an NTFS drive for the catalog, try
        // using a FAT drive for the upgrade files.
        //
        int       iUpgradeFiles = -1;
        int       iBestFitForUpgrade = -1;
        ULONGLONG cbBestFitForUpgrade = 0;
        BOOL      fBestFitOnNtfs = FALSE;

        for ( unsigned i = 0 ; i < _cDrive; i++ )
        {
            if ( iUpgradeFiles == -1 && _DriveList[i].Exists( wszUpgradeDir ) )
            {
                iUpgradeFiles = i;
                break;
            }

            ULONGLONG cbAvail = _DriveList[i].GetAvailableSpace();
            if ( cbAvail < MIN_UPGRADE_SPACE )
                continue;

            if ( iBestFitForUpgrade == -1 ||
                 ( cbAvail < cbBestFitForUpgrade && fBestFitOnNtfs ) ||
                 ( ! _DriveList[i].IsNtfs() && fBestFitOnNtfs ) )
            {
                cbBestFitForUpgrade = cbAvail;
                iBestFitForUpgrade = i;
                fBestFitOnNtfs = _DriveList[i].IsNtfs();
            }
        }
        if ( iUpgradeFiles == -1 && iBestFitForUpgrade != -1 )
            _DriveList[iBestFitForUpgrade].AddReservedSpace( MIN_UPGRADE_SPACE );
        else  if ( iUpgradeFiles == -1 )
        {
            isDebugOut(( DEB_TRACE, "Not enough room for net upgrade!\n" ));
            return FALSE;
        }
    }

    //
    //  Determine which drive to put the catalog on.
    //
    int          iBiggestFreeNTFS = -1;
    int          iBiggestFreeFAT  = -1;
    ULONGLONG    cbMaxFreeSpaceOnNTFS = 0;
    ULONGLONG    cbMaxFreeSpaceOnFAT  = 0;

    for ( unsigned i = 0 ; i < _cDrive; i++ )
    {
        if ( _DriveList[i].IsSmallBootPartition() )
            continue;

        int *       piBiggestFree = &iBiggestFreeFAT;
        ULONGLONG * pcbMaxFree = &cbMaxFreeSpaceOnFAT;
        if ( _DriveList[i].IsNtfs() )
        {
            piBiggestFree = &iBiggestFreeNTFS;
            pcbMaxFree = &cbMaxFreeSpaceOnNTFS;
        }

        if ( *pcbMaxFree < _DriveList[i].GetAvailableSpace() )
        {
            *pcbMaxFree = _DriveList[i].GetAvailableSpace();
            *piBiggestFree = i;
        }
    }


    BOOL fAddNtfsDrives = FALSE;
    CDriveInformation * pCatalogDrive = 0;
    double dblCatalogSizeRatio;

    if ( iBiggestFreeNTFS != -1 )
    {
        //
        // There is an NTFS drive on the system; need to put the catalog
        // there.
        //

        pCatalogDrive = &_DriveList[iBiggestFreeNTFS];
        dblCatalogSizeRatio = CATALOG_SIZE_RATIO_NTFS;
        fAddNtfsDrives = TRUE;
    }
    else if ( iBiggestFreeFAT != -1 )
    {
        pCatalogDrive = &_DriveList[iBiggestFreeFAT];
        dblCatalogSizeRatio = CATALOG_SIZE_RATIO_FAT;
        fAddNtfsDrives = FALSE;
    }

    if ( 0 == pCatalogDrive ||
         pCatalogDrive->GetAvailableSpace() < MIN_CATALOG_SPACE )
    {
        isDebugOut(( DEB_TRACE, "Not enough room for minimal catalog!\n" ));
        return FALSE;
    }

    _pwszCatalogDrive = pCatalogDrive->GetDriveName();
    pCatalogDrive->AddReservedSpace( MIN_CATALOG_SPACE );

    //  Add the primary scope directory for the catalog.
    if ( pwszPrimaryScope && *pwszPrimaryScope )
        AddIncludedDir( pwszPrimaryScope );

    //
    // Iterate through the list of drives once or twice, depending on
    // whether all drives are FAT.
    //
    unsigned maxLoop = _cDrive * ( (fAddNtfsDrives == TRUE) + 1);
    for ( i = 0 ; i < maxLoop; i++ )
    {
        // If end of NTFS enumeration, go back around the loop for FAT drives.
        if (i == _cDrive)
            fAddNtfsDrives = FALSE;

        CDriveInformation & DriveToCheck = _DriveList[i % _cDrive];

        if ( DriveToCheck.IsSmallBootPartition() )
            continue;

        if ( DriveToCheck.IsNtfs() != fAddNtfsDrives )
            continue;

        ULONGLONG cbUsed = DriveToCheck.GetUsedSpace();

        cbUsed = (ULONGLONG) ((LONGLONG)cbUsed * dblCatalogSizeRatio);
        if ( cbUsed < pCatalogDrive->GetAvailableSpace() )
        {
            AddIncludedDir( DriveToCheck.GetDriveName() );
            pCatalogDrive->AddReservedSpace( cbUsed );
        }
    }

    return TRUE;
}

//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::SaveState
//
//  Synopsis:   Saves the state of the catalog configuration in the registry.
//
//  Arguments:  - NONE -
//
//  Returns:    TRUE upon success, FALSE upon Failure,
//
//  History:    19 Nov 1998   AlanW   Created
//
//--------------------------------------------------------------------------

BOOL CCatalogConfig::SaveState( )
{
    Win4Assert( 0 != GetName() && 0 != GetLocation() );

    CCatReg  catReg(_Err);

    if ( !catReg.Init( GetName(), GetLocation() ) )
        return FALSE;

    //
    // Add all the included scopes
    //
    WCHAR const * pwszScope;
    for (unsigned i = 0;  pwszScope = GetIncludedScope( i ); i++)
    {
        if ( !catReg.AddScope( pwszScope, L",,5" ) )
        {
            return FALSE;
        }
    }

    //
    // Now add the excluded scopes
    //
    for (i = 0;  pwszScope = GetExcludedScope( i ); i++)
    {
        if ( !catReg.AddScope( pwszScope, L",,4" ) )
        {
            return FALSE;
        }
    }
    return TRUE;
}


//+-------------------------------------------------------------------------
//
//  Member:     CCatalogConfig::AddStringToArray, private static
//
//  Synopsis:   Adds a string to an XArray
//
//  Arguments:  [c]    - current count of strings in array
//              [xa]   - the XArray of strings
//              [pwsz] - string to be added
//
//  Returns:    BOOL - FALSE if any problems, TRUE otherwise
//
//  Notes:      Can throw on allocation failures.
//
//  History:    04 Nov 1998   AlanW   Created
//
//--------------------------------------------------------------------------

BOOL CCatalogConfig::AddStringToArray(
    ULONG & c,
    XArray<WCHAR const *> & xa,
    WCHAR const * pwsz )
{
    XPtrST<WCHAR> xpwsz;
    if (pwsz)
    {
        WCHAR * pwszCopy = new WCHAR[ wcslen(pwsz) + 1 ];
        xpwsz.Set(pwszCopy);
        wcscpy( pwszCopy, pwsz );
        pwsz = pwszCopy;
    }

    if ( c >= xa.Count() )
        xa.ReSize( c*2 );

    xa[c] = pwsz;
    c++;
    xpwsz.Acquire();
    return TRUE;
}


//+-------------------------------------------------------------------------
//
//  Member:     CCatReg::Init
//
//  Synopsis:   Initializes catalog registry key configurator
//
//  Arguments:  [ pwszCatName ] -   catalog name
//              [ pwszLocation] -   catalog location
//
//  Returns:    none - throws upon fatal errors.
//
//  History:    9-10-97  mohamedn
//
//--------------------------------------------------------------------------

BOOL CCatReg::Init( WCHAR const *pwszCatName, WCHAR const *pwszLocation)
{

    ISAssert( pwszCatName );

    // create a catalog for the drive
    BOOL fExisted = FALSE;
    CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegCatalogsSubKey );

    if ( !reg.CreateKey( pwszCatName, fExisted ) )
    {
        DWORD dwErr = GetLastError();
        isDebugOut(( "created catalogs\\%ws subkey Failed: %d\n",
                      pwszCatName, dwErr ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dwErr );

        return FALSE;
    }

    isDebugOut(( DEB_TRACE, "created catalogs\\%ws subkey\n", pwszCatName ));

    wcscpy( _wszCatRegSubKey, wcsRegCatalogsSubKey );
    wcscat( _wszCatRegSubKey, L"\\" );
    wcscat( _wszCatRegSubKey, pwszCatName );

    CWin32RegAccess regSystem( reg.GetHKey(), pwszCatName );
    if ( !regSystem.Set( L"Location", pwszLocation ) )
    {
        DWORD dw = GetLastError();

        isDebugOut(( "Failed to set Cat Location valued:%ws,  %d\n",
                      pwszLocation, dw ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dw );

        return FALSE;
    }

    if ( !regSystem.Set( wcsIsIndexingW3Roots,        (DWORD) 0 )  ||
         !regSystem.Set( wcsIsIndexingNNTPRoots,      (DWORD) 0 )
       )
    {
        DWORD dw = GetLastError();

        isDebugOut(( "Failed to set Cat values: %d\n", dw ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dw );

        return FALSE;
    }

    // Create a "Scopes" key so a watch can be established in cicat
    // It needs no entries.

    if ( !regSystem.CreateKey( wcsCatalogScopes, fExisted ) )
    {
        DWORD dw = GetLastError();
        isDebugOut(( "created scopes subkey Failed: %d\n", dw ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dw );

        return FALSE;
    }

    //
    // initialize the reg scopes subkey name
    //
    wcscpy( _wszCatScopeRegSubKey, _wszCatRegSubKey );
    wcscat( _wszCatScopeRegSubKey, L"\\" );
    wcscat( _wszCatScopeRegSubKey, wcsCatalogScopes );

    return TRUE;
}

//+-------------------------------------------------------------------------
//
//  Member:     CCatReg::AddScope
//
//  Synopsis:   Adds a scope for the current catalog
//
//  Arguments:  [ pwszScopeName ]   -  scope name
//              [ pwszScopeAttrib]  -  scope attributes
//
//  Returns:    none - throws upon fatal errors.
//
//  History:    9-10-97  mohamedn
//
//--------------------------------------------------------------------------

BOOL CCatReg::AddScope( WCHAR const * pwszScopeName,
                        WCHAR const * pwszScopeAttrib )
{
    CWin32RegAccess regScopes( HKEY_LOCAL_MACHINE, _wszCatScopeRegSubKey );

    if ( !regScopes.Set( pwszScopeName, pwszScopeAttrib ) )
    {
        DWORD dwRetVal = GetLastError();

        isDebugOut(( "Failed to set scope value:\\%ws,  %d\n",
                          pwszScopeName, dwRetVal ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dwRetVal );

        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

//+-------------------------------------------------------------------------
//
//  Member:     CCatReg::TrackW3Svc, public
//
//  Synopsis:   Configures catalog to be a 'web' catalog.
//
//  Arguments:  [dwInstance] -- WWW Virtual Server instance number
//
//  Returns:    TRUE if setup succeeded.
//
//  History:    13-May-1998   KyleP   Created
//
//--------------------------------------------------------------------------

BOOL CCatReg::TrackW3Svc( DWORD dwInstance )
{
    CWin32RegAccess regSystem( HKEY_LOCAL_MACHINE, _wszCatRegSubKey );

    // Fix for 249655. For a web catalog, wcsGenerateCharacterization and 
    // wcsFilterFilesWithUnknownExtensions should be set as follows.

    if ( !regSystem.Set( wcsIsIndexingW3Roots, 1 ) ||
         !regSystem.Set( wcsW3SvcInstance, dwInstance ) ||
         !regSystem.Set( wcsGenerateCharacterization, 1 ) ||
         !regSystem.Set( wcsFilterFilesWithUnknownExtensions, (DWORD)0 ) ||
         !regSystem.Set( wcsMaxCharacterization, 320 ) )
    {
        DWORD dw = GetLastError();

        isDebugOut(( "Failed to set Cat values: %d\n", dw ));

        ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, _Err, LogSevFatalError, dw );

        return FALSE;
    }

    return TRUE;
}