//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#include "tuxmain.h"
#include "fathlp.h"
#include "mfs.h"
#include "storeutil.h"
#include "legacy.h"
#include "testproc.h"
#include "utility.h"

extern SPS_SHELL_INFO *g_pShellInfo;

#define ITERATIONS          128

#define ROOT_DIR_LIMIT      1024

/****************************************************************************

    FUNCTION:   Test1

    PURPOSE:    To test creating, modifying and deleting a cluster sized 
                file with every possible attribute combination.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating an 8.3 directory off the root.
                2.  Creating a file in this directory that is exactly one
                    allocation unit in size.  This also gets read back and 
                    the data is compared with the original data.
                3.  Setting all attributes and combinations of attributes 
                    for this file.
                4.  Attempting to open for write files with every possible 
                    attribute combination.
                5.  Attempting to write to files with every possible 
                    attribute combination.
                6.  Attempting to delete files with every possible attribute 
                    combination.
                7.  Clearing every possible attribute combination.
                8.  Deleting normal files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth1(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szPathBuf[MAX_PATH]; 
    TCHAR szTempStr[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), pMtdPart->GetClusterSize(), 
        pMtdPart->GetVolumeName(szPathBuf));
    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    StringCchPrintf(szTempStr, _countof(szTempStr), TEXT("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    if(!TestAllFileAttributes(szTempStr, pMtdPart->GetClusterSize()))
    {
        FAIL("TestAllFileAttributes()");
        goto Error;
    }
    if (!TestAllDirAttributes(szTempStr))
    {
        FAIL("TestAllDirAttributes()");
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:
    
    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test2

    PURPOSE:    To test creating, modifying and deleting a (cluster sized - 1) 
                file with every possible attribute combination.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating an 8.3 directory off the root.
                2.  Creating a file in this directory that is exactly one
                    byte less than an allocation unit in size.  This also 
                    gets read back and the data is compared with the original 
                    data.
                3.  Setting all attributes and combinations of attributes 
                    for this file.
                4.  Attempting to open for write files with every possible 
                    attribute combination.
                5.  Attempting to write to files with every possible 
                    attribute combination.
                6.  Attempting to delete files with every possible attribute 
                    combination.
                7.  Clearing every possible attribute combination.
                8.  Deleting normal files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth2(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szPathBuf[MAX_PATH]; 
    TCHAR szTempStr[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), pMtdPart->GetClusterSize()-1, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    StringCchPrintf(szTempStr, _countof(szTempStr), TEXT("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    if(!TestAllFileAttributes(szTempStr, pMtdPart->GetClusterSize()-1))
    {
        FAIL("TestAllFileAttributes()");
        goto Error;
    }
    
    if (!TestAllDirAttributes(szTempStr))
    {
        FAIL("TestAllDirAttributes()");
        goto Error;
    }
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test3

    PURPOSE:    To test creating, modifying and deleting a (cluster sized + 1) 
                file with every possible attribute combination.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating an 8.3 directory off the root.
                2.  Creating a file in this directory that is exactly one
                    byte more than an allocation unit in size.  This also 
                    gets read back and the data is compared with the original 
                    data.
                3.  Setting all attributes and combinations of attributes 
                    for this file.
                4.  Attempting to open for write files with every possible 
                    attribute combination.
                5.  Attempting to write to files with every possible 
                    attribute combination.
                6.  Attempting to delete files with every possible attribute 
                    combination.
                7.  Clearing every possible attribute combination.
                8.  Deleting normal files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth3(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szPathBuf[MAX_PATH]; 
    TCHAR szTempStr[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), pMtdPart->GetClusterSize()+1, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    StringCchPrintf(szTempStr, _countof(szTempStr), TEXT("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    if(!TestAllFileAttributes(szTempStr, pMtdPart->GetClusterSize()+1))
    {
        FAIL("TestAllFileAttributes()");
        goto Error;
    }
    
    if (!TestAllDirAttributes(szTempStr))
    {
        FAIL("TestAllDirAttributes()");
        goto Error;
    }
    // success
    retVal = TPR_PASS;
    
Error:
    
    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }

    return retVal;
}

/****************************************************************************

    FUNCTION:   Test4

    PURPOSE:    To test creating, modifying and deleting a 1 byte
                file with every possible attribute combination.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating an 8.3 directory off the root.
                2.  Creating a file in this directory that is exactly one
                    byte in size.  This also gets read back and the data is 
                    compared with the original data.
                3.  Setting all attributes and combinations of attributes 
                    for this file.
                4.  Attempting to open for write files with every possible 
                    attribute combination.
                5.  Attempting to write to files with every possible 
                    attribute combination.
                6.  Attempting to delete files with every possible attribute 
                    combination.
                7.  Clearing every possible attribute combination.
                8.  Deleting normal files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth4(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szPathBuf[MAX_PATH]; 
    TCHAR szTempStr[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), 1, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    StringCchPrintf(szTempStr, _countof(szTempStr), TEXT("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    if(!TestAllFileAttributes(szTempStr, 1))
    {
        FAIL("TestAllFileAttributes()");
        goto Error;
    }
    
    if (!TestAllDirAttributes(szTempStr))
    {
        FAIL("TestAllDirAttributes()");
        goto Error;
    }
    // success
    retVal = TPR_PASS;
    
Error:
    
    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test5

    PURPOSE:    To test creating, modifying and deleting a 0 byte
                file with every possible attribute combination.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating an 8.3 directory off the root.
                2.  Creating a file in this directory that is exactly 0
                    bytes in size.
                3.  Setting all attributes and combinations of attributes 
                    for this file.
                4.  Attempting to open for write files with every possible 
                    attribute combination.
                5.  Attempting to write to files with every possible 
                    attribute combination.
                6.  Attempting to delete files with every possible attribute 
                    combination.
                7.  Clearing every possible attribute combination.
                8.  Deleting normal files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth5(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szPathBuf[MAX_PATH]; 
    TCHAR szTempStr[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {
        Zorchage(g_pKato); 
        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), 0, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    StringCchPrintf(szTempStr, _countof(szTempStr), TEXT("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    if(!TestAllFileAttributes(szTempStr, 0))
    {
        FAIL("TestAllFileAttributes()");
        goto Error;
    }
    
    if (!TestAllDirAttributes(szTempStr))
    {
        FAIL("TestAllDirAttributes()");
        goto Error;
    }
    // success
    retVal = TPR_PASS;
    
Error:
    
    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test6

    PURPOSE:    To test creating deep single-level directories.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating single level directories of MAX_PATH +/- 10 in size
                    off the root.
                2.  Delete the single level directories off the root.
                
****************************************************************************/
TESTPROCAPI Tst_Depth6(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    DWORD dwCurSize;
    TCHAR szLongPath[2*MAX_PATH];
    TCHAR szPathBuf[MAX_PATH];
    BOOL fCallReturn;

    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    for(dwCurSize = MAX_PATH-10; dwCurSize <= MAX_PATH+10; dwCurSize++)
    {
        LOG(_T("Creating and removing %u byte directory"), dwCurSize);

        if(_tcslen(pMtdPart->GetVolumeName(szPathBuf)) > 1){
            StringCchPrintf(szLongPath, _countof(szLongPath), _T("%s\\%s%s"), pMtdPart->GetVolumeName(szPathBuf),
                A316_BYTE_PATH_OFF_ROOT1, A316_BYTE_PATH_OFF_ROOT2);
        }
        else{
            StringCchPrintf(szLongPath, _countof(szLongPath), _T("%s%s%s"), pMtdPart->GetVolumeName(szPathBuf),
                A316_BYTE_PATH_OFF_ROOT1, A316_BYTE_PATH_OFF_ROOT2);
        }

        szLongPath[dwCurSize] = _T('\0');

        fCallReturn = CreateAndRemoveRootDirectory(szLongPath, szPathBuf);

        if(dwCurSize < MAX_PATH)
        {
            CHECKTRUE(fCallReturn);
        }
        else
        {
            CHECKFALSE(fCallReturn);
        }
    }

    // success
    retVal = GetTestResult();
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test7

    PURPOSE:    To test creating deep multiple-level directories.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple level directories of MAX_PATH +/- x in size
                    off the root.(x =10 for small cards, 5 for large cards)
                2.  Delete the multiple level directories off the root.
                
****************************************************************************/
TESTPROCAPI Tst_Depth7(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    DWORD dwCurSize, dwVolPathSize, i;
    TCHAR szLongPath[2*MAX_PATH];
    TCHAR szPathBuf[MAX_PATH];
    BOOL fCallReturn;

    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }    

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    for(dwCurSize = MAX_PATH-10; dwCurSize <= MAX_PATH+10; dwCurSize++)
    {
        LOG(_T("Creating and removing %u byte directory"), dwCurSize);

        // get the length of the mount-point part of the string
        dwVolPathSize = _tcslen(pMtdPart->GetVolumeName(szPathBuf));

        //if not running off root
        if(dwVolPathSize > 1){
            StringCchPrintf(szLongPath, _countof(szLongPath), TEXT("%s\\%s"), szPathBuf, A316_BYTE_PATH_OFF_ROOT1);
            szLongPath[dwVolPathSize+2] = _T('\0');
        }
        else{
            StringCchPrintf(szLongPath, _countof(szLongPath), TEXT("%s%s"), szPathBuf, A316_BYTE_PATH_OFF_ROOT1);
            szLongPath[dwVolPathSize+2] = _T('\0');
        }
        if(FileExists(szLongPath))
        {
            LOG(TEXT("Warning, directory \"%s\" off root already exists!"), szLongPath);
        }

        //if not running off root
        if(dwVolPathSize > 1){
            StringCchPrintf(szLongPath, _countof(szLongPath), _T("%s\\%s%s"), szPathBuf,
            A316_BYTE_PATH_OFF_ROOT1, A316_BYTE_PATH_OFF_ROOT2);
        }
        else{
            StringCchPrintf(szLongPath, _countof(szLongPath), _T("%s%s%s"), szPathBuf,
            A316_BYTE_PATH_OFF_ROOT1, A316_BYTE_PATH_OFF_ROOT2);
        }

        // make this a deep multi-level directory by adding '\' every other character
        for(i = dwVolPathSize + 2; i <= dwCurSize; i+=2)
        {
            szLongPath[i] = _T('\\');
        }
        szLongPath[dwCurSize] = _T('\0');

        // make sure the last characer is not a '\'
        if(_T('\\') == szLongPath[dwCurSize-1])
            szLongPath[dwCurSize-1] = _T('z');

        fCallReturn = CreateAndRemoveRootDirectory(szLongPath, szPathBuf);

        if(dwCurSize < MAX_PATH)
        {
            //If we are running on a small disk (ie 1MB), we'll run out of sectors before we reach MAX_PATH.
            //CreateAndRemoveRootDirectory() will fail before we reach MAX_PATH.
            //We'll still run the test on smaller disks (ie anything < 1.5MB), because we want to exercise the case of
            //creating a directory and running out of sector.  However, we'll only check fCallReturn if the disk is larger
            //than 1.5MB.

            const DWORD MIN_FREE_SPACE_REQ = 0x162000;  //1.5MB
                              
            if (pMtdPart->GetCallerDiskFreeSpace() > MIN_FREE_SPACE_REQ)
            {
                CHECKTRUE(fCallReturn);
            }
        }
        else
        {
            CHECKFALSE(fCallReturn);
        }
    }

    // success
    retVal = GetTestResult();
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test8

    PURPOSE:    To test creating a file in a directory that does not exist.

    NOTE:       This tests a minimum of the following conditions:

                1.  The file should not be created and the system should 
                    fail gracefully.
                
****************************************************************************/

TESTPROCAPI Tst_Depth8(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    TCHAR szFileSpec[MAX_PATH];
    HANDLE hFile;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!CompleteRemoveDirectoryMinusPcCard(pMtdPart->GetTestFilePath(szPathBuf), 
        pMtdPart->GetVolumeName(szFileSpec)))
    {
        if(!DeleteTree(szPathBuf, TRUE))
        {
            LOG(_T("unable to delete path %s"), szPathBuf);
            FAIL("DeleteTree()");
            goto Error;
        }
    }

    StringCchPrintf(szFileSpec, _countof(szFileSpec), _T("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    hFile = CreateFile(szFileSpec, GENERIC_READ | GENERIC_WRITE, 0,
        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if(INVALID_HANDLE_VALUE != hFile)
    {
        FAIL("Created a file in invalid directory");
        CloseHandle(hFile);
        goto Error;
    }
    // success
    retVal = TPR_PASS;
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test9

    PURPOSE:    To test creating a bunch of directories within a directory,
                with each of the new directories containing a file.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple directories within a single directory.
                    NOTE: By creating enough directory entries the store will
                    need to use several allocation units to hold the dir
                    entries.
                2.  Creating files within each of these directories.
                3.  Finding files using FindFirstFile() and FindNextFile()
                    across several allocation units.
                4.  Closing handles from the FindFirstFile() and FindNextFile()
                    functions.  If the FindClose() call fails it will not 
                    release access to the directory, causing the 
                    RemoveDirectory() call to fail in DeleteTree().
                5.  Removing directories.
                6.  Deleting files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth9(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    UINT  nCurrentDirectory;
    TCHAR szFileSpec[MAX_PATH+20];
    TCHAR szPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(NULL == pMtdPart->GetVolumeName(szPathBuf))
    {
        FAIL("GetVolumeName()");
        goto Error;
    }
    
    for(nCurrentDirectory = 1; nCurrentDirectory <= g_testOptions.nFileCount; nCurrentDirectory++)
    {
        StringCchPrintf(szFileSpec, _countof(szFileSpec), _T("%s\\%04.04i"), pMtdPart->GetTestFilePath(szPathBuf), nCurrentDirectory);
        if(!CreateDirectoryAndFile(szFileSpec, TEST_FILE_NAME))
        {
            FAIL("CreateDirectoryAndFile()");
            goto Error;
        }            
    }
    
        
    // success
    retVal = GetTestResult();
    
Error:
    
    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test10

    PURPOSE:    To test creating a bunch of files within a directory,
                Copying them to another directory, moving this new
                directory to another directory and then deleting them 
                from the original directory and the moved to directory.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple files within a single directory.
                    NOTE: By creating enough directory entries the store will
                    need to use several allocation units to hold the dir
                    entries.
                2.  Copying files from one directory to another with various
                    attribute combinations set.
                3.  Moving files from one directory to another with various
                    attribute combinations set.
                4.  Removing directories.
                5.  Deleting files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth10(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    TCHAR szTestPathBuf[MAX_PATH];
    TCHAR szMovePathBuf[MAX_PATH];
    TCHAR szCopyPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), pMtdPart->GetClusterSize()-50, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CopyMoveAndDelForAllFileAttributes(pMtdPart->GetTestFilePath(szTestPathBuf),
        pMtdPart->GetCopyFilePath(szCopyPathBuf), pMtdPart->GetMoveFilePath(szMovePathBuf),
        FILE_ATTRIBUTE_NORMAL, g_testOptions.nFileCount, pMtdPart->GetClusterSize()-50,
        FALSE))
    {
        FAIL("CopyMoveAndDelForAllFileAttributes()");
        goto Error;
    }
        
    // success
    retVal = GetTestResult();
    
Error:    
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test11

    PURPOSE:    To test the FileTimeToLocalTime(), FileTimeToSystemTime() and
                LocalTimeToFileTime() functions.

                
****************************************************************************/
TESTPROCAPI Tst_Depth11(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!TestFileTimes(pMtdPart->GetTestFilePath(szPathBuf), TEST_FILE_NAME, 5000))
    {
        FAIL("TestFileTimes()");
        goto Error;
    }
        
    // success
    retVal = GetTestResult();
    
Error:

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test12

    PURPOSE:    To test the compression logic under fragmented memory
                conditions.  It does this by creating 4 byte files until
                there is no more memory available.  It then deletes every
                other file to free up half the space, with the maximum 
                contiguous space being 4 bytes.

    NOTE:       This tests a minimum of the following conditions:

                1.  Disk full situations.  What happens when you write to
                    a full store.
                2.  Writing a large file to the store when it is too 
                    fragmented to hold the file contiguously.
                
****************************************************************************/
TESTPROCAPI Tst_Depth12(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH], szFileName[MAX_PATH];
    DWORD dwNumFiles, dwCurFile;
    BOOL fDiskFull, fRetVal;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(100000, g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    // create 4 byte files to fill the rest of the disk
    dwNumFiles = 0;
    fDiskFull = FALSE;
    do
    {
        if(pMtdPart->GetCallerDiskFreeSpace() < pMtdPart->GetClusterSize())
        {
            fDiskFull = TRUE;
        }

        StringCchPrintf(szFileName, _countof(szFileName), TEXT("%08.08X.fil"), ++dwNumFiles);

        fRetVal = CreateTestFile(pMtdPart->GetTestFilePath(szPathBuf), szFileName, 4, NULL,
            MAX_EXPANSION);

        if(!fRetVal && !fDiskFull)
        {
            LOG(_T("Unable to create test file %s"), szFileName);
            LOG(_T("%u bytes free"), pMtdPart->GetCallerDiskFreeSpace());
        }
        else if(fDiskFull)
        {
            fRetVal = TRUE;
        }
        
    }while(!fDiskFull && fRetVal);

    // delete every other file
    for(dwCurFile = 1; fRetVal && (dwCurFile < dwNumFiles); dwCurFile +=2)
    {
        StringCchPrintf(szFileName, _countof(szFileName), TEXT("%s\\%08.08X.fil"), pMtdPart->GetTestFilePath(szPathBuf), 
            dwCurFile );
        fRetVal = DeleteFile(szFileName);
        if(!fRetVal)
        {
            LOG(_T("Unable to delete test file %s"), szFileName);
            ERRFAIL("DeleteFile()");
            goto Error;
        }
    }

    // deleted every other file, now create one using 1/2 the remaining space
    if(fRetVal)
    {
        if(!CreateTestFile(pMtdPart->GetTestFilePath(szPathBuf), TEST_FILE_NAME,
            pMtdPart->GetCallerDiskFreeSpace()/2, NULL, MAX_EXPANSION))
        {
            LOG(_T("Unable to create %u byte file with %u bytes free"),
                pMtdPart->GetCallerDiskFreeSpace()/2, pMtdPart->GetCallerDiskFreeSpace());
            goto Error;
        }
        
    }
        
    // success
    retVal = GetTestResult();
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test13

    PURPOSE:    To test the compression logic under fragmented memory
                conditions.  It does this by creating 4096 byte files until
                there is no more memory available.  It then deletes every
                other file to free up half the space, with the maximum 
                contiguous space being 4096 bytes.

    NOTE:       This tests a minimum of the following conditions:

                1.  Disk full situations.  What happens when you write to
                    a full store.
                2.  Writing a large file to the store when it is too 
                    fragmented to hold the file contiguously.
                3.  Compressing a 4096 byte block of expandable data into 
                    a 4096 byte block of memory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth13(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH], szFileName[MAX_PATH];
    DWORD dwNumFiles, dwCurFile;
    BOOL fDiskFull, fRetVal;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(pMtdPart->GetCallerDiskFreeSpace() > pMtdPart->GetClusterSize()*512)
    {
        if(!pMtdPart->FillDiskMinusXBytes(pMtdPart->GetClusterSize()*512, 
            g_testOptions.fQuickFill))
        {
            FAIL("FillDiskMinusXBytes()");
            goto Error;
        }
    }

    
    // create 4 byte files to fill the rest of the disk
    dwNumFiles = 0;
    fDiskFull = FALSE;
    do
    {
        if(pMtdPart->GetCallerDiskFreeSpace() < pMtdPart->GetClusterSize())
        {
            fDiskFull = TRUE;
        }

        StringCchPrintf(szFileName, _countof(szFileName), TEXT("%08.08X.fil"), ++dwNumFiles);

        fRetVal = CreateTestFile(pMtdPart->GetTestFilePath(szPathBuf), szFileName, 
            pMtdPart->GetClusterSize(), NULL, MAX_EXPANSION);

        if(!fRetVal && !fDiskFull)
        {
            LOG(_T("Unable to create test file %s"), szFileName);
            LOG(_T("%u bytes free"), pMtdPart->GetCallerDiskFreeSpace());
        }
        else if(fDiskFull)
        {
            fRetVal = TRUE;
        }
        //when in non destructive mode, break out of loop if > 75% of drive capacity is used
    }while( (g_fNonDestructive && !(pMtdPart->GetCallerDiskFreeSpace() > pMtdPart->GetClusterSize()*512*4)) || 
            (!fDiskFull && fRetVal));

    // delete every other file
    for(dwCurFile = 1; fRetVal && (dwCurFile < dwNumFiles); dwCurFile +=2)
    {
        StringCchPrintf(szFileName, _countof(szFileName), TEXT("%s\\%08.08X.fil"), pMtdPart->GetTestFilePath(szPathBuf), 
            dwCurFile );
        fRetVal = DeleteFile(szFileName);
        if(!fRetVal)
        {
            LOG(_T("Unable to delete test file %s"), szFileName);
            ERRFAIL("DeleteFile()");
            goto Error;
        }
    }

    // deleted every other file, now create one using 1/2 the remaining space
    // if non destructive was specifed there will 50% free at this point (from quick fill files)
    if(fRetVal)
    {
        if(!CreateTestFile(pMtdPart->GetTestFilePath(szPathBuf), TEST_FILE_NAME,
            pMtdPart->GetCallerDiskFreeSpace()/2, NULL, MAX_EXPANSION))
        {
            LOG(_T("Unable to create %u byte file with %u bytes free"),
                pMtdPart->GetCallerDiskFreeSpace()/2, pMtdPart->GetCallerDiskFreeSpace());
            goto Error;
        }
        
    }
        
    // success
    retVal = GetTestResult();
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test14

    PURPOSE:    To test creating a bunch of files within a directory,
                Copying them to another directory, attempting to copy 
                them again over the existing files, moving this new
                directory to another directory and then deleting them 
                from the original directory and the moved to directory.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple files within a single directory.
                    NOTE: By creating enough directory entries the store will
                    need to use several allocation units to hold the dir
                    entries.
                2.  Copying files from one directory to another with various
                    attribute combinations set.
                3.  Moving files from one directory to another with various
                    attribute combinations set.
                4.  Removing directories.
                5.  Deleting files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth14(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    TCHAR szTestPathBuf[MAX_PATH];
    TCHAR szMovePathBuf[MAX_PATH];
    TCHAR szCopyPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    LOG(TEXT("File size %u bytes on volume %s"), pMtdPart->GetClusterSize()-50, 
        pMtdPart->GetVolumeName(szPathBuf));

    if(!CopyMoveAndDelForAllFileAttributes(pMtdPart->GetTestFilePath(szTestPathBuf),
        pMtdPart->GetCopyFilePath(szCopyPathBuf), pMtdPart->GetMoveFilePath(szMovePathBuf),
        FILE_ATTRIBUTE_NORMAL, g_testOptions.nFileCount, pMtdPart->GetClusterSize()-50,
        TRUE))
    {
        FAIL("CopyMoveAndDelForAllFileAttributes()");
        goto Error;
    }
        
    // success
    retVal = GetTestResult();
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test15

    PURPOSE:    To test creating a bunch of files on the Storage Card,
                Copying them to the Object Store, moving this new
                directory from the Object Store to the Storage Card and 
                then deleting them.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple files within a single directory.
                    NOTE: By creating enough directory entries the store will
                    need to use several allocation units to hold the dir
                    entries.
                2.  Copying files from the Storage Card to the Object Store with 
                    various attribute combinations set.
                3.  Moving files from the Object Store to the Storage Card with 
                    various attribute combinations set.
                4.  Removing directories.
                5.  Deleting files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth15(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    TCHAR szTestPathBuf[MAX_PATH];
    TCHAR szMovePathBuf[MAX_PATH];
    TCHAR szCopyPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    DWORD dwFileSize = pMtdPart->GetClusterSize()-50;
    LOG(TEXT("File size %u bytes on volume %s"), dwFileSize, 
        pMtdPart->GetVolumeName(szPathBuf));
    
    ULARGE_INTEGER fb, tb, tfb;
    ::GetDiskFreeSpaceEx(_T("\\"), &fb, &tb, &tfb);
    if(fb.QuadPart < (g_testOptions.nFileCount * dwFileSize)) {
        LOG(_T("Obj Store has insufficient space for this test, skipping"));
        retVal = TPR_SKIP;
        goto Error;
    }

    if(!CopyMoveAndDelForAllFileAttributes(pMtdPart->GetTestFilePath(szTestPathBuf),
        pMtdPart->GetOsCopyFilePath(szCopyPathBuf), pMtdPart->GetMoveFilePath(szMovePathBuf),
        FILE_ATTRIBUTE_NORMAL, g_testOptions.nFileCount, dwFileSize,
        FALSE))
    {
        FAIL("CopyMoveAndDelForAllFileAttributes()");
        goto Error;
    }
        
    // success
    retVal = GetTestResult();
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test16

    PURPOSE:    To test creating a bunch of files in the Object Store,
                Copying them to the Storage Card, moving this new
                directory from the Storage Card to the Object Store and 
                then deleting them.

    NOTE:       This tests a minimum of the following conditions:

                1.  Creating multiple files within a single directory.
                    NOTE: By creating enough directory entries the store will
                    need to use several allocation units to hold the dir
                    entries.
                2.  Copying files from the Object Store to the Storage Card with 
                    various attribute combinations set.
                3.  Moving files from the Storage Card to the Object Store with 
                    various attribute combinations set.
                4.  Removing directories.
                5.  Deleting files.
                
****************************************************************************/
TESTPROCAPI Tst_Depth16(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    TCHAR szTestPathBuf[MAX_PATH];
    TCHAR szMovePathBuf[MAX_PATH];
    TCHAR szCopyPathBuf[MAX_PATH];
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    DWORD dwFileSize = pMtdPart->GetClusterSize()-50;
    LOG(TEXT("File size %u bytes on volume %s"), dwFileSize, 
        pMtdPart->GetVolumeName(szPathBuf));

    ULARGE_INTEGER fb, tb, tfb;
    ::GetDiskFreeSpaceEx(_T("\\"), &fb, &tb, &tfb);
    if(fb.QuadPart < (g_testOptions.nFileCount * dwFileSize)) {
        LOG(_T("Obj Store has insufficient space for this test, skipping"));
        retVal = TPR_SKIP;
        goto Error;
    }

    if(!CopyMoveAndDelForAllFileAttributes(pMtdPart->GetOsTestFilePath(szTestPathBuf),
        pMtdPart->GetCopyFilePath(szCopyPathBuf), pMtdPart->GetOsMoveFilePath(szMovePathBuf),
        FILE_ATTRIBUTE_NORMAL, g_testOptions.nFileCount, dwFileSize,
        FALSE))
    {
        FAIL("CopyMoveAndDelForAllFileAttributes()");
        goto Error;
    }
        
    // success
    retVal = GetTestResult();
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test17

    PURPOSE:    To test creating/removing the "Storage Card" directory in the 
                Object Store.

    NOTE:       This tests a minimum of the following conditions:

                1.  Makes sure that the "Storage Card" directory cannot be created
                    or deleted in the Object Store.
                
****************************************************************************/
TESTPROCAPI Tst_Depth17(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH];
    HANDLE hFile;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    // create directory
    //
    LOG(_T("Trying CreateDirectory(%s)..."), pMtdPart->GetVolumeName(szPathBuf));
    if(CreateDirectory(szPathBuf, NULL))
    {
        LOG(_T("CreateDirectory(%s) succeeded when it should have failed"),
            szPathBuf);
        FAIL("CreateDirectory()");
        goto Error;
    }
    LOG(_T("CreateDirectory(%s) failed as expected, error=%u"), pMtdPart->GetVolumeName(szPathBuf),
        GetLastError());

    // create file
    //
    LOG(_T("Trying CreateFile(%s)..."), pMtdPart->GetVolumeName(szPathBuf));
    hFile = CreateFile(szPathBuf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(VALID_HANDLE(hFile))
    {
        LOG(_T("CreateFile(%s) succeeded when it should have failed"),
            szPathBuf);
        FAIL("CreateFile()");
        CloseHandle(hFile);
        goto Error;
    }
    LOG(_T("CreateFile(%s) failed as expected, error=%u"), pMtdPart->GetVolumeName(szPathBuf),
        GetLastError());

    // remove directory
    //
    LOG(_T("Trying RemoveDirectory(%s)..."), pMtdPart->GetVolumeName(szPathBuf));
    if(RemoveDirectory(szPathBuf))
    {
        LOG(_T("RemoveDirectory(%s) succeeded when it should have failed"),
            szPathBuf);
        FAIL("RemoveDirectory()");
        goto Error;
    }
    LOG(_T("RemoveDirectory(%s) failed as expected, error=%u"), pMtdPart->GetVolumeName(szPathBuf),
        GetLastError());
        
    // success
    retVal = TPR_PASS;
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test18

    PURPOSE:    To test truncating a file on the Storage Card.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests creating a 100k file the Storage Card.
                2.  Tests truncating 10k off the end of the file.
                3.  Tests truncating the file to 10k from the beginning.
                
****************************************************************************/
TESTPROCAPI Tst_Depth18(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH], szFileName[MAX_PATH];
    HANDLE hFile;
    DWORD dwFilePtr;
    DWORD dwFileSize = 100000;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    // create at file to test with
    if(!CreateTestFile(szPathBuf, TEST_FILE_NAME, dwFileSize, NULL, REPETITIVE_BUFFER))
    {
        LOG(_T("Unable to create test file \"%s\\%s\""), szPathBuf, TEST_FILE_NAME);
        ERRFAIL("CreateTestFile()");
        goto Error;
    }

    // re-open the test file
    StringCchPrintf(szFileName, _countof(szFileName), _T("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, 0,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE(hFile))
    {
        LOG(_T("Unable to re-open test file \"%s\""), szFileName);
        ERRFAIL("CreateFile()");
        goto Error;
    }

    // seek to 10k from the end of file
    LOG(_T("Truncating file \"%s\", seeking from end of file..."), szFileName);
    dwFilePtr = SetFilePointer(hFile, -10000, NULL, FILE_END );
    if(dwFilePtr != dwFileSize-10000)
    {
        LOG(_T("Unable to set file pointer from the end in file \"%s\""),
            szFileName);
        LOG(_T("File Ptr == %lu"), dwFilePtr);
        LOG(_T("Expected File Ptr == %lu"), dwFileSize-10000);
        LOG(_T("Seek Value == %lu"), -10000);
        ERRFAIL("SetFilePointer(FILE_END)");
        goto Error;
    }
    
    if(!SetEndOfFile(hFile))
    {
        LOG(_T("Unable to truncate file \"%s\""), szFileName);
        ERRFAIL("SetEndOfFile()");
        goto Error;
    }

    CloseHandle(hFile);

    if(dwFilePtr != FileSize(szFileName))
    {
        LOG(_T("Unable to truncate the file \"%s\", file size mistmatch"),
            szFileName);
        LOG(_T("Expected file size == %lu"), dwFilePtr);
        LOG(_T("Actual file size == %lu"), FileSize(szFileName));
        FAIL("Truncating file");
        goto Error;
    }

    // re-open the test file
    hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, 0,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE(hFile))
    {
        LOG(_T("Unable to re-open test file \"%s\""), szFileName);
        ERRFAIL("CreateFile()");
        goto Error;
    }

    LOG(_T("Truncating file \"%s\", seeking from beginning of file..."), szFileName);
    dwFilePtr = SetFilePointer(hFile, 10000, NULL, FILE_BEGIN );
    if(dwFilePtr != 10000)
    {
        LOG(_T("Unable to set the file pointer from the beginning in file \"%s\""),
            szFileName);
        LOG(_T("File Ptr == %lu"), dwFilePtr);
        LOG(_T("Expected File Ptr == %lu"), 10000);
        LOG(_T("Seek Value == %lu"), 10000);
        ERRFAIL("SetFilePointer(FILE_BEGIN)");
        goto Error;
    }

    if(!SetEndOfFile(hFile))
    {
        LOG(_T("Unable to truncate file \"%s\""), szFileName);
        ERRFAIL("SetEndOfFile()");
        goto Error;
    }

    CloseHandle(hFile);

    if(dwFilePtr != FileSize(szFileName))
    {
        LOG(_T("Unable to truncate the file \"%s\", file size mistmatch"),
            szFileName);
        LOG(_T("Expected file size == %lu"), dwFilePtr);
        LOG(_T("Actual file size == %lu"), FileSize(szFileName));
        FAIL("Truncating file");
        goto Error;
    }
        
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test19

    PURPOSE:    To test creating more directory entries than the root can hold.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles the situation
                    where a user attempts to create too many root 
                    directory entries.
                
****************************************************************************/
TESTPROCAPI Tst_Depth19(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH], szDirName[MAX_PATH];
    DWORD dwMaxRootEntries, dwDirCounter, dwNumRootEntries;
    BOOL fDone;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    dwMaxRootEntries = pMtdPart->GetMaxRootDirEntries();
    if(ROOT_DIR_LIMIT < dwMaxRootEntries)
    {
        dwMaxRootEntries = ROOT_DIR_LIMIT;
        LOG(_T("Reducing maximum root directory entries for this volume to %u"), dwMaxRootEntries);
    }

    // kill off any dirs that match the one's we'll be creating for this test
    NukeDirectories(pMtdPart->GetVolumeName(szPathBuf), _T("*PATH.DIR"));

    dwDirCounter = pMtdPart->GetNumberOfRootDirEntries();

    if(dwDirCounter >= dwMaxRootEntries)
    {
        LOG(_T("The volume already contains too many root entries; skipping test (this not an error)."));
        retVal = TPR_SKIP;
        goto Error;
    }

    if(0 < dwDirCounter)
    {
        LOG(_T("Volume \"%s\" already contains %u root entries; test will attempt to create %u more"),
            pMtdPart->GetVolumeName(szPathBuf), dwDirCounter, dwMaxRootEntries - dwDirCounter);
    }
    
    fDone = FALSE;
    while(!fDone)
    {
        StringCchPrintf(szDirName, _countof(szDirName), _T("%s\\%03.03luPATH.DIR"), szPathBuf, dwDirCounter++);
        if(!CreateDirectory(szDirName, NULL))
        {
            ERR("CreateDirectory()");
            dwNumRootEntries = pMtdPart->GetNumberOfRootDirEntries();
            if(dwNumRootEntries >= dwMaxRootEntries)
            {
                LOG(_T("CreateDirectory() failed as expected with %lu root directory entries."), 
                    dwNumRootEntries );
                fDone = TRUE;
            }
            else
            {
                LOG(_T("ERROR: CreateDirectory() failed with only %lu root directory entries."), 
                    dwNumRootEntries );
                FAIL("CreateDirectory()");
                goto Error;
            }
        }
        else // create dir succeeded
        {
            //LOG(_T("Created dir %s ok"), szDirName);
            dwNumRootEntries = pMtdPart->GetNumberOfRootDirEntries();
            if(dwNumRootEntries >= dwMaxRootEntries)
            {
                LOG(_T("Successfully created %lu root directory entries."), 
                    dwNumRootEntries );
                fDone = TRUE;
            }
            if(!(dwNumRootEntries%32))
            {
                LOG(_T("Created %lu root directory entries"), dwNumRootEntries );
            }
        }
    }
        
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        NukeDirectories(pMtdPart->GetVolumeName(szPathBuf), _T("*PATH.DIR"));
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test20

    PURPOSE:    To test creating a file using the same name as an existing
                directory on the Storage Card.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles creating a file
                    whose name is the same as an existing directory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth20(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->CreateTestDirectory(TEST_FILE_NAME))
    {
        FAIL("CreateTestDirectory()");
        goto Error;
    }

    if(pMtdPart->CreateTestFile(TEST_FILE_NAME,  0))
    {
        FAIL("CreateFile() succeeded when a directory existed with the same name");
        goto Error;
    }

    LOG(_T("CreateFile() failed as expected when a directory already existed with the same name"));


    if(!pMtdPart->RemoveTestDirectory(TEST_FILE_NAME))
    {
        FAIL("RemoveTestDirectory()");
        goto Error;
    }

    // success
    retVal = TPR_PASS;
    
Error:
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test21

    PURPOSE:    To test creating a directory using the same name as an existing
                file on the Storage Card.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles creating a directory
                    whose name is the same as an existing file.
                
****************************************************************************/
TESTPROCAPI Tst_Depth21(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->CreateTestFile(TEST_FILE_NAME, 0))
    {
        FAIL("CreateTestFile()");
        goto Error;
    }

    if(pMtdPart->CreateTestDirectory(TEST_FILE_NAME))
    {
        FAIL("CreateTestDirectory() succeeded when a file existed with the same name");
        DETAIL("Attempting to delete test directory");
        if(!pMtdPart->RemoveTestDirectory(TEST_FILE_NAME))
        {
            DETAIL("Deletion of test directory failed, attempting to delete test file");
            if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
            {
                DETAIL("Deletion of test file failed as well.");
            }
        }

        goto Error;
    }

    LOG(_T("CreateFile() failed as expected when a file already existed with the same name"));


    if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
    {
        FAIL("DeleteTestFile()");
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:
    
    return retVal;
}


/****************************************************************************

    FUNCTION:   Test22

    PURPOSE:    To test creating > 999 files with the same extensions and
                first 8 characters in the file name on the Storage Card.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles creating short file names.
                    It has a limit of 999 and should fail when you attempt 
                    to create the 1,000th.
                
****************************************************************************/
TESTPROCAPI Tst_Depth22(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    TCHAR szPathBuf[MAX_PATH], szFileName[MAX_PATH], szTmpName[MAX_PATH];
    DWORD i;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }
    
    // Skip this test on TexFat and ExFat
    if (pMtdPart->LargeFileSupport())
    {
        LOG(_T("This is an ExFat or TexFat volume; skipping test (this not an error)."));
        return TPR_SKIP;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    LOG(_T("Creating 999 test files in \"%s\""), szPathBuf);
    for(i = 0; i < 999; i++)
    {
        StringCchPrintf(szFileName, _countof(szFileName), TEXT("%s%03.03X.tst"), LONG_FILE_NAME, i );
        if(!CreateTestFile(szPathBuf, szFileName, 0, NULL, REPETITIVE_BUFFER))
        {
            LOG(_T("Unable to create file #%u \"%s\\%s\""), i, szPathBuf, szFileName);
            ERRFAIL("CreateTestFile()");
            goto Error;
        }
    }

    LOG(_T("Attempting to create 1000th test file in \"%s\""), szPathBuf);
    StringCchPrintf(szFileName, _countof(szFileName), TEXT("%s999.tst"), LONG_FILE_NAME);
    if(CreateTestFile(szPathBuf, szFileName, 0, NULL, REPETITIVE_BUFFER))
    {
        LOG(_T("Created file #1000 \"%s\\%s\" when it should have failed"),
            szPathBuf, szFileName);
        FAIL("CreateTestFile()");
        goto Error;
    }
    else
    {
        ERR("CreateTestFile()");
        LOG(_T("Unable to create file #1000 \"%s\\%s\" as expected"), szPathBuf, szFileName);
    }

    if(!CreateTestFile(szPathBuf, TEST_FILE_NAME, 0, NULL, REPETITIVE_BUFFER))
    {
        LOG(_T("Unable to create test file \"%s\\%s\""), szPathBuf, TEST_FILE_NAME);
        ERRFAIL("CreateTestFile()");
        goto Error;
    }

    StringCchPrintf(szTmpName, _countof(szTmpName), _T("%s\\%s"), szPathBuf, TEST_FILE_NAME);
    StringCchPrintf(szFileName, _countof(szFileName), _T("%s\\%s999.tst"), szPathBuf, LONG_FILE_NAME);
    if(MoveFile(szTmpName, szFileName))
    {
        LOG(_T("Renamed test file from \"%s\" to \"%s\" when it should have failed"),
            szTmpName, szFileName);
        FAIL("MoveFile()");
        goto Error;
    }
    else
    {
        LOG(_T("Unable to rename test file from \"%s\" to \"%s\" as expected"),
            szTmpName, szFileName);
    }
   
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test23

    PURPOSE:    To test creating a 100 byte file on the Storage Card with 2
                available clusters.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a file.
                
****************************************************************************/
TESTPROCAPI Tst_Depth23(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(2*pMtdPart->GetClusterSize(), g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    if(!pMtdPart->CreateTestFile(TEST_FILE_NAME, 100))
    {
        FAIL("CreateTestFile()");
        goto Error;
    }

    if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
    {
        FAIL("DeleteTestFile()");
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test24

    PURPOSE:    To test creating a directory on the Storage Card with only one
                available cluster.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a directory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth24(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    // Skip this test on TexFat
    if (pMtdPart->TransactionSupport())
    {
        LOG(_T("This is a TexFat volume; skipping test (this not an error)."));
        return TPR_SKIP;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(1*pMtdPart->GetClusterSize(), g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    if(!pMtdPart->CreateTestDirectory(TEST_DIR_NAME))
    {
        FAIL("CreateTestDirectory()");
        goto Error;
    }

    if(!pMtdPart->RemoveTestDirectory(TEST_DIR_NAME))
    {
        FAIL("RemoveTestDirectory()");
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test25

    PURPOSE:    To test creating a 100 byte file on the Storage Card with 1
                available cluster.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a file.
                
****************************************************************************/
TESTPROCAPI Tst_Depth25(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {
        Zorchage(g_pKato); 
        return TPR_SKIP; 
    }
    
    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    // Skip this test on TexFat
    if (pMtdPart->TransactionSupport())
    {
        LOG(_T("This is a TexFat volume; skipping test (this not an error)."));
        return TPR_SKIP;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(1*pMtdPart->GetClusterSize(), g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    if(!pMtdPart->CreateTestFile(TEST_FILE_NAME, 100))
    {
        FAIL("CreateTestFile()");
        goto Error;
    }

    if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
    {
        FAIL("DeleteTestFile()");
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test26

    PURPOSE:    To test creating directories on the Storage Card with only one
                available cluster until the disk is full.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a directory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth26(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);
    
    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    TCHAR szDirName[MAX_PATH];

    BOOL fDone = FALSE;
    INT cLoop = 0;
    DWORD dwLastError = 0;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(1*pMtdPart->GetClusterSize(), g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    fDone = FALSE;
    while(!fDone)
    {
        StringCchPrintf(szDirName, _countof(szDirName), _T("%s.%03.03u"), TEST_DIR_NAME, cLoop);
        if(!pMtdPart->CreateTestDirectory(szDirName))
        {
            dwLastError = GetLastError();
            if(ERROR_DISK_FULL != dwLastError)
            {
                ERRFAIL("CreateTestDirectory()");
                goto Error;
            }
            else
            {
                fDone = TRUE;
            }
        }
        else
        {
            cLoop++;
        }
        if(ROOT_DIR_LIMIT == cLoop)
        {
            break;
        }
    }

    // remove all the directories we created
    for(cLoop--; cLoop >= 0; cLoop--)
    {
        StringCchPrintf(szDirName, _countof(szDirName), _T("%s.%03.03u"), TEST_DIR_NAME, cLoop);
        if(!pMtdPart->RemoveTestDirectory(szDirName))
        {
            ERRFAIL("RemoveTestDirectory()");
            goto Error;
        }
    }
    
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test27

    PURPOSE:    To test creating a directory on the Storage Card with no
                available clusters.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a directory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth27(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    // Skip this test on TexFat
    if (pMtdPart->TransactionSupport())
    {
        LOG(_T("This is a TexFat volume; skipping test (this not an error)."));
        return TPR_SKIP;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(0, g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    // should be unable to create a directory when the disk is full
    if(pMtdPart->CreateTestDirectory(TEST_DIR_NAME))
    {
        FAIL("CreateTestDirectory() succeeded when the disk was full");
        //attempt to remove directory that was created
        pMtdPart->RemoveTestDirectory(TEST_DIR_NAME);
        goto Error;
    }
    
    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test27

    PURPOSE:    To test creating a directory on the Storage Card with no
                available clusters.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a directory.
                
****************************************************************************/
TESTPROCAPI Tst_Depth28(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;

    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(0, g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    // should be able to create a zero-byte file even though disk is full
    if(!pMtdPart->CreateTestFile(TEST_FILE_NAME, 0))
    {
        FAIL("CreateTestFile()");
        goto Error;
    }
    if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
    {
        ERRFAIL("DeleteTestFile()");
        goto Error;
    }

    // success
    retVal = TPR_PASS;

Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

/****************************************************************************
    FUNCTION:   Test29

    PURPOSE:    To test creating a 100 byte file on the Storage Card with 0
                available clusters.

    NOTE:       This tests a minimum of the following conditions:

                1.  Tests how the Storage Card handles disk full situations
                    when creating a file.
                
****************************************************************************/
TESTPROCAPI Tst_Depth29(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

     // Skip this test on TexFat
    if (pMtdPart->TransactionSupport())
    {
        LOG(_T("This is a TexFat volume; skipping test (this not an error)."));
        return TPR_SKIP;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!pMtdPart->FillDiskMinusXBytes(0, g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        goto Error;
    }

    // should be unable to create a 100 byte file because disk is full
    if(pMtdPart->CreateTestFile(TEST_FILE_NAME, 100))
    {
        FAIL("CreateTestFile() succeeded when it should have failed");
        if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
        {
            ERRFAIL("DeleteTestFile()");
        }
        goto Error;
    }
    
    // Even though we should have failed to create a 100 byte file,
    // CreateFile() should have create a 0 byte file. We shall delete it:
    if(!pMtdPart->DeleteTestFile(TEST_FILE_NAME))
    {
        ERRFAIL("DeleteTestFile()");
        goto Error;
    }

    // success
    retVal = TPR_PASS;
    
Error:

    if(pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }
    
    return retVal;
}

TESTPROCAPI Tst_Depth30(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    UINT i = 0;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    TCHAR szPathBuf[MAX_PATH];
    TCHAR szFile[MAX_PATH];
    DWORD dwData = 0;
    DWORD dwWritten = 0;
    DWORD offset;
    DWORD maxIterations;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    offset = lpFTE->dwUserData;

    StringCchPrintf(szFile, _countof(szFile), _T("%s\\%s.DAT"), szPathBuf, TEST_FILE_NAME);
    LOG(_T("Creating file %s"), szFile);
    hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE(hFile))
    {
        ERRFAIL("CreateFile()");
        goto Error;
    }

    // see if this FSD supports RFWS, WFWS
    if(!ReadFileWithSeek(hFile, NULL, 0, NULL, NULL, 0, 0))
    {
        if(ERROR_NOT_SUPPORTED == GetLastError())
        {
            LOG(_T("ReadFileWithSeek() failed on %s; FSD does not support this API"), szFile);
            retVal = TPR_PASS;
            goto Error;
        }
        ERRFAIL("ReadFileWithSeek()");
        goto Error;
    }

    // fill the disk
    if(!pMtdPart->FillDiskMinusXBytes(1*pMtdPart->GetClusterSize(), g_testOptions.fQuickFill))
    {
        FAIL("FillDiskMinusXBytes()");
        pMtdPart->UnFillDisk();
        goto Error;
    }

    LOG(_T("Writing data to %s at %u offsets using WriteFileWithSeek()..."), szFile, offset);
    // write data to different offsets in the file until we fail from filling the disk
    for(i = 0; ; i++)
    {
        dwData = i;
        LOG(_T("File %s: writing 0x%08X at offset %u"), szFile, dwData, i*offset);
        if(!WriteFileWithSeek(hFile, &dwData, sizeof(dwData), &dwWritten, NULL, 
            i*offset, 0))
        {
            if(ERROR_DISK_FULL == GetLastError() ||
               ERROR_OUTOFMEMORY == GetLastError())
            {
                LOG(_T("Disk filled up while writing to file %s..., Error = %u"), szFile, GetLastError());
                // reset our maximum to the total number that we wrote
                maxIterations = i - 1;
                break;
            }
            ERRFAIL("WriteFileWithSeek()");
            LOG(_T("Unexpected error %u occured during WriteFileWithSeek"), GetLastError());
            goto Error;
        }
    }    
        
    // success
    retVal = TPR_PASS;
    
Error:

    if(VALID_HANDLE(hFile))
    {
        if(!CloseHandle(hFile))
        {
            ERRFAIL("CloseHandle()");
            retVal = TPR_FAIL;
        }
    }

    if (pMtdPart)
    {
        pMtdPart->UnFillDisk();
    }

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

TESTPROCAPI Tst_Depth31(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);

    DWORD retVal = TPR_FAIL;

    CMtdPart *pMtdPart = NULL;
    UINT i = 0;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    TCHAR szPathBuf[MAX_PATH];
    TCHAR szFile[MAX_PATH];
    DWORD dwData = 0;
    DWORD dwWritten = 0;
    DWORD offset;
    DWORD maxIterations = ITERATIONS;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }
    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {

        return TPR_SKIP; 
    }

    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }

    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
       retVal = TPR_PASS;
       LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
       goto Error;
    }

    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }

    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    if(!CompleteCreateDirectory(pMtdPart->GetTestFilePath(szPathBuf)))
    {
        FAIL("CompleteCreateDirectory()");
        goto Error;
    }

    offset = lpFTE->dwUserData;

    StringCchPrintf(szFile, _countof(szFile), _T("%s\\%s.DAT"), szPathBuf, TEST_FILE_NAME);
    LOG(_T("Creating file %s"), szFile);
    hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE(hFile))
    {
        ERRFAIL("CreateFile()");
        goto Error;
        
    }

    // see if this FSD supports RFWS, WFWS
    if(!ReadFileWithSeek(hFile, NULL, 0, NULL, NULL, 0, 0))
    {
        if(ERROR_NOT_SUPPORTED == GetLastError())
        {
            LOG(_T("ReadFileWithSeek() failed on %s; FSD does not support this API"), szFile);
            retVal = TPR_PASS;
            goto Error;
        }
        ERRFAIL("ReadFileWithSeek()");
        goto Error;
    }

    LOG(_T("Writing data to %s at %u offsets using WriteFileWithSeek()..."), szFile, offset);
    // write data to different offsets in the file
    for(i = 0; i < maxIterations ; i++)
    {
        dwData = i;
        LOG(_T("File %s: writing 0x%08X at offset %u"), szFile, dwData, i*offset);
        if(!WriteFileWithSeek(hFile, &dwData, sizeof(dwData), &dwWritten, NULL, 
            i*offset, 0))
        {
            if(ERROR_DISK_FULL == GetLastError() ||
               ERROR_OUTOFMEMORY == GetLastError())
            {
                LOG(_T("Disk filled up while writing to file %s... continuing test"), szFile);
                // reset our maximum to the total number that we wrote
                maxIterations = i;
                break;
            }
            ERRFAIL("WriteFileWithSeek()");
            goto Error;
        }
        
    }

    LOG(_T("Reading data from %s using ReadFileWithSeek() and verifying..."), szFile);
    // verify the data using RFWS
    for(i = 0; i < maxIterations; i++)
    {
        ReadFileWithSeek(hFile, &dwData, sizeof(dwData), &dwWritten, NULL, i*offset, 0);
        if (0 == dwWritten)
        {
            ERRFAIL("ReadFileWithSeek() : reading past end of file");
            goto Error;
        }
        LOG(_T("File %s: read 0x%08X at offset %u"), szFile, dwData, i*offset);
        if(dwData != i)
        {
            FAIL("data mismatch");
            goto Error;
        }
    }

    LOG(_T("Reading data from %s using SetFilePointer() and ReadFile() and verifying..."), szFile);
    // verify the data using SetFilePointer and ReadFile
    for(i = 0; i < maxIterations; i++)
    {
        if(0xFFFFFFFF == SetFilePointer(hFile, i*offset, NULL, FILE_BEGIN))
        {
            ERRFAIL("SetFilePointer()");
            goto Error;
        }
        if(!ReadFile(hFile, &dwData, sizeof(dwData), &dwWritten, NULL))
        {
            ERRFAIL("ReadFile()");
            goto Error;
        }
        LOG(_T("File %s: read 0x%08X at offset %u"), szFile, dwData, i*offset);
        if(dwData != i)
        {
            FAIL("data mismatch");
            goto Error;
        }
    }
        
    // success
    retVal = TPR_PASS;
    
Error:

    if(VALID_HANDLE(hFile))
    {
        if(!CloseHandle(hFile))
        {
            ERRFAIL("CloseHandle()");
            retVal = TPR_FAIL;
        }
    }

    if(pMtdPart && !DeleteTree(pMtdPart->GetTestFilePath(szPathBuf), FALSE))
    {
        LOG(_T("Unable to remove \"%s\""), szPathBuf);
        FAIL("DeleteTree()");
        retVal = TPR_FAIL;
    }
    
    return retVal;
}

/****************************************************************************

    FUNCTION:   Test32

    PURPOSE:    Tests if a directory containing a file with an open file
                handle can be moved to a parent directory.

****************************************************************************/

TESTPROCAPI Tst_Depth32(UINT uMsg, TPPARAM tpParam, LPFUNCTION_TABLE_ENTRY lpFTE )
{
    UNREFERENCED_PARAMETER(lpFTE);
    
    DWORD retVal = TPR_FAIL;
    
    CMtdPart * pMtdPart = NULL;
    TCHAR * szFileName = NULL;
    TCHAR * szVolumeName = NULL;
    TCHAR * szDirName = NULL;
    TCHAR * szSubDirName = NULL;
    TCHAR * szRelocatedDirName = NULL;
    
    if( TPM_QUERY_THREAD_COUNT == uMsg )
    {
        ((LPTPS_QUERY_THREAD_COUNT)tpParam)->dwThreadCount = GetPartitionCount();
        retVal = SPR_HANDLED;
        goto Error;
    }
    else if( TPM_EXECUTE != uMsg )
    {
        retVal = TPR_NOT_HANDLED;
        goto Error;
    }

    if(!IsWithinTestRange(g_pKato, lpFTE->dwUniqueID))
    {
        Zorchage(g_pKato);
        return TPR_SKIP;
    }
    
    if(0 == GetPartitionCount())
    {
        retVal = TPR_SKIP;
        LOG(_T("There are no [%s] stores with [%s] partitions to test, skipping"),
            g_testOptions.szProfile, g_testOptions.szFilesystem);
        goto Error;
    }
    
    if(((TPS_EXECUTE *)tpParam)->dwThreadNumber > GetPartitionCount())
    {
        retVal = TPR_PASS;
        LOG(_T("No partition for thread %u to test"), ((TPS_EXECUTE *)tpParam)->dwThreadNumber);
        goto Error;
    }
    
    pMtdPart = GetPartition(((TPS_EXECUTE *)tpParam)->dwThreadNumber-1);
    
    if(NULL == pMtdPart)
    {
        FAIL("GetPartition()");
        goto Error;
    }
    
    if (g_testOptions.fFormat)
    {
        retVal = FormatVolume(pMtdPart);
        if (retVal != TPR_PASS)
            goto Error;
    }

    // Allocate strings
    szFileName = new TCHAR[MAX_PATH];
    szVolumeName = new TCHAR[MAX_PATH];
    szDirName  = new TCHAR[MAX_PATH];
    szSubDirName = new TCHAR[MAX_PATH];
    szRelocatedDirName = new TCHAR[MAX_PATH];

    // Test that the strings were allocated
    if (!(szFileName && szVolumeName && szDirName
        && szSubDirName && szRelocatedDirName))
    {
        FAIL("Out of Memory");
        goto Error;
    }

    // Get the volume name
    pMtdPart->GetVolumeName(szVolumeName);
    
    // Create a top level test directory

    // This condition will get hit when FS is mounted as a root
    if(!wcscmp(_T("\\"), szVolumeName))
    {
        StringCchPrintf(szDirName, MAX_PATH,TEST_DIR_NAME);
    }
    else
    {
        StringCchPrintf(szDirName, MAX_PATH, _T("%s\\%s"), szVolumeName, TEST_DIR_NAME);
    }

    if(!CreateDirectory(szDirName, NULL))
    {
        ERRFAIL("CreateTestDirectory()");
        goto Error;
    }

    // Create a subdirectory in the top level directory
    // Add a suffix to the name to distiguish it from the top
    // level directory, to avoid name collisions later
    StringCchPrintf(szSubDirName, MAX_PATH, _T("%s\\%s02"), szDirName, TEST_DIR_NAME);
    
    if(!CreateDirectory(szSubDirName, NULL))
    {
        ERRFAIL("CreateTestDirectory()");
    }
    
    // Append the file name to test path
    StringCchPrintf(szFileName, MAX_PATH, L"%s\\%s", szSubDirName, TEST_FILE_NAME);

    // Create the file
    HANDLE hFile = CreateFile(
        szFileName,
        GENERIC_WRITE | GENERIC_READ,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    // Test for valid file handle
    if(INVALID_HANDLE(hFile))
    {
        ERRFAIL("CreateFile()");
        goto Error;
    }

    // Write out new string containing the relocated directory name

    // This condition will get hit when FS is mounted as a root
    if(!wcscmp(_T("\\") , szVolumeName))
    {
        StringCchPrintf(szRelocatedDirName, MAX_PATH, _T("%s02"), TEST_DIR_NAME);
    }
    else
    {
        StringCchPrintf(szRelocatedDirName, MAX_PATH, _T("%s\\%s02"), szVolumeName, TEST_DIR_NAME);
    }
    
    // Write out new string containg the relocated file name
    StringCchPrintf(szFileName, MAX_PATH, _T("%s\\%s"), szRelocatedDirName, TEST_FILE_NAME);

    // Attempt to move the subdirectory to the root
    if (!MoveFile(szSubDirName, szRelocatedDirName))
    {
        ERRFAIL("MoveFile()");
        goto Error;
    }

    // Close the file handle
    if (!CloseHandle(hFile))
    {
        ERRFAIL("CloseHandle()");
        goto Error;
    }
    
    // Clean up the objects created during the test
    
    // Delete top level test directory
    if(!RemoveDirectory(szDirName))
    {
        ERRFAIL("RemoveDirectory()");
        goto Error;
    }

    // Delete the test file
    if (!DeleteFile(szFileName))
    {
        ERRFAIL("DeleteFile()");
        goto Error;
    }

    // Finally, delete the relocated directory
    if(!RemoveDirectory(szRelocatedDirName))
    {
        ERRFAIL("RemoveDirectory()");
        goto Error;
    }
    
    // Delete strings
    delete[] szFileName;
    delete[] szVolumeName;
    delete[] szDirName;
    delete[] szSubDirName;
    delete[] szRelocatedDirName;

    // success
    retVal = TPR_PASS;

Error:
    
    return retVal;
}
