Example #1
0
static HRESULT BeginChangeFile(
    __in LPCWSTR pwzFile,
    __in int iCompAttributes,
    __inout LPWSTR* ppwzCustomActionData
    )
{
    Assert(pwzFile && *pwzFile && ppwzCustomActionData);

    HRESULT hr = S_OK;
    BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;

    LPBYTE pbData = NULL;
    DWORD cbData = 0;

    LPWSTR pwzRollbackCustomActionData = NULL;

    if (fIs64Bit)
    {
        hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data");
    }
    else
    {
        hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write file indicator to custom action data");
    }

    hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write file to custom action data: %ls", pwzFile);

    // If the file already exits, then we have to put it back the way it was on failure
    if (FileExistsEx(pwzFile, NULL))
    {
        hr = FileRead(&pbData, &cbData, pwzFile);
        ExitOnFailure1(hr, "failed to read file: %ls", pwzFile);

        // Set up the rollback for this file
        hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData);
        ExitOnFailure(hr, "failed to write component bitness to rollback custom action data");

        hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData);
        ExitOnFailure1(hr, "failed to write file name to rollback custom action data: %ls", pwzFile);

        hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData);
        ExitOnFailure(hr, "failed to write file contents to rollback custom action data.");

        hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE);
        ExitOnFailure1(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile);

        ReleaseStr(pwzRollbackCustomActionData);
    }
LExit:
    ReleaseMem(pbData);

    return hr;
}
Example #2
0
extern "C" HRESULT DAPI LocProbeForFile(
    __in_z LPCWSTR wzBasePath,
    __in_z LPCWSTR wzLocFileName,
    __in_z_opt LPCWSTR wzLanguage,
    __inout LPWSTR* psczPath
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczProbePath = NULL;
    LANGID langid = 0;
    LPWSTR sczLangIdFile = NULL;

    // If a language was specified, look for a loc file in that as a directory.
    if (wzLanguage && *wzLanguage)
    {
        hr = PathConcat(wzBasePath, wzLanguage, &sczProbePath);
        ExitOnFailure(hr, "Failed to concat base path to language.");

        hr = PathConcat(sczProbePath, wzLocFileName, &sczProbePath);
        ExitOnFailure(hr, "Failed to concat loc file name to probe path.");

        if (FileExistsEx(sczProbePath, NULL))
        {
            ExitFunction();
        }
    }

    langid = ::GetUserDefaultLangID();

    hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
    ExitOnFailure(hr, "Failed to format user langid.");

    hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
    ExitOnFailure(hr, "Failed to concat user langid file name to base path.");

    if (FileExistsEx(sczProbePath, NULL))
    {
        ExitFunction();
    }

    if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid) 
    { 
        langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT); 
        
        hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); 
        ExitOnFailure(hr, "Failed to format user langid (default sublang).");

        hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); 
        ExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang).");

        if (FileExistsEx(sczProbePath, NULL)) 
        { 
            ExitFunction(); 
        } 
    }

    langid = ::GetSystemDefaultUILanguage();

    hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
    ExitOnFailure(hr, "Failed to format system langid.");

    hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
    ExitOnFailure(hr, "Failed to concat system langid file name to base path.");

    if (FileExistsEx(sczProbePath, NULL))
    {
        ExitFunction();
    }

    if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid) 
    { 
        langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT); 
        
        hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); 
        ExitOnFailure(hr, "Failed to format user langid (default sublang).");

        hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); 
        ExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang).");

        if (FileExistsEx(sczProbePath, NULL)) 
        { 
            ExitFunction(); 
        } 
    }

    // Finally, look for the loc file in the base path.
    hr = PathConcat(wzBasePath, wzLocFileName, &sczProbePath);
    ExitOnFailure(hr, "Failed to concat loc file name to base path.");

    if (!FileExistsEx(sczProbePath, NULL))
    {
        hr = E_FILENOTFOUND;
    }

LExit:
    if (SUCCEEDED(hr))
    {
        hr = StrAllocString(psczPath, sczProbePath, 0);
    }

    ReleaseStr(sczLangIdFile);
    ReleaseStr(sczProbePath);

    return hr;
}
Example #3
0
HRESULT HandleLock(
    __inout CFGDB_STRUCT *pcdb
    )
{
    HRESULT hr = S_OK;

    ::EnterCriticalSection(&pcdb->cs);
    ++pcdb->dwLockRefCount;

    if (1 < pcdb->dwLockRefCount)
    {
        ExitFunction1(hr = S_OK);
    }

    // This should only be set to TRUE if the database was successfully completely synced with local upon unlock
    pcdb->fUpdateLastModified = FALSE;

    // Connect to database, if it's a remote database
    if (pcdb->fRemote)
    {
        // If database path is present right now, clean up conflicted databases
        if (FileExistsEx(pcdb->sczDbPath, NULL))
        {
            hr = CleanConflictedDatabases(pcdb->sczDbDir, pcdb->sczDbPath);
            TraceError(hr, "Failed to clean conflicted databases, continuing");
            hr = S_OK;
        }

        hr = FileCreateTempW(L"Remote", L".sdf", &pcdb->sczDbCopiedPath, NULL);
        ExitOnFailure(hr, "Failed to create temp file to copy database file to");
    
        hr = FileEnsureCopy(pcdb->sczDbPath, pcdb->sczDbCopiedPath, TRUE);
        ExitOnFailure(hr, "Failed to copy remote database locally");

        hr = FileGetTime(pcdb->sczDbCopiedPath, NULL, NULL, &pcdb->ftBeforeModify);
        ExitOnFailure(hr, "Failed to get modified time of copied remote %ls", pcdb->sczDbCopiedPath);

        hr = SceEnsureDatabase(pcdb->sczDbCopiedPath, wzSqlCeDllPath, L"CfgRemote", 1, &pcdb->dsSceDb, &pcdb->psceDb);
        ExitOnFailure(hr, "Failed to ensure SQL CE database at %ls exists", pcdb->sczDbPath);

        // If the remote wasn't up when we initialized, we couldn't get cfg app id or GUID, so get it now
        if (DWORD_MAX == pcdb->dwCfgAppID)
        {
            hr = HandleEnsureSummaryDataTable(pcdb);
            ExitOnFailure(hr, "Failed to ensure remote database summary data");

            hr = GuidListEnsure(pcdb->pcdbLocal, pcdb->sczGuid, &pcdb->sczGuidRemoteInLocalKey);
            ExitOnFailure(hr, "Failed to ensure remote database is in local database's guid table");

            hr = GuidListEnsure(pcdb, pcdb->pcdbLocal->sczGuid, &pcdb->sczGuidLocalInRemoteKey);
            ExitOnFailure(hr, "Failed to ensure local database is in remote database's guid table");

            hr = ProductSet(pcdb, wzCfgProductId, wzCfgVersion, wzCfgPublicKey, TRUE, NULL);
            ExitOnFailure(hr, "Failed to set product to cfg product id");
            pcdb->dwCfgAppID = pcdb->dwAppID;
        }
    }

LExit:
    if (FAILED(hr))
    {
        --pcdb->dwLockRefCount;
        ::LeaveCriticalSection(&pcdb->cs);
    }

    return hr;
}
Example #4
0
static HRESULT DeleteEmptyDirectory(
    __in LEGACY_FILE_TYPE fileType,
    __in_z LPCWSTR wzPath
    )
{
    HRESULT hr = S_OK;

    LPWSTR sczParentDirectory = NULL;
    DWORD dwIndex = 0;
    LPWSTR pwcLastBackslash = NULL;

    // If it's an individual file and it exists, no point trying to delete any directories for it
    if (LEGACY_FILE_PLAIN == fileType)
    {
        if (FileExistsEx(wzPath, NULL))
        {
            ExitFunction1(hr = S_OK);
        }
    }
    else
    {
        // It's a directory, so delete children first
        hr = DeleteEmptyDirectoryChildren(wzPath);
        // This code is just an FYI that the directory was not empty and so wasn't deleted. It's not an error, so ignore it.
        if (FAILED(hr))
        {
            ExitFunction1(hr = S_OK);
        }
        ExitOnFailure(hr, "Failed to check for empty directories and delete them at path: %ls", wzPath);
    }

    hr = StrAllocString(&sczParentDirectory, wzPath, 0);
    ExitOnFailure(hr, "Failed to allocate copy of directory");

    // Eliminate any trailing backslashes from the directory first, if there are any
    dwIndex = lstrlenW(sczParentDirectory);
    if (0 == dwIndex)
    {
        hr = E_INVALIDARG;
        ExitOnFailure(hr, "Unexpected empty parent directory encountered while deleting empty directories");
    }

    --dwIndex; // Start at the last character of the string
    while (dwIndex > 0 && sczParentDirectory[dwIndex] == L'\\')
    {
        sczParentDirectory[dwIndex] = L'\0';
        --dwIndex;
    }

    if (0 == dwIndex)
    {
        hr = E_INVALIDARG;
        ExitOnFailure(hr, "Parent directory was entirely composed of backslashes!");
    }

    // Now delete any empty parent directories we see as well
    while (NULL != (pwcLastBackslash = wcsrchr(sczParentDirectory, L'\\')))
    {
        hr = DirEnsureDelete(sczParentDirectory, FALSE, FALSE);
        if (FAILED(hr))
        {
            LogErrorString(hr, "Failed to check for empty parent directories and delete them at directory: %ls", sczParentDirectory);
            hr = S_OK;
            break;
        }

        *pwcLastBackslash = L'\0';
    }

LExit:
    ReleaseStr(sczParentDirectory);

    return hr;
}
Example #5
0
// Searches subdirectories of the given path for the highest version of ngen.exe available
static HRESULT GetNgenVersion(
    __in LPWSTR pwzParentPath,
    __out LPWSTR* ppwzVersion
    )
{
    Assert(pwzParentPath);

    HRESULT hr = S_OK;
    DWORD dwError = 0;
    DWORD dwNgenFileFlags = 0;

    LPWSTR pwzVersionSearch = NULL;
    LPWSTR pwzNgen = NULL;
    LPWSTR pwzTemp = NULL;
    LPWSTR pwzTempVersion = NULL;
    DWORD dwMaxMajorVersion = 0; // This stores the highest major version we've seen so far
    DWORD dwMaxMinorVersion = 0; // This stores the minor version of the highest major version we've seen so far
    DWORD dwMajorVersion = 0; // This stores the major version of the directory we're currently considering
    DWORD dwMinorVersion = 0; // This stores the minor version of the directory we're currently considering
    BOOL fFound = TRUE;
    WIN32_FIND_DATAW wfdVersionDirectories;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    
    hr = StrAllocFormatted(&pwzVersionSearch, L"%s*", pwzParentPath);
    ExitOnFailure1(hr, "failed to create outer directory search string from string %ls", pwzParentPath);
    hFind = FindFirstFileW(pwzVersionSearch, &wfdVersionDirectories);
    if (hFind == INVALID_HANDLE_VALUE)
    {
        ExitWithLastError1(hr, "failed to call FindFirstFileW with string %ls", pwzVersionSearch);
    }

    while (fFound)
    {
        pwzTempVersion = (LPWSTR)&(wfdVersionDirectories.cFileName);

        // Explicitly exclude v1.1.4322, which isn't backwards compatible and is not supported
        if (wfdVersionDirectories.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if (0 != lstrcmpW(L"v1.1.4322", pwzTempVersion))
            {
                // A potential candidate directory was found to run ngen from - let's make sure ngen actually exists here
                hr = StrAllocFormatted(&pwzNgen, L"%s%s\\ngen.exe", pwzParentPath, pwzTempVersion);
                ExitOnFailure2(hr, "failed to create inner ngen search string with strings %ls and %ls", pwzParentPath, pwzTempVersion);

                // If Ngen.exe does exist as a file here, then let's check the file version
                if (FileExistsEx(pwzNgen, &dwNgenFileFlags) && (0 == (dwNgenFileFlags & FILE_ATTRIBUTE_DIRECTORY)))
                {
                    hr = FileVersion(pwzNgen, &dwMajorVersion, &dwMinorVersion);

                    if (FAILED(hr))
                    {
                        WcaLog(LOGMSG_VERBOSE, "Failed to get version of %ls - continuing", pwzNgen);
                    }
                    else if (dwMajorVersion > dwMaxMajorVersion || (dwMajorVersion == dwMaxMajorVersion && dwMinorVersion > dwMaxMinorVersion))
                    {
                        // If the version we found is the highest we've seen so far in this search, it will be our new best-so-far candidate
                        hr = StrAllocString(ppwzVersion, pwzTempVersion, 0);
                        ExitOnFailure1(hr, "failed to copy temp version string %ls to version string", pwzTempVersion);
                        // Add one for the backslash after the directory name
                        WcaLog(LOGMSG_VERBOSE, "Found highest-so-far version of ngen.exe (in directory %ls, version %u.%u.%u.%u)", *ppwzVersion, (DWORD)HIWORD(dwMajorVersion), (DWORD)LOWORD(dwMajorVersion), (DWORD)HIWORD(dwMinorVersion), (DWORD)LOWORD(dwMinorVersion));

                        dwMaxMajorVersion = dwMajorVersion;
                        dwMaxMinorVersion = dwMinorVersion;
                    }
                }
                else
                {
                    WcaLog(LOGMSG_VERBOSE, "Ignoring %ls because it doesn't contain the file ngen.exe", pwzTempVersion);
                }
            }
            else
            {
                WcaLog(LOGMSG_VERBOSE, "Ignoring %ls because it is from .NET Framework v1.1, which is not backwards compatible with other versions of the Framework and thus is not supported by this custom action.", pwzTempVersion);
            }
        }
        else
        {
            WcaLog(LOGMSG_VERBOSE, "Ignoring %ls because it isn't a directory", pwzTempVersion);
        }

        fFound = FindNextFileW(hFind, &wfdVersionDirectories);

        if (!fFound)
        {
            dwError = ::GetLastError();
            hr = (ERROR_NO_MORE_FILES == dwError) ? ERROR_SUCCESS : HRESULT_FROM_WIN32(dwError);
            ExitOnFailure1(hr, "Failed to call FindNextFileW() with query %ls", pwzVersionSearch);
        }
    }

    if (NULL == *ppwzVersion)
    {
        hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
        ExitOnRootFailure1(hr, "Searched through all subdirectories of %ls, but failed to find any version of ngen.exe", pwzParentPath);
    }
    else
    {
        WcaLog(LOGMSG_VERBOSE, "Using highest version of ngen found, located in this subdirectory: %ls, version %u.%u.%u.%u", *ppwzVersion, (DWORD)HIWORD(dwMajorVersion), (DWORD)LOWORD(dwMajorVersion), (DWORD)HIWORD(dwMinorVersion), (DWORD)LOWORD(dwMinorVersion));
    }

LExit:
    if (hFind != INVALID_HANDLE_VALUE)
    {
        if (0 == FindClose(hFind))
        {
            dwError = ::GetLastError();
            hr = HRESULT_FROM_WIN32(dwError);
            WcaLog(LOGMSG_STANDARD, "Failed to close handle created by outer FindFirstFile with error %x - continuing", hr);
        }
        hFind = INVALID_HANDLE_VALUE;
    }

    ReleaseStr(pwzVersionSearch);
    ReleaseStr(pwzNgen);
    ReleaseStr(pwzTemp);
    // Purposely don't release pwzTempVersion, because it wasn't allocated in this function, it's just a pointer to a string inside wfdVersionDirectories

    return hr;
}