/* Recursively searches the directory dir for files that match the signature * sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir * (and only dir). If depth is 1, searches dir and its immediate * subdirectories. * Assumes sig->File is not NULL. * Returns ERROR_SUCCESS on success (which may include non-critical errors), * something else on failures which should halt the install. */ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig, LPCWSTR dir, int depth) { HANDLE hFind; WIN32_FIND_DATAW findData; UINT rc = ERROR_SUCCESS; size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File); WCHAR subpath[MAX_PATH]; WCHAR *buf; DWORD len; static const WCHAR starDotStarW[] = { '*','.','*',0 }; TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir), debugstr_w(sig->File), depth); if (depth < 0) return ERROR_SUCCESS; *appValue = NULL; /* We need the buffer in both paths below, so go ahead and allocate it * here. Add two because we might need to add a backslash if the dir name * isn't backslash-terminated. */ len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2; buf = msi_alloc(len * sizeof(WCHAR)); if (!buf) return ERROR_OUTOFMEMORY; lstrcpyW(buf, dir); PathAddBackslashW(buf); lstrcatW(buf, sig->File); hFind = FindFirstFileW(buf, &findData); if (hFind != INVALID_HANDLE_VALUE) { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { BOOL matches; rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches); if (rc == ERROR_SUCCESS && matches) { TRACE("found file, returning %s\n", debugstr_w(buf)); *appValue = buf; } } FindClose(hFind); } if (rc == ERROR_SUCCESS && !*appValue) { lstrcpyW(buf, dir); PathAddBackslashW(buf); lstrcatW(buf, starDotStarW); hFind = FindFirstFileW(buf, &findData); if (hFind != INVALID_HANDLE_VALUE) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && lstrcmpW(findData.cFileName, szDot) && lstrcmpW(findData.cFileName, szDotDot)) { lstrcpyW(subpath, dir); PathAppendW(subpath, findData.cFileName); rc = ACTION_RecurseSearchDirectory(package, appValue, sig, subpath, depth - 1); } while (rc == ERROR_SUCCESS && !*appValue && FindNextFileW(hFind, &findData) != 0) { if (!lstrcmpW(findData.cFileName, szDot) || !lstrcmpW(findData.cFileName, szDotDot)) continue; lstrcpyW(subpath, dir); PathAppendW(subpath, findData.cFileName); if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) rc = ACTION_RecurseSearchDirectory(package, appValue, sig, subpath, depth - 1); } FindClose(hFind); } } if (*appValue != buf) msi_free(buf); return rc; }
/* Recursively searches the directory dir for files that match the signature * sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir * (and only dir). If depth is 1, searches dir and its immediate * subdirectories. * Assumes sig->File is not NULL. * Returns ERROR_SUCCESS on success (which may include non-critical errors), * something else on failures which should halt the install. */ static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig, LPCWSTR dir, int depth) { static const WCHAR starDotStarW[] = { '*','.','*',0 }; UINT rc = ERROR_SUCCESS; size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File); WCHAR *buf; TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir), debugstr_w(sig->File), depth); if (depth < 0) return ERROR_INVALID_PARAMETER; *appValue = NULL; /* We need the buffer in both paths below, so go ahead and allocate it * here. Add two because we might need to add a backslash if the dir name * isn't backslash-terminated. */ buf = msi_alloc( (dirLen + max(fileLen, lstrlenW(starDotStarW)) + 2) * sizeof(WCHAR)); if (buf) { /* a depth of 0 implies we should search dir, so go ahead and search */ HANDLE hFind; WIN32_FIND_DATAW findData; memcpy(buf, dir, dirLen * sizeof(WCHAR)); if (buf[dirLen - 1] != '\\') buf[dirLen++ - 1] = '\\'; memcpy(buf + dirLen, sig->File, (fileLen + 1) * sizeof(WCHAR)); hFind = FindFirstFileW(buf, &findData); if (hFind != INVALID_HANDLE_VALUE) { BOOL matches; /* assuming Signature can't contain wildcards for the file name, * so don't bother with FindNextFileW here. */ if (!(rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches)) && matches) { TRACE("found file, returning %s\n", debugstr_w(buf)); *appValue = buf; } FindClose(hFind); } if (rc == ERROR_SUCCESS && !*appValue && depth > 0) { HANDLE hFind; WIN32_FIND_DATAW findData; memcpy(buf, dir, dirLen * sizeof(WCHAR)); if (buf[dirLen - 1] != '\\') buf[dirLen++ - 1] = '\\'; lstrcpyW(buf + dirLen, starDotStarW); hFind = FindFirstFileW(buf, &findData); if (hFind != INVALID_HANDLE_VALUE) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) rc = ACTION_RecurseSearchDirectory(package, appValue, sig, findData.cFileName, depth - 1); while (rc == ERROR_SUCCESS && !*appValue && FindNextFileW(hFind, &findData) != 0) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) rc = ACTION_RecurseSearchDirectory(package, appValue, sig, findData.cFileName, depth - 1); } FindClose(hFind); } } if (!*appValue) msi_free(buf); } else rc = ERROR_OUTOFMEMORY; return rc; }