Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Kernel - File System - HDD.c
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

#if !defined(TgCOMPILE_FORCE_ANSI)


/* == Kernel ============================================================================================================================================================ */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Types                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

TgTYPE_STRUCT(STg2_KN_FS_HDD__Mount_File_Table,)
{
    STg2_UTM_AM_HT                              m_asFile;
    TgSTRING_DICT_ID                            m_tiPathName;
#if TgCOMPILE_CACHE_LINE_SIZE > 8
    TgUINT08                                    m_uiPad[TgCOMPILE_CACHE_LINE_SIZE - 8];
#endif
};

TgTYPE_STRUCT(STg2_KN_FS_HDD__Mount,)
{
    TgKN_FS_MOUNT_ID                            m_tiFS_Mount;
    TgCHAR                                      m_szMount_Root[KTgMAX_FILE_PATH];
    TgSINT32                                    m_iPad;
    TgUINT32                                    m_niFS_File_Table;
    STg2_UTM_AM_HT                              m_sFS_Path_Table;
    P_STg2_KN_FS_HDD__Mount_File_Table          m_asFS_File_Table;
#if TgCOMPILE_CACHE_LINE_SIZE > 8
    TgUINT08                                    m_uiPad[TgCOMPILE_CACHE_LINE_SIZE - 8];
#endif
};




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions and Data                                                                                                                                         */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static TgVOID                               tgKN_FS_HDD__FQN( PC_TgCHAR, C_TgSIZE, PC_STg2_KN_File_Job, PC_STg2_KN_FS_HDD__Mount, C_TgBOOL bCreate );
static TgVOID                               tgKN_FS_HDD__Mount__Init_Table_Entry( C_TgKN_FS_MOUNT_ID, P_TgCHAR );

static STg2_KN_FS_HDD__Mount                s_asKN_FS_HDD__Mount[KTgKN_MAX_FILE_SYSTEM_MOUNT];
static TgSINTPTR                            s_aiKN_HDD_File_Info[KTgKN_MAX_FILE_OPEN];




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Private Functions                                                                                                                                                     */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgKN_FS_HDD__Free_Space ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgSIZE tgKN_FS_HDD__Free_Space( C_TgKN_FS_MOUNT_ID tiFS_Mount )
{
    P_STg2_KN_FS_Mount                  psFS_Mount;
    P_STg2_KN_FS_HDD__Mount             psFS_HDD_Mount;

    psFS_Mount = g_asKN_FS_Mount + tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( tiFS_Mount, psFS_Mount->m_tiFS_Mount ) );
    psFS_HDD_Mount = s_asKN_FS_HDD__Mount + tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( tiFS_Mount, psFS_HDD_Mount->m_tiFS_Mount ) );

    /* #IMPLEMENT */
    return (0);
}


/* ---- tgKN_FS_HDD__Mount ---------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgKN_FS_HDD__Mount( C_TgKN_FS_MOUNT_ID tiFS_Mount, CPCU_TgCHAR pszMountPath )
{
    P_STg2_KN_FS_Mount                  psFS_Mount;
    P_STg2_KN_FS_HDD__Mount             psFS_HDD_Mount;
    TgCHAR                              szPath[KTgMAX_FILE_PATH];
    TgCHAR                              szDirectory[KTgMAX_FILE_PATH];
    P_TgVOID                            pFind;

    psFS_Mount = g_asKN_FS_Mount + tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( tiFS_Mount, psFS_Mount->m_tiFS_Mount ) );
    psFS_HDD_Mount = s_asKN_FS_HDD__Mount + tiFS_Mount.m.iI;

    psFS_HDD_Mount->m_tiFS_Mount = psFS_Mount->m_tiFS_Mount;

    tgCM_Path_Copy( psFS_HDD_Mount->m_szMount_Root, TgARRAY_COUNT( psFS_HDD_Mount->m_szMount_Root ), pszMountPath );
    psFS_HDD_Mount->m_niFS_File_Table = 0;
    psFS_HDD_Mount->m_asFS_File_Table = TgRESERVE_VIRTUAL( KTgKN_MAX_FILE_DIRECTORY * sizeof( STg2_KN_FS_HDD__Mount_File_Table ) );
    TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Init_Virtual( &psFS_HDD_Mount->m_sFS_Path_Table, 1, KTgKN_MAX_FILE_DIRECTORY )));

    tgCM_Path_Copy( szPath, TgARRAY_COUNT( szPath ), psFS_HDD_Mount->m_szMount_Root );
    tgCM_Path_Append( szPath, TgARRAY_COUNT( szPath ), TgT( "\\*" ) );

    tgKN_FS_HDD__Mount__Init_Table_Entry( tiFS_Mount, TgT( "" ) );

    if (TgFAILED(tgIO_Directory_Find_First( szDirectory, TgARRAY_COUNT(szDirectory), &pFind, szPath )))
    {
        return;
    };

    do
    {
        tgKN_FS_HDD__Mount__Init_Table_Entry( tiFS_Mount, szDirectory );
    }
    while (TgTRUE == tgIO_Directory_Find_Next( szDirectory, TgARRAY_COUNT( szDirectory ), pFind ));

    tgIO_Directory_Find_Close( pFind );

    /* #IMPLEMENT */
}


/* ---- tgKN_FS_HDD__Execute_Job ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgKN_FS_HDD__Execute_Job( P_STg2_KN_File_Job psJob )
{
    P_STg2_KN_File_Info                 psFile_Info;
    P_STg2_KN_FS_Mount                  psFS_Mount;
    P_STg2_KN_FS_HDD__Mount             psFS_HDD_Mount;
    P_STg2_KN_File_System               psFS;
    TgSINT32                            iFile;
    TgBOOL                              bCreate;
    TgCHAR                              szFull_Path[KTgMAX_FILE_PATH];
    TgSIZE                              uiFile_Size;

    psFile_Info = g_asKN_File_Info + psJob->m_tiFile.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_ID( psJob->m_tiFile, psFile_Info->m_tiFile ) );
    psFS_Mount = g_asKN_FS_Mount + psFile_Info->m_tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( psFile_Info->m_tiFS_Mount, psFS_Mount->m_tiFS_Mount ) );
    psFS_HDD_Mount = s_asKN_FS_HDD__Mount + psFile_Info->m_tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( psFile_Info->m_tiFS_Mount, psFS_HDD_Mount->m_tiFS_Mount ) );
    psFS = g_asKN_FS + psFile_Info->m_tiFS.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_SYSTEM_ID( psFile_Info->m_tiFS, psFS->m_tiFS ) );

    iFile = psJob->m_tiFile.m.iI;

    switch (psJob->m_enCmd)
    {
        case ETgFILE_COMMAND__OPEN:
            /* Generate a text string containing the full path for the file */
            bCreate = ETgFILE_IO_ACCESS__CREATE == (psJob->m_sCmd.m_sOpen.m_enMode & ETgFILE_IO_ACCESS__CREATE) ? TgTRUE : TgFALSE;
            tgKN_FS_HDD__FQN( szFull_Path, TgARRAY_COUNT( szFull_Path ), psJob, psFS_HDD_Mount, bCreate );
            if (0 == szFull_Path[0])
            {
                psFile_Info->m_tiFile = KTgKN_FILE_ID__INVALID;
                tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__INVALID );
                break;
            };

            if (TgFAILED( tgIO_File_Open( &s_aiKN_HDD_File_Info[iFile], szFull_Path, g_asKN_File_Info[iFile].m_enMode ) ))
            {
                psFile_Info->m_tiFile = KTgKN_FILE_ID__INVALID;
                tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__INVALID );
                break;
            };

            uiFile_Size = tgIO_File_Size( s_aiKN_HDD_File_Info[iFile] );
            TgERROR( uiFile_Size < (TgSIZE)KTgMAX_S32 );

            g_asKN_File_Info[iFile].m_uiSize = uiFile_Size;
            g_asKN_File_Info[iFile].m_uiPos = 0;

            if (psJob->m_sCmd.m_sOpen.m_iCache > 0)
            {
                g_asKN_File_Info[iFile].m_puiCache = TgMALLOC_POOL( (TgSIZE)psJob->m_sCmd.m_sOpen.m_iCache );
                g_asKN_File_Info[iFile].m_uiCache_Size = (TgSIZE)psJob->m_sCmd.m_sOpen.m_iCache;
            };
            tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__DONE );
            tgKN_FS_Job_Complete( psJob );
            break;

        case ETgFILE_COMMAND__READ_ASYNC:
            if (g_asKN_File_Info[psJob->m_tiFile.m.iI].m_uiSize <= g_asKN_File_Info[psJob->m_tiFile.m.iI].m_uiPos)
            {
                tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__INVALID );
                break;
            };

            /* Check to see if a buffer should be allocated.  All memory management is the responsibility of the call back function.  Obviously, all allocator functions */
            /* would have to be multi-thread and concurrent safe. */
            if ((0 == psJob->m_sCmd.m_sRead.m_pBuffer) && (0 != psJob->m_sCmd.m_sRead.m_pfnAllocator))
            {
                psJob->m_sCmd.m_sRead.m_nuiBuffer = g_asKN_File_Info[iFile].m_uiSize - g_asKN_File_Info[iFile].m_uiPos;
                psJob->m_sCmd.m_sRead.m_pBuffer = psJob->m_sCmd.m_sRead.m_pfnAllocator( psJob->m_sCmd.m_sRead.m_nuiBuffer );
            };

            if (nullptr == psJob->m_sCmd.m_sRead.m_pBuffer)
            {
                tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__INVALID );
                break;
            };

            TgERROR( 0 < psJob->m_sCmd.m_sRead.m_nuiBuffer );

            psJob->m_sCmd.m_sRead.m_nuiResult = tgIO_File_Read( s_aiKN_HDD_File_Info[iFile], psJob->m_sCmd.m_sRead.m_pBuffer, psJob->m_sCmd.m_sRead.m_nuiBuffer );

            g_asKN_File_Info[iFile].m_uiPos += psJob->m_sCmd.m_sRead.m_nuiResult;

            tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__DONE );
            tgKN_FS_Job_Complete( psJob );
            break;

        case ETgFILE_COMMAND__WRITE_ASYNC:
            TgERROR( 0 != psJob->m_sCmd.m_sWrite.m_pBuffer );
            TgERROR( 0 < psJob->m_sCmd.m_sWrite.m_nuiBuffer );

            /* Copy the data from the cache into the read buffer */
            if (psFile_Info->m_uiCache_Size - psFile_Info->m_uiCache_Pos < psJob->m_sCmd.m_sWrite.m_nuiBuffer)
            {
                /* Need to flush out the cache before writing the parameter data */
                if (psFile_Info->m_uiCache_Pos > 0)
                {
                    psFile_Info->m_uiPos += tgIO_File_Write( s_aiKN_HDD_File_Info[iFile], psFile_Info->m_puiCache, psFile_Info->m_uiCache_Pos );
                    psFile_Info->m_uiCache_Pos = 0;
                };

                psJob->m_sCmd.m_sWrite.m_nuiResult = tgIO_File_Write( s_aiKN_HDD_File_Info[iFile], psJob->m_sCmd.m_sWrite.m_pBuffer, psJob->m_sCmd.m_sWrite.m_nuiBuffer );

                psFile_Info->m_uiPos += psJob->m_sCmd.m_sWrite.m_nuiResult;
            }
            else
            {
                /* Add the write request into the cache (write combining) */
                memcpy( psFile_Info->m_puiCache + psFile_Info->m_uiCache_Pos, psJob->m_sCmd.m_sWrite.m_pBuffer, psJob->m_sCmd.m_sWrite.m_nuiBuffer );
                psFile_Info->m_uiCache_Pos += psJob->m_sCmd.m_sWrite.m_nuiBuffer;
                psJob->m_sCmd.m_sWrite.m_nuiResult = psJob->m_sCmd.m_sWrite.m_nuiBuffer;
            };

            tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__DONE );
            tgKN_FS_Job_Complete( psJob );
            break;

        case ETgFILE_COMMAND__FLUSH:
            if (psFile_Info->m_uiCache_Pos > 0)
            {
                psFile_Info->m_uiPos += tgIO_File_Write( s_aiKN_HDD_File_Info[iFile], psFile_Info->m_puiCache, psFile_Info->m_uiCache_Pos );
                psFile_Info->m_uiCache_Pos = 0;
            };

            /* If the file flush failed for any reason - emit a warning to the console and return the failure state. */
            if (TgFAILED( tgIO_File_Flush( s_aiKN_HDD_File_Info[iFile] ) ))
            {
                TgWARNING_MSGF( 0, TgT( "%-16.16s(%-32.32s): File handle is invalid (thread).\n" ), TgT("Kernel"), TgT("File") );
            };

            tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__DONE );
            tgKN_FS_Job_Complete( psJob );
            break;

        case ETgFILE_COMMAND__CLOSE:
            /* Write back any data in the cache before closing the file */
            if (psFile_Info->m_uiCache_Pos > 0)
            {
                psFile_Info->m_uiPos += tgIO_File_Write( s_aiKN_HDD_File_Info[iFile], psFile_Info->m_puiCache, psFile_Info->m_uiCache_Pos );
                psFile_Info->m_uiCache_Pos = 0;
            };

            /* If the file flush failed for any reason - emit a warning to the console and return the failure state. */
            if (TgFAILED( tgIO_File_Close( s_aiKN_HDD_File_Info[iFile] ) ))
            {
                TgWARNING_MSGF( 0, TgT( "%-16.16s(%-32.32s): File handle is invalid (thread).\n" ), TgT("Kernel"), TgT("File") );
            };

            s_aiKN_HDD_File_Info[iFile] = -1;
            tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__DONE );
            tgKN_FS_Job_Complete( psJob );
            break;

        case ETgFILE_COMMAND__UNKNOWN:
        case ETgFILE_COMMAND__CACHE:
        case ETgFILE_COMMAND__CANCEL:
            TgS_NO_DEFAULT( break );
    };

    psJob->m_tiFile_Job = KTgKN_FILE_JOB_ID__INVALID;
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgKN_FS_HDD__FQN ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_HDD__FQN( PC_TgCHAR pszFull_Path, C_TgSIZE nuiFullPath, PC_STg2_KN_File_Job psJob, PC_STg2_KN_FS_HDD__Mount psFS_HDD_Mount, C_TgBOOL bCreate )
{
    TgPARAM_CHECK( nullptr != pszFull_Path );
    TgPARAM_CHECK( nuiFullPath > 0 );
    TgPARAM_CHECK( nullptr != psJob );
    TgPARAM_CHECK( nullptr != psFS_HDD_Mount );

    pszFull_Path[0] = 0;

    if ((ETgFILE_COMMAND__OPEN == psJob->m_enCmd) && (TgTRUE == bCreate))
    {
        TgSTRING_DICT_ID                    tiFileName;
        TgUINTXX                            uiHash;
        TgUINTPTR                           iFile_Table;

        tgCM_Path_Copy( pszFull_Path, nuiFullPath, psFS_HDD_Mount->m_szMount_Root );
        tgCM_Path_Append( pszFull_Path, nuiFullPath, psJob->m_sCmd.m_sOpen.m_pszFile_Name );
        tiFileName = tgSM_Dict_Insert_String( psJob->m_sCmd.m_sOpen.m_pszFile_Name, tgSZ_Length( psJob->m_sCmd.m_sOpen.m_pszFile_Name ) );
        TgERROR(TgTRUE == tgSTRING_DICT_ID_Is_Valid( tiFileName ));
        uiHash = tgSZ_Hash_File_Name( psJob->m_sCmd.m_sOpen.m_pszFile_Name );

        TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Find_Spin( &iFile_Table, psJob->m_sCmd.m_sOpen.m_uiPath, &psFS_HDD_Mount->m_sFS_Path_Table )));
        TgERROR( iFile_Table < psFS_HDD_Mount->m_niFS_File_Table );
        TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Insert_Spin( &psFS_HDD_Mount->m_asFS_File_Table[iFile_Table].m_asFile, uiHash, (TgUINT64)tiFileName.m_iKI )));
    }
    else
    {
        TgUINTPTR                           iFile_Table;
        TgUINTPTR                           iString_Index;
        TgSTRING_DICT_ID                    tiFileName;
        CP_TgCHAR                           pszPath;
        CP_TgCHAR                           pszFile;

        TgCOMPILER_ASSERT( sizeof( tiFileName.m_iKI ) == sizeof( TgUINTPTR ), 1 );

        TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Find_Spin( &iFile_Table, psJob->m_sCmd.m_sOpen.m_uiPath, &psFS_HDD_Mount->m_sFS_Path_Table )));
        TgERROR( iFile_Table < psFS_HDD_Mount->m_niFS_File_Table );
        TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Find_Spin( &iString_Index, psJob->m_sCmd.m_sOpen.m_uiFile, &psFS_HDD_Mount->m_asFS_File_Table[iFile_Table].m_asFile )));
        tiFileName.m_iKI = (TgSINT64)iString_Index;

        pszPath = nullptr;
        tgSM_Dict_Query_String( &pszPath, nullptr, psFS_HDD_Mount->m_asFS_File_Table[iFile_Table].m_tiPathName );
        pszFile = nullptr;
        tgSM_Dict_Query_String( &pszFile, nullptr, tiFileName );

        tgCM_Path_Copy( pszFull_Path, nuiFullPath, psFS_HDD_Mount->m_szMount_Root );
        tgCM_Path_Append( pszFull_Path, nuiFullPath, pszPath );
        tgCM_Path_Append( pszFull_Path, nuiFullPath, pszFile );
    };

    /* #IMPLEMENT */
}


/* ---- tgKN_FS_HDD__Mount__Init_Table_Entry ---------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_HDD__Mount__Init_Table_Entry( C_TgKN_FS_MOUNT_ID tiFS_Mount, P_TgCHAR pszRelPath )
{
    P_STg2_KN_FS_Mount                  psFS_Mount;
    P_STg2_KN_FS_HDD__Mount             psFS_HDD_Mount;
    TgCHAR                              szPath[KTgMAX_FILE_PATH];
    TgUINTXX                            uiHash;
    P_STg2_KN_FS_HDD__Mount_File_Table  psTable;
    P_TgVOID                            pFind;
    TgCHAR                              szFile[KTgMAX_FILE_PATH];
    TgSTRING_DICT_ID                    tiFileName;

    psFS_Mount = g_asKN_FS_Mount + tiFS_Mount.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FS_MOUNT_ID( tiFS_Mount, psFS_Mount->m_tiFS_Mount ) );
    psFS_HDD_Mount = s_asKN_FS_HDD__Mount + tiFS_Mount.m.iI;

    tgCM_Path_Copy( szPath, TgARRAY_COUNT( szPath ), psFS_HDD_Mount->m_szMount_Root );
    tgCM_Path_Append( szPath, TgARRAY_COUNT( szPath ), pszRelPath );
    tgCM_Path_Append( szPath, TgARRAY_COUNT( szPath ), TgT( "\\*" ) );

    /* Add the path to the path table to reference the needed file table */
    uiHash = tgSZ_Hash_Directory( pszRelPath );
    TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Insert_Spin( &psFS_HDD_Mount->m_sFS_Path_Table, uiHash, psFS_HDD_Mount->m_niFS_File_Table )));

    /* Commit the memory necessary for a new table */
    psTable = psFS_HDD_Mount->m_asFS_File_Table + psFS_HDD_Mount->m_niFS_File_Table;
    ++psFS_HDD_Mount->m_niFS_File_Table;
    psFS_HDD_Mount->m_asFS_File_Table = TgCOMMIT_VIRTUAL(psFS_HDD_Mount->m_asFS_File_Table, psFS_HDD_Mount->m_niFS_File_Table * sizeof( STg2_KN_FS_HDD__Mount_File_Table ));

    /* Add the path name and the file names to the file table */
    psTable->m_tiPathName = tgSM_Dict_Insert_String( pszRelPath, tgSZ_Length( pszRelPath ) );
    TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Init_Virtual( &psTable->m_asFile, 1, KTgKN_MAX_FILE_PER_DIRECTORY )));

    if (TgFAILED(tgIO_File_Find_First( szFile, TgARRAY_COUNT(szFile), &pFind, szPath )))
    {
        return;
    };

    do
    {
        uiHash = tgSZ_Hash_File_Name( szFile );
        tiFileName = tgSM_Dict_Insert_String( szFile, tgSZ_Length( szFile ) );
        TgVERIFY(TgSUCCEEDED(tgCM_UTM_HT_Insert_Spin( &psTable->m_asFile, uiHash, (TgUINT64)tiFileName.m_iKI )));
    }
    while (TgTRUE == tgIO_File_Find_Next( szFile, TgARRAY_COUNT(szFile), pFind ));

    tgIO_File_Find_Close( pFind );
}


/*# !defined(TgCOMPILE_FORCE_ANSI) */
#endif