|
|
//--------------------------------------------------------------
//
// File: loadfiles
//
// Contents: Load files.
//
//---------------------------------------------------------------
#include "loadhead.cxx"
#pragma hdrstop
#include <common.hxx>
#include <loadstate.hxx>
#include <bothchar.hxx>
#include <section.hxx>
#include <special.hxx>
#include <fileutil.cxx>
#define CREATE_DIRECTORY_MAX_PATH 248
//---------------------------------------------------------------
CSection *g_pcsSectionList = NULL;
CSpecialDirectory g_csdCurrent; CSpecialDirectory g_csdOld;
CRuleList g_crlExcludeWildcards; CRuleList g_crlIncludeWildcards;
//---------------------------------------------------------------
DWORD ComputeTemp() { return ERROR_SUCCESS; }
//---------------------------------------------------------------
void EraseTemp() { }
DWORD FixShellShortcut(const TCHAR *ptsFile) { HRESULT hr; IShellLink *pisl = NULL; IPersistFile *pipf = NULL; TCHAR *ptsDest = NULL; WIN32_FIND_DATA wfd;
if (DebugOutput) Win32Printf(LogFile, "Called FixShellShortcut for %s\r\n", ptsFile); hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&pisl); if (FAILED(hr)) goto cleanup;
hr = pisl->QueryInterface(IID_IPersistFile, (void **)&pipf); if (FAILED(hr)) goto cleanup;
hr = pipf->Load(ptsFile, 0); if (FAILED(hr)) goto cleanup; TCHAR ptsPath[MAX_PATH + 1]; hr = pisl->GetPath(ptsPath, MAX_PATH + 1, &wfd, SLGP_RAWPATH); if (FAILED(hr)) goto cleanup;
if (DebugOutput) Win32Printf(LogFile, "Retrieved path %s from shell link %s\r\n", ptsPath, ptsFile);
hr = WhereIsThisFile(ptsPath, &ptsDest); if (hr == ERROR_SUCCESS) { //Change the shortcut
//Expand any environment strings in the original data with
//the values for the user we're loading for. If the final
//paths match, we'll retain the version of the data with the
//unexpanded environment variables in it. Otherwise, we take
//the full path.
//We could be much smarter here if we wanted to.
//For instance:
// 1) Check the old path against the old special directories
// list, and try to remap things that match.
// 2) Double check to make sure the shortcut is actually
// broken before we go ahead and fix it.
TCHAR tsExpand[MAX_PATH + 1]; TCHAR tsTemp[MAX_PATH + 1]; TCHAR *ptsFinalDest; if (_tcslen(ptsPath) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: ptsPath too long %s\r\n", ptsPath); goto cleanup; } _tcscpy(tsExpand, ptsPath); hr = ExpandEnvStringForUser(tsExpand, tsTemp, &ptsFinalDest); if (hr) goto cleanup;
if (_tcsicmp(ptsDest, ptsFinalDest) == 0) { //They're the same, use the string with the environment
//variables in it.
ptsFinalDest = ptsPath; } else { ptsFinalDest = ptsDest; } hr = pisl->SetPath(ptsFinalDest); if (FAILED(hr)) goto cleanup;
if (DebugOutput) Win32Printf(LogFile, "FixShellShortcut fixed %s from %s to %s\r\n", ptsFile, ptsPath, ptsFinalDest); }
//If this function failed, we leave the shortcut alone. A possible
//change is to delete the shortcut for this case.
cleanup: if (ptsDest != NULL) free(ptsDest);
if (pipf != NULL) pipf->Release();
if (pisl != NULL) pisl->Release(); return ERROR_SUCCESS; }
DWORD ExpandEnvStringForUser(TCHAR *ptsString, TCHAR *ptsTemp, TCHAR **pptsFinal) { return g_csdCurrent.ExpandMacro(ptsString, ptsTemp, pptsFinal, FALSE); }
//---------------------------------------------------------------
DWORD WhereIsThisFile( const TCHAR *ptsFile, TCHAR **pptsNewFile ) { CSection *pcsCurrent = g_pcsSectionList; TCHAR tsExpName[MAX_PATH + 1]; TCHAR tsTemp[MAX_PATH + 1]; TCHAR *ptsFullName; DWORD dwErr;
if (_tcslen(ptsFile) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: ptsFile too long %s\r\n", ptsFile); return ERROR_FILENAME_EXCED_RANGE; }
_tcscpy(tsExpName, ptsFile); dwErr = g_csdOld.ExpandMacro(tsExpName, tsTemp, &ptsFullName, FALSE); if (dwErr) return dwErr; while (pcsCurrent != NULL) { TCHAR *ptsFileOnly; ptsFileOnly = _tcsrchr(ptsFullName, '\\');
if ((NULL == ptsFileOnly) || (_tcsnicmp(ptsFullName, pcsCurrent->GetSectionPath(), pcsCurrent->GetSectionPathLength()) == 0)) { //Section matches, search for file
if (NULL == ptsFileOnly) { ptsFileOnly = ptsFullName; } else { ptsFileOnly = ptsFullName + pcsCurrent->GetSectionPathLength() + 1; } for (ULONG i = 0; i < pcsCurrent->GetNameCount(); i++) { const TCHAR *ptsCurrent = pcsCurrent->GetFullFileName(i);
if (_tcsicmp(ptsFileOnly, ptsCurrent) == 0) { TCHAR tsDest[MAX_PATH + 1]; const TCHAR *ptsDest = pcsCurrent->GetDestination(i);
if (ptsDest == NULL) { DWORD dwDestLen = pcsCurrent->GetSectionDestLength(); if (dwDestLen + _tcslen(ptsCurrent) + 1 > MAX_PATH) { if (Verbose) { Win32Printf(LogFile, "Error: destination too long %s\\%s\r\n", pcsCurrent->GetSectionDest(), ptsCurrent); } return ERROR_FILENAME_EXCED_RANGE; } _tcscpy(tsDest, pcsCurrent->GetSectionDest()); tsDest[dwDestLen] = TEXT('\\'); _tcscpy(tsDest + dwDestLen + 1, ptsCurrent); ptsDest = tsDest; } //Bingo, direct hit.
*pptsNewFile = (TCHAR *) malloc( (_tcslen(ptsDest) + 1) * sizeof(TCHAR));
if (*pptsNewFile == NULL) return ERROR_NOT_ENOUGH_MEMORY; _tcscpy( *pptsNewFile, ptsDest);
if (DebugOutput) Win32Printf(LogFile, "WhereIsThisFile(%ws) found %ws\r\n", ptsFile, *pptsNewFile);
return ERROR_SUCCESS; } } } pcsCurrent = pcsCurrent->GetNextSection(); } return ERROR_NOT_FOUND; }
DWORD AddInfSectionToRuleList(INFCONTEXT *pic, CRuleList *pfl, BOOL fAllowRename) { TCHAR buf[MAX_PATH + 1]; TCHAR bufMacro[MAX_PATH + 1]; TCHAR *ptsFinalName; TCHAR bufTag[MAX_PATH + 1]; DWORD dwErr; CRuleList *prl; do { DWORD dwIndex; DWORD cFields; BOOL fDirectoryTag = FALSE; cFields = SetupGetFieldCount(pic);
if (((cFields != 1) && !fAllowRename) || ((cFields > 2) && fAllowRename)) { Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "Line contains more than one file name\r\n"); return ERROR_INVALID_PARAMETER; }
if (!SetupGetStringField(pic, 1, buf, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; }
if (SetupGetStringField(pic, 0, bufTag, MAX_PATH + 1, NULL)) { if (_tcsicmp(bufTag, buf)) { //Someone put a field identifier on there. The only
//one we recognize is 'dir'
if (_tcsicmp(bufTag, TEXT("dir"))) { Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "Unknown tag %s\r\n", bufTag); return ERROR_INVALID_PARAMETER; } fDirectoryTag = TRUE; } }
dwErr = g_csdOld.ExpandMacro(buf, bufMacro, &ptsFinalName, TRUE); if (dwErr) return dwErr;
if (fDirectoryTag) { //Append a backslash
if (_tcslen(ptsFinalName) >= MAX_PATH) { if (DebugOutput) { Win32Printf(LogFile, "Error: ptsFinalName too long %s\r\n", ptsFinalName); } return ERROR_FILENAME_EXCED_RANGE; }
_tcscat(ptsFinalName, TEXT("\\")); }
dwErr = pfl->SetName(ptsFinalName, &prl); if (dwErr) { return dwErr; }
if (cFields == 2) { if (!SetupGetStringField(pic, 2, buf, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; } dwErr = prl->SetDestination(buf); if (dwErr) { return dwErr; } } } while (SetupFindNextLine(pic, pic));
return ERROR_SUCCESS; }
DWORD ProcessCopyFiles(HINF hi, const TCHAR *ptsName) { DWORD dwErr; INFCONTEXT ic;
if (!SetupFindFirstLine(hi, ptsName, NULL, &ic)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, ptsName); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed on section %s with %lu\r\n", ptsName, dwErr); return dwErr; }
dwErr = AddInfSectionToRuleList(&ic, &g_crlIncludeWildcards, TRUE);
return dwErr; }
DWORD ProcessDelFiles(HINF hi, const TCHAR *ptsName) { DWORD dwErr; INFCONTEXT ic;
if (!SetupFindFirstLine(hi, ptsName, NULL, &ic)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, ptsName); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed on section %s with %lu\r\n", ptsName, dwErr); return dwErr; }
dwErr = AddInfSectionToRuleList(&ic, &g_crlExcludeWildcards, FALSE);
return dwErr; }
DWORD ProcessRules(HINF hi) { DWORD dwErr; INFCONTEXT ic;
if (!SetupFindFirstLine(hi, EXTENSION_SECTION, NULL, &ic)) { //Ignore - this section is optional
return ERROR_SUCCESS; }
do { DWORD cFields; cFields = SetupGetFieldCount(&ic); TCHAR buf[MAX_PATH + 1];
if (!SetupGetStringField(&ic, 0, buf, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField failed with %lu\r\n", dwErr); return dwErr; }
if (_tcsicmp(buf, COPYFILES_LABEL) == 0) { //Add files in all sections to the include list
for (DWORD j = 1; j < cFields + 1; j++) { if (!SetupGetStringField(&ic, j, buf, MAX_PATH + 1, NULL)) {
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField failed with %lu\r\n", dwErr); return dwErr; } dwErr = ProcessCopyFiles(hi, buf); if (dwErr != 0) return dwErr; } } else if (_tcsicmp(buf, DELFILES_LABEL) == 0) { //Add files in all sections to the include list
for (DWORD j = 1; j < cFields + 1; j++) { if (!SetupGetStringField(&ic, j, buf, MAX_PATH + 1, NULL)) {
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField failed with %lu\r\n", dwErr); return dwErr; } dwErr = ProcessDelFiles(hi, buf); if (dwErr != 0) return dwErr; } } } while (SetupFindNextLine(&ic, &ic));
return ERROR_SUCCESS; } DWORD ProcessSpecialDirs(HINF hi) { DWORD dwErr; INFCONTEXT ic; if (!SetupFindFirstLine(hi, SPECIALDIRS_SECTION, NULL, &ic)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, SPECIALDIRS_SECTION); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed with %lu\r\n", dwErr); return dwErr; }
do { TCHAR bufName[MAX_PATH + 1]; TCHAR bufPath[MAX_PATH + 2]; DWORD cFields; cFields = SetupGetFieldCount(&ic);
if (cFields != 1) { Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "INF line contains too many fields in " "section %s\r\n", SPECIALDIRS_SECTION); return ERROR_INVALID_PARAMETER; }
if (!SetupGetStringField(&ic, 0, bufName, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; }
if (!SetupGetStringField(&ic, 1, bufPath, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; }
dwErr = g_csdOld.InitFromInf(bufName, bufPath); if (dwErr) return dwErr; } while (SetupFindNextLine(&ic, &ic));
return ERROR_SUCCESS; }
DWORD AddLoadFileSection(HINF hi, TCHAR *ptsName, CSection **ppcs) { DWORD dwErr; INFCONTEXT ic; CSection *pcsSection; TCHAR tsSection[MAX_PATH + 1]; TCHAR buf[MAX_PATH + 1]; TCHAR bufDest[MAX_PATH + 1]; TCHAR bufMacro[MAX_PATH + 1]; TCHAR *ptsFinalName;
pcsSection = new CSection; if (pcsSection == NULL) { Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY); return ERROR_OUTOFMEMORY; }
if (ppcs) *ppcs = pcsSection;
if (g_pcsSectionList == NULL) { g_pcsSectionList = pcsSection; } else { g_pcsSectionList->AddToList(pcsSection); }
dwErr = pcsSection->SetSectionTitle(ptsName); if (dwErr) { return dwErr; }
if (_tcslen(ptsName) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: ptsName too long %s\r\n", ptsName); return ERROR_FILENAME_EXCED_RANGE; } _tcscpy(buf, ptsName); dwErr = g_csdOld.ExpandMacro(buf, bufMacro, &ptsFinalName, TRUE); if (dwErr) { //Try with the current list
dwErr = g_csdCurrent.ExpandMacro(buf, bufMacro, &ptsFinalName, FALSE); if (dwErr) return dwErr; }
dwErr = pcsSection->SetSectionPath(ptsFinalName); if (dwErr) { return dwErr; }
const TCHAR *ptsSectionPath = pcsSection->GetSectionPath();
if (_tcslen(ptsSectionPath) + 1 > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: ptsSectionPath too long %s\r\n", ptsSectionPath); return ERROR_FILENAME_EXCED_RANGE; } _tcscpy(tsSection, ptsSectionPath); _tcscat(tsSection, TEXT("\\"));
if (!SetupFindFirstLine(hi, ptsName, NULL, &ic)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, ptsName); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed on section %s with %lu\r\n", ptsName, dwErr); return dwErr; }
do { DWORD cFields; cFields = SetupGetFieldCount(&ic);
if ((cFields != 1) && (cFields != 2)) { Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "INF line contains too many fields in " "section %s\r\n", ptsName); return ERROR_INVALID_PARAMETER; }
if (!SetupGetStringField(&ic, 1, buf, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; }
dwErr = g_csdCurrent.ExpandMacro(buf, bufMacro, &ptsFinalName, TRUE); if (dwErr) return dwErr; //Check if we're supposed to exclude this file by a rule
CRuleList *prl; if (!g_crlExcludeWildcards.MatchAgainstRuleList(tsSection, buf, &prl, NULL)) { DWORD i; dwErr = pcsSection->SetName(ptsFinalName, &i, FALSE); if (dwErr) return dwErr; if (cFields == 2) { if (!SetupGetStringField(&ic, 2, bufDest, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField returned %lu\r\n", dwErr); return dwErr; } dwErr = g_csdCurrent.ExpandMacro(bufDest, bufMacro, &ptsFinalName, TRUE); if (dwErr) return dwErr; dwErr = pcsSection->SetDestination(ptsFinalName, i); if (dwErr) return dwErr; } } else { if (Verbose) Win32Printf(LogFile, "Excluding %s by rule %s\r\n", buf, prl->GetFullName()); } } while (SetupFindNextLine(&ic, &ic));
return ERROR_SUCCESS; }
DWORD CopyAllFiles(void) { DWORD dwErr; CSection *pcs = g_pcsSectionList;
DWORD ccMigPath; TCHAR tsFinalSource[MAX_PATH + 1]; TCHAR tsSectionDest[MAX_PATH + 1]; TCHAR tsFinalDest[MAX_PATH + 1]; TCHAR *ptsJustFile; DWORD ccPredictedLength; DWORD dwReturnUp = ERROR_SUCCESS;
#ifdef UNICODE
if (_tcslen(wcsMigrationPath) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: wcsMigrationPath too long %s\r\n", wcsMigrationPath); return ERROR_FILENAME_EXCED_RANGE; } wcscpy(tsFinalSource, wcsMigrationPath); ccMigPath = wcslen(wcsMigrationPath); #else
if (_tcslen(MigrationPath) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: MigrationPath too long %s\r\n", MigrationPath); return ERROR_FILENAME_EXCED_RANGE; } strcpy(tsFinalSource, MigrationPath); ccMigPath = strlen(MigrationPath); #endif
while (pcs != NULL) { ULONG ulNameCount = pcs->GetNameCount();
//Add section to source path
const TCHAR *ptsSection = pcs->GetSectionPath();
DWORD ccSection = pcs->GetSectionPathLength() + ccMigPath; if ( ccSection + 1 > MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsSection); if (Verbose) { Win32Printf(STDERR, "Skipping Too Long Source Filename: %s\\%s\r\n", tsFinalSource, ptsSection); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } pcs = pcs->GetNextSection(); continue; } tsFinalSource[ccMigPath] = TEXT('\\'); tsFinalSource[ccMigPath + 1] = ptsSection[0]; _tcscpy(tsFinalSource + ccMigPath + 2, ptsSection + 2);
tsFinalSource[ccSection++] = TEXT('\\'); tsFinalSource[ccSection] = 0;
// Build Destination Path
INT_PTR ccDest = pcs->GetSectionDestLength(); if ( ccDest + 1 > MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, pcs->GetSectionDest); if (Verbose) { Win32Printf(STDERR, "Skipping Too Long Destination Filename: %s\r\n", pcs->GetSectionDest); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } pcs = pcs->GetNextSection(); continue; } _tcscpy(tsSectionDest, pcs->GetSectionDest()); if (tsSectionDest[ccDest - 1] != TEXT('\\')) { tsSectionDest[ccDest++] = TEXT('\\'); tsSectionDest[ccDest] = 0; }
for (ULONG i = 0; i < ulNameCount; i++) { TCHAR *ptsDestFinal; const TCHAR *ptsName = pcs->GetFullFileName(i); const TCHAR *ptsDest = pcs->GetDestination(i);
if (ptsDest != NULL) { TCHAR *ptsTopDir;
// File is explicitly being migrated
// Build the destination filename with these pieces:
// - Destination dir specified in the file rule
// - Last piece of the path in the section heading
// - Filename
DWORD ccFinalDest = _tcslen(ptsDest); if (ccFinalDest > MAX_PATH) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsName); if (Verbose) Win32Printf(STDERR, "Skipping Too Long Destination Filename: %s\r\n", ptsDest); continue; } _tcscpy(tsFinalDest, ptsDest);
if (tsFinalDest[ccFinalDest] != TEXT('\\') && ccFinalDest < MAX_PATH) { tsFinalDest[ccFinalDest++] = TEXT('\\'); }
ptsTopDir = _tcsrchr( ptsSection, TEXT('\\')); if (ptsTopDir != NULL) { ptsTopDir++; // move past the '\'
}
// Skip this if we're going to create a filename that is too long
ccPredictedLength = ccFinalDest + _tcslen(ptsName); if (ptsTopDir != NULL) { ccPredictedLength += _tcslen(ptsTopDir) + 1; } if ( ccPredictedLength > MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsName); if (Verbose) { tsFinalDest[ccFinalDest] = 0; // Null terminate for printing
if (ptsTopDir == NULL) Win32Printf(STDERR, "Skipping Too Long Destination Filename: %s%s\r\n", tsFinalDest, ptsName); else Win32Printf(STDERR, "Skipping Too Long Destination Filename: %s%s\\%s\r\n", tsFinalDest, ptsTopDir, ptsName); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } continue; }
if (ptsTopDir != NULL) { _tcscpy(tsFinalDest + ccFinalDest, ptsTopDir); ccFinalDest += _tcslen(ptsTopDir); if (tsFinalDest[ccFinalDest] != TEXT('\\') ) { tsFinalDest[ccFinalDest++] = TEXT('\\'); } } _tcscpy(tsFinalDest + ccFinalDest, ptsName); ptsDestFinal = tsFinalDest; } else { if ( ccDest + _tcslen(ptsName) > MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsName); if (Verbose) { tsFinalDest[ccDest] = 0; // Null terminate for printing
Win32Printf(STDERR, "Skipping Too Long Destination Filename: %s%s\r\n", tsFinalDest, ptsName); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } continue; } //Use section destination
_tcscpy(tsSectionDest + ccDest, ptsName); ptsDestFinal = tsSectionDest; }
DWORD_PTR ccDestDir; // If the directory is more than 248 characters, then CreateDirectory will fail
// There is no system define for 248, unfortunately.. It's only mentioned in the
// documentation. How odd.
ptsJustFile = _tcsrchr(ptsDestFinal, '\\'); if ( ptsJustFile == NULL ) { ccDestDir = _tcslen(ptsDestFinal); } else { ccDestDir = ptsJustFile - ptsDestFinal; ptsJustFile++; // Move past the '\'
} if ( ccDestDir > CREATE_DIRECTORY_MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsName); if (Verbose) { ptsDestFinal[ccDestDir] = 0; // Null terminate for printing
Win32Printf(STDERR, "Skipping Too Long Destination Directory: %s for %s\r\n", ptsDestFinal, ptsJustFile ? ptsJustFile : TEXT("file list") ); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } continue; }
// Windows appears to enforce that an existing file cannot exceed MAX_PATH,
// but we'll check just to make sure.
if ( (ccSection + _tcslen(ptsName)) > MAX_PATH ) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, ptsName); if (Verbose) { tsFinalSource[ccSection] = 0; // Null terminate for printing
Win32Printf(STDERR, "Skipping Too Long Source Filename: %s\\%s\r\n", tsFinalSource, ptsName); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } continue; } _tcscpy(tsFinalSource + ccSection, ptsName);
// Store the full destination in the file list
pcs->SetDestination(ptsDestFinal, i);
//Finally we have the filenames constructed, now try
//the CopyFile operation
BOOL fPath = FALSE; ULONG ulVersion = 1; TCHAR tsCollision[MAX_PATH + 1]; INT_PTR ccExt; TCHAR *ptsDestOriginal = ptsDestFinal;
if (DebugOutput) { Win32Printf(LogFile, "Copying %s to %s\r\n", tsFinalSource, ptsDestFinal); }
while (!CopyFile(tsFinalSource, ptsDestFinal, TRUE)) { dwErr = GetLastError();
if (dwErr == ERROR_PATH_NOT_FOUND) { if (fPath) { //We already tried to create the path, so something
//else must be wrong. Punt-arooney.
break; }
dwErr = ERROR_SUCCESS;
TCHAR *ptsPos; DWORD dwPos; //Try to create all the necessary directories
TCHAR ptsDirectory[MAX_PATH + 1];
// ptsDestFinal was built inside this function and verified to
// be less than MAX_PATH in length
_tcscpy(ptsDirectory, ptsDestFinal); dwPos = 0;
// Skip any leading drive specifier.
if (ptsDirectory[0] == TEXT('\\')) dwPos = 1; else if (ptsDirectory[0] != 0 && ptsDirectory[1] == TEXT(':')) if (ptsDirectory[2] == TEXT('\\')) dwPos = 3; else dwPos = 2;
//Create every directory along this path
while (ptsPos = _tcschr(ptsDirectory + dwPos, TEXT('\\'))) { *ptsPos = 0; //Create the directory
if (!CreateDirectory(ptsDirectory, NULL)) { dwErr = GetLastError(); if (dwErr != ERROR_ALREADY_EXISTS) { break; } dwErr = ERROR_SUCCESS; }
//Put the backslash back in
*ptsPos = TEXT('\\'); //Update dwLen
dwPos = ptsPos - ptsDirectory + 1; } if (dwErr) break; fPath = TRUE; } else if (dwErr == ERROR_FILE_EXISTS) { TCHAR tsSquigs[MAX_PATH]; TCHAR *ptsDestSquig; INT_PTR ccSquig;
//Add squiggles until we get an OK name.
if (ptsDestFinal != tsCollision) { TCHAR *ptsDestExt;
//First time
ptsDestExt = _tcsrchr(ptsDestOriginal, TEXT('.')); if (ptsDestExt == NULL) { //No extension, just tack onto the end.
ccExt = _tcslen(ptsDestOriginal); } else { ccExt = ptsDestExt - ptsDestOriginal; }
// ptsDestOriginal was built inside this function and verified to
// be less than MAX_PATH in length
_tcscpy(tsCollision, ptsDestOriginal); ptsDestFinal = tsCollision;
// temporarily terminate the original to find the squig.
if( ptsDestExt != NULL ) *ptsDestExt = TEXT('\0'); ptsDestSquig = _tcsrchr(ptsDestOriginal, TEXT('(')); if( ptsDestSquig == NULL ) { ccSquig = ccExt; } else { ccSquig = ptsDestSquig - ptsDestOriginal; } // put the period back where we took it off.
if( ptsDestExt != NULL ) *ptsDestExt = TEXT('.'); } wsprintf(tsSquigs, TEXT("(%lu)"), ulVersion++); if (_tcslen(ptsDestOriginal) + _tcslen(tsSquigs) > MAX_PATH) { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, tsFinalSource); if (Verbose) { Win32Printf(STDERR, "Could Not Copy To Too Long Destination Filename %s\r\n", ptsDestOriginal); } if (dwReturnUp == ERROR_SUCCESS) { dwReturnUp = ERROR_FILENAME_EXCED_RANGE; } continue; } wsprintf(tsCollision + ccSquig, TEXT("%s%s"), tsSquigs, ptsDestOriginal + ccExt);
//Go back around and try again.
} else { Win32PrintfResource(LogFile, IDS_FILE_COPYERROR, tsFinalSource); if (Verbose) { Win32Printf(STDERR, "Error %lu trying to copy %s to %s\r\n", dwErr, tsFinalSource, ptsDestFinal); } dwReturnUp = dwErr; break; } } if (ptsDestFinal == tsCollision) { dwErr = pcs->SetDestination(tsCollision, i); Win32Printf(LogFile, "Filename collision on %s, file renamed to %s\r\n", ptsDestOriginal, ptsDestFinal); }
//Check if the file has a .lnk extension.
TCHAR *ptsLastDot; ptsLastDot = _tcsrchr(ptsDestFinal, TEXT('.')); if (ptsLastDot != NULL) { if (_tcsicmp(ptsLastDot + 1, TEXT("lnk")) == 0) { //It's a link, try to fix it. Ignore errors.
FixShellShortcut(ptsDestFinal); } } } pcs = pcs->GetNextSection(); }
return dwReturnUp; }
DWORD ParseInputFile(HINF hi) { DWORD dwErr; CSection *pcs; BOOL fMapping = FALSE; INFCONTEXT ic; INFCONTEXT icDestinationDirs; INFCONTEXT icDirectoryMapping; TCHAR tsFirstDestKey[MAX_PATH + 1]; TCHAR tsFirstMapping[10];
dwErr = ProcessSpecialDirs(hi); if (dwErr) return dwErr;
dwErr = ProcessRules(hi); if (dwErr) return dwErr;
if (!SetupFindFirstLine(hi, COPYFILE_SECTION, NULL, &ic)) { dwErr = GetLastError();
if (dwErr == ERROR_LINE_NOT_FOUND) { if (Verbose) Win32Printf(LogFile, "Warning: No [Copy These Files] section found.\r\n"); return ERROR_SUCCESS; } Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, COPYFILE_SECTION); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed with %lu\r\n", dwErr); return dwErr; }
if (!SetupFindFirstLine(hi, DESTINATIONDIRS_SECTION, NULL, &icDestinationDirs)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_SECTION_NAME_NOT_FOUND, DESTINATIONDIRS_SECTION); if (Verbose) Win32Printf(STDERR, "SetupFindFirstLine failed with %lu\r\n", dwErr); return dwErr; }
//Get the key for the first line, we'll need it later.
if (!SetupGetStringField(&icDestinationDirs, 0, tsFirstDestKey, MAX_PATH + 1, NULL)) { //Error
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField couldn't get " "first line in %s\r\n", DESTINATIONDIRS_SECTION); return dwErr; }
if (SetupFindFirstLine(hi, DIRECTORYMAPPING_SECTION, NULL, &icDirectoryMapping)) { fMapping = TRUE; //Get the first key, we'll need it later.
if (!SetupGetStringField(&icDirectoryMapping, 0, tsFirstMapping, 10, NULL)) { //Error
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField couldn't get " "first line in %s, error %lX\r\n", DIRECTORYMAPPING_SECTION, dwErr); return dwErr; }
} else { //Ignore errors here, this section is optional
}
do { DWORD cFields; cFields = SetupGetFieldCount(&ic); TCHAR buf[MAX_PATH + 1];
if (cFields != 1) { Win32PrintfResource(LogFile, IDS_INF_ERROR); return ERROR_INVALID_PARAMETER; }
if (!SetupGetStringField(&ic, 0, buf, MAX_PATH + 1, NULL)) { dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField failed with %lu\r\n", dwErr); return dwErr; }
dwErr = AddLoadFileSection(hi, buf, &pcs); if (dwErr) return dwErr;
if (fMapping) { INFCONTEXT icMap; TCHAR tsMapping[MAX_PATH + 1];
//Find the destination path for this directory.
//First we have to check the first line, because
// of SetupFindNextMatchLine
if (_tcscmp(tsFirstDestKey, pcs->GetSectionTitle()) == 0) { //It's the first line
icMap = icDestinationDirs; } else if (!SetupFindNextMatchLine(&icDestinationDirs, pcs->GetSectionTitle(), &icMap)) { //This is an error - we should have output this line
//ourselves in scanstate.
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupFindNextMatch couldn't find " "destination dir for %s\r\n", pcs->GetSectionTitle()); return dwErr; }
if (!SetupGetStringField(&icMap, 1, tsMapping, MAX_PATH + 1, NULL)) { //Error, malformed INF
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetIntField couldn't get " "destination dir for %s\r\n", pcs->GetSectionTitle()); return dwErr; }
//Now look this up in the DirectoryMapping section
if (_tcscmp(tsFirstMapping, tsMapping) == 0) icMap = icDirectoryMapping; if ((_tcscmp(tsFirstMapping, tsMapping) == 0) || (SetupFindNextMatchLine(&icDirectoryMapping, tsMapping, &icMap))) { TCHAR bufDest[MAX_PATH + 1]; if (!SetupGetStringField(&icMap, 1, bufDest, MAX_PATH + 1, NULL)) { //Error
dwErr = GetLastError(); Win32PrintfResource(LogFile, IDS_INF_ERROR); if (Verbose) Win32Printf(STDERR, "SetupGetStringField couldn't get " "directory mapping for %s\r\n", tsMapping); return dwErr; } dwErr = pcs->SetSectionDest(bufDest); if (dwErr) { return dwErr; } } else { //Fall through
}
}
if ((pcs->GetSectionDest())[0] == 0) { //Check for implicit relocation, for special directories
TCHAR bufMacro[MAX_PATH + 1]; TCHAR *ptsFinal; const TCHAR *ptsSectionTitle = pcs->GetSectionTitle(); if (_tcslen(ptsSectionTitle) > MAX_PATH) { if (DebugOutput) Win32Printf(LogFile, "Error: ptsSectionTitle too long %s\r\n", ptsSectionTitle); return ERROR_FILENAME_EXCED_RANGE; } _tcscpy(buf, ptsSectionTitle); dwErr = g_csdCurrent.ExpandMacro(buf, bufMacro, &ptsFinal, TRUE); if (dwErr) return dwErr; //Compare to section path - if they're different, set the
//section destination to the new section
if (_tcsicmp(ptsFinal, pcs->GetSectionPath()) != 0) { dwErr = pcs->SetSectionDest(ptsFinal); if (dwErr) { return dwErr; } } } if ((pcs->GetSectionDest())[0] == 0) { dwErr = pcs->SetSectionDest(pcs->GetSectionPath()); if (dwErr) { return dwErr; } } } while (SetupFindNextLine(&ic, &ic));
return ERROR_SUCCESS; }
//---------------------------------------------------------------
DWORD LoadFiles() { DWORD dwErr = ERROR_SUCCESS;
if (UserPath == NULL) { UserPath = (TCHAR *) malloc(MAX_PATH + 1); if (UserPath == NULL) { Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY); dwErr = ERROR_OUTOFMEMORY; return dwErr; } //We need this but it hasn't been set in LoadUser, so get the
//USERPROFILE variable for the current user and put it in there.
dwErr = GetEnvironmentVariable(TEXT("USERPROFILE"), UserPath, MAX_PATH + 1); if (dwErr == 0) { //Fatal error.
Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY); dwErr = ERROR_OUTOFMEMORY; return dwErr; } } dwErr = g_csdCurrent.InitForUser(CurrentUser); if (dwErr) return dwErr;
if (DebugOutput) { for (ULONG i = 0; i < g_csdCurrent.GetDirectoryCount(); i++) { if (g_csdCurrent.GetDirectoryPath(i) != NULL) { Win32Printf(LogFile, "%s=%s\r\n", g_csdCurrent.GetDirectoryName(i), g_csdCurrent.GetDirectoryPath(i)); } } Win32Printf(LogFile, "\r\n"); }
dwErr = ParseInputFile(InputInf);
if (dwErr) return dwErr;
//If CopyFiles is FALSE, do nothing
if (!CopyFiles) return ERROR_SUCCESS;
dwErr = CopyAllFiles(); if (dwErr) return dwErr;
return ERROR_SUCCESS; }
|