/*++

 Copyright (c) 2000 Microsoft Corporation

 Module Name:

   FailOpenFile.cpp

 Abstract:

   Force OpenFile to fail for the specified files.

 History:

    01/31/2001  robkenny    created
    03/13/2001  robkenny    Converted to CString
    02/07/2002  astritz     Converted to StrSafe

--*/

#include "precomp.h"
#include "charvector.h"

IMPLEMENT_SHIM_BEGIN(FailOpenFile)
#include "ShimHookMacro.h"

APIHOOK_ENUM_BEGIN
    APIHOOK_ENUM_ENTRY(OpenFile) 
APIHOOK_ENUM_END

CharVector  * g_FailList = NULL;

HFILE 
APIHOOK(OpenFile)(
    LPCSTR lpFileName,        // file name
    LPOFSTRUCT lpReOpenBuff,  // file information
    UINT uStyle               // action and attributes
    )
{
    int i;
    for (i = 0; i < g_FailList->Size(); ++i)
    {
        // Compare each fail name against the end of lpFileName
        const char * failName = g_FailList->Get(i);
        size_t failNameLen = strlen(failName);
        size_t fileNameLen = strlen(lpFileName);

        if (fileNameLen >= failNameLen)
        {
            if (_strnicmp(failName, lpFileName+fileNameLen-failNameLen, failNameLen) == 0)
            {
                // Force OpenFile to fail for this filename
                DPFN( eDbgLevelError, "Forcing OpenFile(%s) to fail", lpFileName); 
                return FALSE;
            }
        }
    }

    HFILE returnValue = ORIGINAL_API(OpenFile)(lpFileName, lpReOpenBuff, uStyle);
    return returnValue;
}

/*++

 Parse the command line, push each filename onto the end of the g_FailList.

--*/

BOOL ParseCommandLine(const char * cl)
{
    g_FailList = new CharVector;
    if (!g_FailList)
    {
        return FALSE;
    }

    if (cl != NULL && *cl)
    {
        int     argc = 0;
        LPSTR * argv = _CommandLineToArgvA(cl, & argc);
        if (argv)
        {
            for (int i = 0; i < argc; ++i)
            {
                if (!g_FailList->Append(argv[i]))
                {
                    // Memory failure
                    delete g_FailList;
                    g_FailList = NULL;
                    break;
                }
                DPFN( eDbgLevelSpew, "Adding %s to fail list", argv[i]); 
            }
            LocalFree(argv);
        }
    }
    return g_FailList != NULL;
}

/*++

 Handle attach and detach

--*/

BOOL
NOTIFY_FUNCTION(DWORD fdwReason)
{
    if (fdwReason == DLL_PROCESS_ATTACH) 
    {
        return ParseCommandLine(COMMAND_LINE);
    }
    return TRUE;
}


/*++

  Register hooked functions

--*/

HOOK_BEGIN
    CALL_NOTIFY_FUNCTION

    APIHOOK_ENTRY(KERNEL32.DLL, OpenFile)
HOOK_END

IMPLEMENT_SHIM_END

