Example #1
0
/*******************************************************************
 PipeConnectionUninitialize - free data in a pipe connection.

*******************************************************************/
void PipeConnectionUninitialize(
    __in BURN_PIPE_CONNECTION* pConnection
    )
{
    ReleaseFileHandle(pConnection->hCachePipe);
    ReleaseFileHandle(pConnection->hPipe);
    ReleaseHandle(pConnection->hProcess);
    ReleaseStr(pConnection->sczSecret);
    ReleaseStr(pConnection->sczName);

    memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION));
    pConnection->hPipe = INVALID_HANDLE_VALUE;
    pConnection->hCachePipe = INVALID_HANDLE_VALUE;
}
Example #2
0
static HRESULT InitializeResume(
    __in LPCWSTR wzDestinationPath,
    __out LPWSTR* psczResumePath,
    __out HANDLE* phResumeFile,
    __out DWORD64* pdw64ResumeOffset
    )
{
    HRESULT hr = S_OK;
    HANDLE hResumeFile = INVALID_HANDLE_VALUE;
    DWORD cbTotalReadResumeData = 0;
    DWORD cbReadData = 0;

    *pdw64ResumeOffset = 0;

    hr = CacheGetResumePath(wzDestinationPath, psczResumePath);
    ExitOnFailure1(hr, "Failed to calculate resume path from working path: %ls", wzDestinationPath);

    hResumeFile = ::CreateFileW(*psczResumePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hResumeFile)
    {
        ExitWithLastError1(hr, "Failed to create resume file: %ls", *psczResumePath);
    }

    do
    {
        if (!::ReadFile(hResumeFile, reinterpret_cast<BYTE*>(pdw64ResumeOffset) + cbTotalReadResumeData, sizeof(DWORD64) - cbTotalReadResumeData, &cbReadData, NULL))
        {
            ExitWithLastError1(hr, "Failed to read resume file: %ls", *psczResumePath);
        }
        cbTotalReadResumeData += cbReadData;
    } while (cbReadData && sizeof(DWORD64) > cbTotalReadResumeData);

    // Start over if we couldn't get a resume offset.
    if (cbTotalReadResumeData != sizeof(DWORD64))
    {
        *pdw64ResumeOffset = 0;
    }

    *phResumeFile = hResumeFile;
    hResumeFile = INVALID_HANDLE_VALUE;

LExit:
    ReleaseFileHandle(hResumeFile);
    return hr;
}
Example #3
0
// ---------------------------------------------------------------------------
// Name:        RawDataReader::Close
// Description: Close the raw file and release all handles and memory
// Author:      Rajeeb Barman
// Date:        26/09/2013
// ---------------------------------------------------------------------------
AMDTResult RawDataReader::Close()
{
    AMDTInt32 ret = AMDT_STATUS_OK;

    if (!g_isOnline && (NULL != m_hRawFile))
    {
        PwrCloseFile(m_hRawFile);
        m_hRawFile = NULL;
    }

    if (m_pBufferList && m_bufferCnt)
    {
        for (AMDTUInt16 cnt = 0; cnt < m_bufferCnt; cnt++)
        {
            RawBufferInfo* pBuff = m_pBufferList + cnt;
            AMDTUInt8* pMem = (AMDTUInt8*)(pBuff->uliBuffer.QuadPart);
            free(pMem);
            pBuff->ulvalidLength = 0;
        }
    }

    ReleaseFileHandle(&m_rawDataHdl);
    return ret;
}
Example #4
0
static DWORD WINAPI LoadThreadProc(
    __in LPVOID pvContext
    )
{
    HRESULT hr = S_OK;

    LOAD_THREAD_CONTEXT* pContext = static_cast<LOAD_THREAD_CONTEXT*>(pvContext);
    LPWSTR sczThemePath = pContext->sczThemePath;
    HWND hWnd = pContext->hWnd;

    // We can signal the initialization event as soon as we have copied the context
    // values into local variables.
    ::SetEvent(pContext->hInit);

    BOOL fComInitialized = FALSE;
    HANDLE hDirectory = INVALID_HANDLE_VALUE;
    LPWSTR sczDirectory = NULL;
    LPWSTR wzFileName = NULL;

    THEME* pTheme = NULL;
    HANDLE_THEME* pHandle = NULL;

    hr = ::CoInitialize(NULL);
    ExitOnFailure(hr, "Failed to initialize COM on load thread.");
    fComInitialized = TRUE;

    // Open a handle to the directory so we can put a notification on it.
    hr = PathGetDirectory(sczThemePath, &sczDirectory);
    ExitOnFailure(hr, "Failed to get path directory.");

     wzFileName = PathFile(sczThemePath);

    hDirectory = ::CreateFileW(sczDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
    if (INVALID_HANDLE_VALUE == hDirectory)
    {
        ExitWithLastError(hr, "Failed to open directory: %ls", sczDirectory);
    }

    BOOL fUpdated = FALSE;
    do
    {
        // Get the last modified time on the file we're loading for verification that the
        // file actually gets changed down below.
        FILETIME ftModified = { };
        FileGetTime(sczThemePath, NULL, NULL, &ftModified);

        // Try to load the theme file.
        hr = ThemeLoadFromFile(sczThemePath, &pTheme);
        if (FAILED(hr))
        {
            ::SendMessageW(hWnd, WM_THMVWR_THEME_LOAD_ERROR, 0, hr);
        }
        else
        {
            hr = AllocHandleTheme(pTheme, &pHandle);
            ExitOnFailure(hr, "Failed to allocate handle to theme");

            ::SendMessageW(hWnd, WM_THMVWR_NEW_THEME, 0, reinterpret_cast<LPARAM>(pHandle));
            pHandle = NULL;
        }

        fUpdated = FALSE;
        do
        {
            DWORD rgbNotifications[1024];
            DWORD cbRead = 0;
            if (!::ReadDirectoryChangesW(hDirectory, rgbNotifications, sizeof(rgbNotifications), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &cbRead, NULL, NULL))
            {
                ExitWithLastError(hr, "Failed while watching directory: %ls", sczDirectory);
            }

            // Wait for half a second to let all the file handles get closed to minimize access
            // denied errors.
            ::Sleep(500);

            FILE_NOTIFY_INFORMATION* pNotification = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(rgbNotifications);
            while (pNotification)
            {
                // If our file was updated, check to see if the modified time really changed. The notifications
                // are often trigger happy thinking the file changed two or three times in a row. Maybe it's AV
                // software creating the problems but actually checking the modified date works well.
                if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pNotification->FileName, pNotification->FileNameLength / sizeof(WCHAR), wzFileName, -1))
                {
                    FILETIME ft = { };
                    FileGetTime(sczThemePath, NULL, NULL, &ft);

                    fUpdated = (ftModified.dwHighDateTime < ft.dwHighDateTime) || (ftModified.dwHighDateTime == ft.dwHighDateTime && ftModified.dwLowDateTime < ft.dwLowDateTime);
                    break;
                }

                pNotification = pNotification->NextEntryOffset ? reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<BYTE*>(pNotification) + pNotification->NextEntryOffset) : NULL;
            }
        } while (!fUpdated);
    } while(fUpdated);

LExit:
    if (fComInitialized)
    {
        ::CoUninitialize();
    }

    ReleaseFileHandle(hDirectory);
    ReleaseStr(sczDirectory);
    ReleaseStr(sczThemePath);
    return hr;
}
Example #5
0
/*******************************************************************
 PipeCreatePipes - create the pipes and event to signal child process.

*******************************************************************/
extern "C" HRESULT PipeCreatePipes(
    __in BURN_PIPE_CONNECTION* pConnection,
    __in BOOL fCreateCachePipe,
    __out HANDLE* phEvent
    )
{
    Assert(pConnection->sczName);
    Assert(INVALID_HANDLE_VALUE == pConnection->hPipe);
    Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe);

    HRESULT hr = S_OK;
    PSECURITY_DESCRIPTOR psd = NULL;
    SECURITY_ATTRIBUTES sa = { };
    LPWSTR sczFullPipeName = NULL;
    HANDLE hPipe = INVALID_HANDLE_VALUE;
    HANDLE hCachePipe = INVALID_HANDLE_VALUE;

    // Only the grant special rights when the pipe is being used for "embedded"
    // scenarios (aka: there is no cache pipe).
    if (!fCreateCachePipe)
    {
        // Create the security descriptor that grants read/write/sync access to Everyone.
        // TODO: consider locking down "WD" to LogonIds (logon session)
        LPCWSTR wzSddl = L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW0x00100000;;;WD)";
        if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSddl, SDDL_REVISION_1, &psd, NULL))
        {
            ExitWithLastError(hr, "Failed to create the security descriptor for the connection event and pipe.");
        }

        sa.nLength = sizeof(sa);
        sa.lpSecurityDescriptor = psd;
        sa.bInheritHandle = FALSE;
    }

    // Create the pipe.
    hr = StrAllocFormatted(&sczFullPipeName, PIPE_NAME_FORMAT_STRING, pConnection->sczName);
    ExitOnFailure1(hr, "Failed to allocate full name of pipe: %ls", pConnection->sczName);

    // TODO: consider using overlapped IO to do waits on the pipe and still be able to cancel and such.
    hPipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, psd ? &sa : NULL);
    if (INVALID_HANDLE_VALUE == hPipe)
    {
        ExitWithLastError1(hr, "Failed to create pipe: %ls", sczFullPipeName);
    }

    if (fCreateCachePipe)
    {
        // Create the cache pipe.
        hr = StrAllocFormatted(&sczFullPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName);
        ExitOnFailure1(hr, "Failed to allocate full name of cache pipe: %ls", pConnection->sczName);

        hCachePipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL);
        if (INVALID_HANDLE_VALUE == hCachePipe)
        {
            ExitWithLastError1(hr, "Failed to create pipe: %ls", sczFullPipeName);
        }
    }

    pConnection->hCachePipe = hCachePipe;
    hCachePipe = INVALID_HANDLE_VALUE;

    pConnection->hPipe = hPipe;
    hPipe = INVALID_HANDLE_VALUE;

    // TODO: remove the following
    *phEvent = NULL;

LExit:
    ReleaseFileHandle(hCachePipe);
    ReleaseFileHandle(hPipe);
    ReleaseStr(sczFullPipeName);

    if (psd)
    {
        ::LocalFree(psd);
    }

    return hr;
}
Example #6
0
static HRESULT DownloadResource(
    __in BURN_USER_EXPERIENCE* pUX,
    __in_z LPCWSTR wzPackageOrContainerId,
    __in_z LPCWSTR wzPayloadId,
    __in HINTERNET hSession,
    __inout_z LPWSTR* psczUrl,
    __in_z_opt LPCWSTR wzUser,
    __in_z_opt LPCWSTR wzPassword,
    __in_z LPCWSTR wzDestinationPath,
    __in DWORD64 dw64AuthoredResourceLength,
    __in DWORD64 dw64ResourceLength,
    __in DWORD64 dw64ResumeOffset,
    __in HANDLE hResumeFile,
    __in_opt BURN_CACHE_CALLBACK* pCallback
    )
{
    HRESULT hr = S_OK;
    HANDLE hPayloadFile = INVALID_HANDLE_VALUE;
    DWORD cbMaxData = 64 * 1024; // 64 KB
    BYTE* pbData = NULL;
    BOOL fRangeRequestsAccepted = TRUE;
    LPWSTR sczRangeRequestHeader = NULL;
    HINTERNET hConnect = NULL;
    HINTERNET hUrl = NULL;
    LONGLONG llLength = 0;

    hPayloadFile = ::CreateFileW(wzDestinationPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hPayloadFile)
    {
        ExitWithLastError1(hr, "Failed to create download destination file: %ls", wzDestinationPath);
    }

    // Allocate a memory block on a page boundary in case we want to do optimal writing.
    pbData = static_cast<BYTE*>(::VirtualAlloc(NULL, cbMaxData, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
    ExitOnNullWithLastError(pbData, hr, "Failed to allocate buffer to download files into.");

    // Let's try downloading the file assuming that range requests are accepted. If range requests
    // are not supported we'll have to start over and accept the fact that we only get one shot
    // downloading the file however big it is. Hopefully, not more than 2 GB since wininet doesn't
    // like files that big.
    while (fRangeRequestsAccepted && (0 == dw64ResourceLength || dw64ResumeOffset < dw64ResourceLength))
    {
        hr = AllocateRangeRequestHeader(dw64ResumeOffset, 0 == dw64ResourceLength ? dw64AuthoredResourceLength : dw64ResourceLength, &sczRangeRequestHeader);
        ExitOnFailure(hr, "Failed to allocate range request header.");

        ReleaseNullInternet(hConnect);
        ReleaseNullInternet(hUrl);

        hr = MakeRequest(pUX, wzPackageOrContainerId, wzPayloadId, hSession, psczUrl, L"GET", sczRangeRequestHeader, wzUser, wzPassword, &hConnect, &hUrl, &fRangeRequestsAccepted);
        ExitOnFailure1(hr, "Failed to request URL for download: %ls", *psczUrl);

        // If we didn't get the size of the resource from the initial "HEAD" request
        // then let's try to get the size from this "GET" request.
        if (0 == dw64ResourceLength)
        {
            hr = InternetGetSizeByHandle(hUrl, &llLength);
            if (SUCCEEDED(hr))
            {
                dw64ResourceLength = llLength;
            }
            else // server didn't tell us the resource length.
            {
                // Fallback to the authored size of the resource. However, since we
                // don't really know the size on the server, don't try to use
                // range requests either.
                dw64ResourceLength = dw64AuthoredResourceLength;
                fRangeRequestsAccepted = FALSE;
            }
        }

        // If we just tried to do a range request and found out that it isn't supported, start over.
        if (!fRangeRequestsAccepted)
        {
            // TODO: log a message that the server did not accept range requests.
            dw64ResumeOffset = 0;
        }

        hr = WriteToFile(hUrl, hPayloadFile, &dw64ResumeOffset, hResumeFile, dw64ResourceLength, pbData, cbMaxData, pCallback);
        ExitOnFailure1(hr, "Failed while reading from internet and writing to: %ls", wzDestinationPath);
    }

LExit:
    ReleaseInternet(hUrl);
    ReleaseInternet(hConnect);
    ReleaseStr(sczRangeRequestHeader);
    if (pbData)
    {
        ::VirtualFree(pbData, 0, MEM_RELEASE);
    }
    ReleaseFileHandle(hPayloadFile);

    return hr;
}
Example #7
0
extern "C" HRESULT WininetDownloadUrl(
    __in BURN_USER_EXPERIENCE* pUX,
    __in BURN_CACHE_CALLBACK* pCallback,
    __in_z LPCWSTR wzPackageOrContainerId,
    __in_z LPCWSTR wzPayloadId,
    __in BURN_DOWNLOAD_SOURCE* pDownloadSource,
    __in DWORD64 dw64AuthoredDownloadSize,
    __in LPCWSTR wzDestinationPath
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczUrl = NULL;
    HINTERNET hSession = NULL;
    DWORD dwTimeout = 0;
    LPWSTR sczResumePath = NULL;
    HANDLE hResumeFile = INVALID_HANDLE_VALUE;
    DWORD64 dw64ResumeOffset = 0;
    DWORD64 dw64Size = 0;
    FILETIME ftCreated = { };

    // Copy the download source into a working variable to handle redirects then
    // open the internet session.
    hr = StrAllocString(&sczUrl, pDownloadSource->sczUrl, 0);
    ExitOnFailure(hr, "Failed to copy download source URL.");

    hSession = ::InternetOpenW(L"Burn", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    ExitOnNullWithLastError(hSession, hr, "Failed to open internet session");

    // Make a best effort to set the download timeouts to 2 minutes or whatever policy says.
    PolcReadNumber(BURN_POLICY_REGISTRY_PATH, L"DownloadTimeout", 2 * 60, &dwTimeout);
    if (0 < dwTimeout)
    {
        dwTimeout *= 1000; // convert to milliseconds.
        ::InternetSetOptionW(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
        ::InternetSetOptionW(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
        ::InternetSetOptionW(hSession, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
    }

    // Get the resource size and creation time from the internet.
    hr = GetResourceMetadata(pUX, wzPackageOrContainerId, wzPayloadId, hSession, &sczUrl, pDownloadSource->sczUser, pDownloadSource->sczPassword, &dw64Size, &ftCreated);
    ExitOnFailure1(hr, "Failed to get size and time for URL: %ls", sczUrl);

    // Ignore failure to initialize resume because we will fall back to full download then
    // download.
    InitializeResume(wzDestinationPath, &sczResumePath, &hResumeFile, &dw64ResumeOffset);

    hr = DownloadResource(pUX, wzPackageOrContainerId, wzPayloadId, hSession, &sczUrl, pDownloadSource->sczUser, pDownloadSource->sczPassword, wzDestinationPath, dw64AuthoredDownloadSize, dw64Size, dw64ResumeOffset, hResumeFile, pCallback);
    ExitOnFailure1(hr, "Failed to download URL: %ls", sczUrl);

    // Cleanup the resume file because we successfully downloaded the whole file.
    if (sczResumePath && *sczResumePath)
    {
        ::DeleteFileW(sczResumePath);
    }

LExit:
    ReleaseFileHandle(hResumeFile);
    ReleaseStr(sczResumePath);
    ReleaseInternet(hSession);
    ReleaseStr(sczUrl);

    return hr;
}
Example #8
0
/*******************************************************************
Dutil_AssertMsg

*******************************************************************/
extern "C" void DAPI Dutil_AssertMsg(
    __in_z LPCSTR szMessage
    )
{
    static BOOL fInAssert = FALSE; // TODO: make this thread safe (this is a cheap hack to prevent re-entrant Asserts)

    HRESULT hr = S_OK;
    DWORD er = ERROR_SUCCESS;

    int id = IDRETRY;
    HKEY hkDebug = NULL;
    HANDLE hAssertFile = INVALID_HANDLE_VALUE;
    char szPath[MAX_PATH] = { };
    DWORD cch = 0;

    if (fInAssert)
    {
        return;
    }
    fInAssert = TRUE;

    char szMsg[DUTIL_STRING_BUFFER];
    hr = ::StringCchCopyA(szMsg, countof(szMsg), szMessage);
    ExitOnFailure(hr, "failed to copy message while building assert message");

    if (Dutil_pfnDisplayAssert)
    {
        // call custom function to display the assert string
        if (!Dutil_pfnDisplayAssert(szMsg))
        {
            ExitFunction();
        }
    }
    else
    {
        OutputDebugStringA(szMsg);
    }

    if (!Dutil_fNoAsserts)
    {
        er = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Delivery\\Debug", 0, KEY_QUERY_VALUE, &hkDebug);
        if (ERROR_SUCCESS == er)
        {
            cch = countof(szPath);
            er = ::RegQueryValueExA(hkDebug, "DeliveryAssertsLog", NULL, NULL, reinterpret_cast<BYTE*>(szPath), &cch);
            szPath[countof(szPath) - 1] = '\0'; // ensure string is null terminated since registry won't guarantee that.
            if (ERROR_SUCCESS == er)
            {
                hAssertFile = ::CreateFileA(szPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (INVALID_HANDLE_VALUE != hAssertFile)
                {
                    ::SetFilePointer(hAssertFile, 0, 0, FILE_END);
                    ::StringCchCatA(szMsg, countof(szMsg), "\r\n");
                    ::WriteFile(hAssertFile, szMsg, lstrlenA(szMsg), &cch, NULL);
                }
            }
        }

        // if anything went wrong while fooling around with the registry, just show the usual assert dialog box
        if (ERROR_SUCCESS != er)
        {
            hr = ::StringCchCatA(szMsg, countof(szMsg), "\nAbort=Debug, Retry=Skip, Ignore=Skip all");
            ExitOnFailure(hr, "failed to concat string while building assert message");

            id = ::MessageBoxA(0, szMsg, "Debug Assert Message",
                MB_SERVICE_NOTIFICATION | MB_TOPMOST | 
                MB_DEFBUTTON2 | MB_ABORTRETRYIGNORE);
        }
    }

    if (id == IDABORT)
    {
        if (Dutil_hAssertModule)
        {
            ::GetModuleFileNameA(Dutil_hAssertModule, szPath, countof(szPath));

            hr = ::StringCchPrintfA(szMsg, countof(szMsg), "Module is running from: %s\nIf you are not using pdb-stamping, place your PDB near the module and attach to process id: %d (0x%x)", szPath, ::GetCurrentProcessId(), ::GetCurrentProcessId());
            if (SUCCEEDED(hr))
            {
                ::MessageBoxA(0, szMsg, "Debug Assert Message", MB_SERVICE_NOTIFICATION | MB_TOPMOST | MB_OK);
            }
        }

        ::DebugBreak();
    }
    else if (id == IDIGNORE)
    {
        Dutil_fNoAsserts = TRUE;
    }

LExit:
    ReleaseFileHandle(hAssertFile);
    ReleaseRegKey(hkDebug);
    fInAssert = FALSE;
}