HRESULT UrlCanonicalizeUnescape(LPCWSTR pszUrl, LPWSTR pszCanonicalized, LPDWORD pcchCanonicalized, DWORD dwFlags) { HRESULT hr = S_OK; DWORD dwSize; WCHAR wzCanonical[MAX_URL_LENGTH]; if (UrlIsW(pszUrl, URLIS_FILEURL) || !PathIsURLW(pszUrl)) { dwSize = MAX_URL_LENGTH; hr = UrlCanonicalizeW(pszUrl, wzCanonical, &dwSize, dwFlags); if (FAILED(hr)) { goto Exit; } hr = UrlUnescapeW(wzCanonical, pszCanonicalized, pcchCanonicalized, 0); if (FAILED(hr)) { goto Exit; } } else { hr = UrlCanonicalizeW(pszUrl, pszCanonicalized, pcchCanonicalized, dwFlags /*| URL_ESCAPE_PERCENT*/); } Exit: return hr; }
HRESULT PathCreateFromUrlWrap(LPCWSTR pszUrl, LPWSTR pszPath, LPDWORD pcchPath, DWORD dwFlags) { HRESULT hr = S_OK; DWORD dw; WCHAR wzEscaped[MAX_URL_LENGTH]; if (!UrlIsW(pszUrl, URLIS_FILEURL)) { hr = E_INVALIDARG; goto Exit; } dw = MAX_URL_LENGTH; hr = UrlEscapeW(pszUrl, wzEscaped, &dw, URL_ESCAPE_PERCENT); if (FAILED(hr)) { goto Exit; } hr = PathCreateFromUrlW(wzEscaped, pszPath, pcchPath, dwFlags); if (FAILED(hr)) { goto Exit; } Exit: return hr; }
HRESULT UrlCombineUnescape(LPCWSTR pszBase, LPCWSTR pszRelative, LPWSTR pszCombined, LPDWORD pcchCombined, DWORD dwFlags) { HRESULT hr = S_OK; DWORD dwSize; LPWSTR pwzCombined = NULL; LPWSTR pwzFileCombined = NULL; pwzCombined = NEW(WCHAR[MAX_URL_LENGTH]); if (!pwzCombined) { hr = E_OUTOFMEMORY; goto Exit; } // If we're just combining an absolute file path to an relative file // path, do this by concatenating the strings, and canonicalizing it. // This avoids UrlCombine randomness where you could end up with // a partially escaped (and partially unescaped) resulting URL! if (!PathIsURLW(pszBase) && PathIsRelativeWrap(pszRelative)) { pwzFileCombined = NEW(WCHAR[MAX_URL_LENGTH]); if (!pwzFileCombined) { hr = E_OUTOFMEMORY; goto Exit; } wnsprintfW(pwzFileCombined, MAX_URL_LENGTH, L"%ws%ws", pszBase, pszRelative); hr = UrlCanonicalizeUnescape(pwzFileCombined, pszCombined, pcchCombined, 0); goto Exit; } else { dwSize = MAX_URL_LENGTH; hr = UrlCombineW(pszBase, pszRelative, pwzCombined, &dwSize, dwFlags); if (FAILED(hr)) { goto Exit; } } // Don't unescape if the relative part was already an URL because // URLs wouldn't have been escaped during the UrlCombined. if (UrlIsW(pwzCombined, URLIS_FILEURL)) { hr = UrlUnescapeW(pwzCombined, pszCombined, pcchCombined, 0); if (FAILED(hr)) { goto Exit; } } else { if (*pcchCombined >= dwSize) { lstrcpyW(pszCombined, pwzCombined); } *pcchCombined = dwSize; } Exit: SAFEDELETEARRAY(pwzCombined); SAFEDELETEARRAY(pwzFileCombined); return hr; }
static void test_UrlIs(void) { BOOL ret; size_t i; WCHAR wurl[80]; for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) { MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80); ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL ); ok( ret == TEST_PATH_IS_URL[i].expect, "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path, TEST_PATH_IS_URL[i].expect ); ret = UrlIsW( wurl, URLIS_URL ); ok( ret == TEST_PATH_IS_URL[i].expect, "returned %d from path (UrlIsW) %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path, TEST_PATH_IS_URL[i].expect ); } for(i = 0; i < sizeof(TEST_URLIS_ATTRIBS) / sizeof(TEST_URLIS_ATTRIBS[0]); i++) { MultiByteToWideChar(CP_ACP, 0, TEST_URLIS_ATTRIBS[i].url, -1, wurl, 80); ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_OPAQUE); ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque, "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url, TEST_URLIS_ATTRIBS[i].expectOpaque ); ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_FILEURL); ok( ret == TEST_URLIS_ATTRIBS[i].expectFile, "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url, TEST_URLIS_ATTRIBS[i].expectFile ); ret = UrlIsW( wurl, URLIS_OPAQUE); ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque, "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url, TEST_URLIS_ATTRIBS[i].expectOpaque ); ret = UrlIsW( wurl, URLIS_FILEURL); ok( ret == TEST_URLIS_ATTRIBS[i].expectFile, "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url, TEST_URLIS_ATTRIBS[i].expectFile ); } }
STDAPI CopyPDBs(IAssembly *pAsm) { HRESULT hr = S_OK; IAssemblyName *pName = NULL; IAssemblyModuleImport *pModImport = NULL; DWORD dwSize; WCHAR wzAsmCachePath[MAX_PATH]; WCHAR wzFileName[MAX_PATH]; WCHAR wzSourcePath[MAX_PATH]; WCHAR wzPDBName[MAX_PATH]; WCHAR wzPDBSourcePath[MAX_PATH]; WCHAR wzPDBTargetPath[MAX_PATH]; WCHAR wzModPath[MAX_PATH]; LPWSTR wzCodebase=NULL; LPWSTR wzModName = NULL; DWORD dwIdx = 0; LPWSTR wzTmp = NULL; if (!pAsm) { hr = E_INVALIDARG; goto Exit; } if (pAsm->GetAssemblyLocation(NULL) == E_NOTIMPL) { // This is a registered "known assembly" (ie. the process EXE). // We don't copy PDBs for the process EXE because it's never // shadow copied. hr = S_FALSE; goto Exit; } // Find the source location. Make sure this is a file:// URL (ie. we // don't support retrieving the PDB over http://). hr = pAsm->GetAssemblyNameDef(&pName); if (FAILED(hr)) { goto Exit; } wzCodebase = NEW(WCHAR[MAX_URL_LENGTH+1]); if (!wzCodebase) { hr = E_OUTOFMEMORY; goto Exit; } dwSize = MAX_URL_LENGTH * sizeof(WCHAR); hr = pName->GetProperty(ASM_NAME_CODEBASE_URL, (void *)wzCodebase, &dwSize); if (FAILED(hr)) { goto Exit; } if (!UrlIsW(wzCodebase, URLIS_FILEURL)) { hr = E_INVALIDARG; goto Exit; } dwSize = MAX_PATH; hr = PathCreateFromUrlWrap(wzCodebase, wzSourcePath, &dwSize, 0); if (FAILED(hr)) { goto Exit; } wzTmp = PathFindFileName(wzSourcePath); ASSERT(wzTmp > (LPWSTR)wzSourcePath); *wzTmp = L'\0'; // Find the target location in the cache. dwSize = MAX_PATH; hr = pAsm->GetManifestModulePath(wzAsmCachePath, &dwSize); if (FAILED(hr)) { goto Exit; } wzTmp = PathFindFileName(wzAsmCachePath); ASSERT(wzTmp > (LPWSTR)wzAsmCachePath); StrCpy(wzFileName, wzTmp); *wzTmp = L'\0'; // Copy the manifest PDB. // Hack for now dwSize = MAX_PATH; hr = GetPDBName(wzFileName, wzPDBName, &dwSize); if (FAILED(hr)) { goto Exit; } wnsprintfW(wzPDBSourcePath, MAX_PATH, L"%ws%ws", wzSourcePath, wzPDBName); wnsprintf(wzPDBTargetPath, MAX_PATH, L"%ws%ws", wzAsmCachePath, wzPDBName); if (GetFileAttributes(wzPDBTargetPath) == (DWORD) -1 && lstrcmpiW(wzPDBSourcePath, wzPDBTargetPath)) { CopyFile(wzPDBSourcePath, wzPDBTargetPath, TRUE); } // Copy the module PDBs. dwIdx = 0; while (SUCCEEDED(hr)) { hr = pAsm->GetNextAssemblyModule(dwIdx++, &pModImport); if (SUCCEEDED(hr)) { if (pModImport->IsAvailable()) { dwSize = MAX_PATH; hr = pModImport->GetModulePath(wzModPath, &dwSize); if (FAILED(hr)) { SAFERELEASE(pModImport); goto Exit; } wzModName = PathFindFileName(wzModPath); ASSERT(wzModName); dwSize = MAX_PATH; hr = GetPDBName(wzModName, wzPDBName, &dwSize); if (FAILED(hr)) { SAFERELEASE(pModImport); goto Exit; } wnsprintfW(wzPDBSourcePath, MAX_PATH, L"%ws%ws", wzSourcePath, wzPDBName); wnsprintfW(wzPDBTargetPath, MAX_PATH, L"%ws%ws", wzAsmCachePath, wzPDBName); if (GetFileAttributes(wzPDBTargetPath) == (DWORD) -1 && lstrcmpiW(wzPDBSourcePath, wzPDBTargetPath)) { CopyFile(wzPDBSourcePath, wzPDBTargetPath, TRUE); } } SAFERELEASE(pModImport); } } // Copy complete. Return success. if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { hr = S_OK; } Exit: SAFERELEASE(pName); SAFEDELETEARRAY(wzCodebase); return hr; }
static UINT ready_media(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi) { UINT rc = ERROR_SUCCESS; /* media info for continuous cabinet is already loaded */ if (mi->is_continuous) return ERROR_SUCCESS; rc = load_media_info(package, file, mi); if (rc != ERROR_SUCCESS) { ERR("Unable to load media info\n"); return ERROR_FUNCTION_FAILED; } /* cabinet is internal, no checks needed */ if (!mi->cabinet || mi->cabinet[0] == '#') return ERROR_SUCCESS; /* package should be downloaded */ if (file->IsCompressed && GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES && package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL)) { WCHAR temppath[MAX_PATH]; msi_download_file(mi->source, temppath); lstrcpyW(mi->source, temppath); return ERROR_SUCCESS; } /* check volume matches, change media if not */ if (mi->volume_label && mi->disk_id > 1 && lstrcmpW(mi->first_volume, mi->volume_label)) { LPWSTR source = msi_dup_property(package, cszSourceDir); BOOL matches; matches = source_matches_volume(mi, source); msi_free(source); if ((mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) && !matches) { rc = msi_change_media(package, mi); if (rc != ERROR_SUCCESS) return rc; } } if (file->IsCompressed && GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES) { /* FIXME: this might be done earlier in the install process */ rc = find_published_source(package, mi); if (rc != ERROR_SUCCESS) { ERR("Cabinet not found: %s\n", debugstr_w(mi->source)); return ERROR_INSTALL_FAILURE; } } return ERROR_SUCCESS; }
static UINT load_media_info(MSIPACKAGE *package, MSIFILE *file, struct media_info *mi) { MSIRECORD *row; LPWSTR source_dir; LPWSTR source; DWORD options; UINT r; static const WCHAR query[] = { 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', ' ','%','i',' ','A','N','D',' ','`','D','i','s','k','I','d','`',' ','>','=', ' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ', '`','D','i','s','k','I','d','`',0 }; row = MSI_QueryGetRecord(package->db, query, file->Sequence, mi->disk_id); if (!row) { TRACE("Unable to query row\n"); return ERROR_FUNCTION_FAILED; } mi->is_extracted = FALSE; mi->disk_id = MSI_RecordGetInteger(row, 1); mi->last_sequence = MSI_RecordGetInteger(row, 2); msi_free(mi->disk_prompt); mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3)); msi_free(mi->cabinet); mi->cabinet = strdupW(MSI_RecordGetString(row, 4)); msi_free(mi->volume_label); mi->volume_label = strdupW(MSI_RecordGetString(row, 5)); msiobj_release(&row->hdr); if (!mi->first_volume) mi->first_volume = strdupW(mi->volume_label); source_dir = msi_dup_property(package, cszSourceDir); lstrcpyW(mi->source, source_dir); PathStripToRootW(source_dir); mi->type = GetDriveTypeW(source_dir); if (file->IsCompressed && mi->cabinet) { if (mi->cabinet[0] == '#') { r = writeout_cabinet_stream(package, &mi->cabinet[1], mi->source); if (r != ERROR_SUCCESS) { ERR("Failed to extract cabinet stream\n"); return ERROR_FUNCTION_FAILED; } } else lstrcatW(mi->source, mi->cabinet); } options = MSICODE_PRODUCT; if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) { source = source_dir; options |= MSISOURCETYPE_MEDIA; } else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL)) { source = package->BaseURL; options |= MSISOURCETYPE_URL; } else { source = mi->source; options |= MSISOURCETYPE_NETWORK; } if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) msi_package_add_media_disk(package, package->Context, MSICODE_PRODUCT, mi->disk_id, mi->volume_label, mi->disk_prompt); msi_package_add_info(package, package->Context, options, INSTALLPROPERTY_LASTUSEDSOURCEW, source); msi_free(source_dir); return ERROR_SUCCESS; }
static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi, MSIFILE *file ) { UINT rc = ERROR_SUCCESS; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ', '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; LPCWSTR cab, volume; DWORD sz; INT seq; LPCWSTR prompt; MSICOMPONENT *comp = file->Component; if (file->Sequence <= mi->last_sequence) { set_file_source(package,file,comp,mi->last_path); TRACE("Media already ready (%u, %u)\n",file->Sequence,mi->last_sequence); return ERROR_SUCCESS; } mi->count ++; row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); if (!row) { TRACE("Unable to query row\n"); return ERROR_FUNCTION_FAILED; } seq = MSI_RecordGetInteger(row,2); mi->last_sequence = seq; volume = MSI_RecordGetString(row, 5); prompt = MSI_RecordGetString(row, 3); msi_free(mi->last_path); mi->last_path = NULL; if (!file->IsCompressed) { mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); set_file_source(package,file,comp,mi->last_path); MsiSourceListAddMediaDiskW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume, prompt); MsiSourceListSetInfoW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path); msiobj_release(&row->hdr); return rc; } cab = MSI_RecordGetString(row,4); if (cab) { TRACE("Source is CAB %s\n",debugstr_w(cab)); /* the stream does not contain the # character */ if (cab[0]=='#') { LPWSTR path; writeout_cabinet_stream(package,&cab[1],mi->source); mi->last_path = strdupW(mi->source); *(strrchrW(mi->last_path,'\\')+1)=0; path = msi_dup_property( package, cszSourceDir ); MsiSourceListAddMediaDiskW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume, prompt); MsiSourceListSetInfoW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT|MSISOURCETYPE_NETWORK, INSTALLPROPERTY_LASTUSEDSOURCEW, path); msi_free(path); } else { sz = MAX_PATH; mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR)); if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz)) { ERR("No Source dir defined\n"); rc = ERROR_FUNCTION_FAILED; } else { strcpyW(mi->last_path,mi->source); strcatW(mi->source,cab); MsiSourceListSetInfoW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path); /* extract the cab file into a folder in the temp folder */ sz = MAX_PATH; if (MSI_GetPropertyW(package, cszTempFolder,mi->last_path, &sz) != ERROR_SUCCESS) GetTempPathW(MAX_PATH,mi->last_path); } } /* only download the remote cabinet file if a local copy does not exist */ if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES && UrlIsW(package->PackagePath, URLIS_URL)) { rc = msi_extract_remote_cabinet(package, mi); } else { rc = !extract_cabinet_file(package, mi->source, mi->last_path); } } else { sz = MAX_PATH; mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR)); MSI_GetPropertyW(package,cszSourceDir,mi->source,&sz); strcpyW(mi->last_path,mi->source); MsiSourceListSetInfoW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path); } set_file_source(package, file, comp, mi->last_path); MsiSourceListAddMediaDiskW(package->ProductCode, NULL, MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume, prompt); msiobj_release(&row->hdr); return rc; }
HRESULT CAssemblyDownload::GetNextCodebase(BOOL *pbIsFileUrl, LPWSTR wzFilePath, DWORD cbLen) { HRESULT hr = S_OK; LPWSTR wzNextCodebase = NULL; DWORD cbCodebase; DWORD dwSize; BOOL bIsFileUrl = FALSE; ASSERT(pbIsFileUrl && wzFilePath); *pbIsFileUrl = FALSE; for (;;) { cbCodebase = 0; hr = _pCodebaseList->GetCodebase(0, NULL, &cbCodebase); if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { // could not get codebase hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); goto Exit; } wzNextCodebase = NEW(WCHAR[cbCodebase]); if (!wzNextCodebase) { hr = E_OUTOFMEMORY; goto Exit; } hr = _pCodebaseList->GetCodebase(0, wzNextCodebase, &cbCodebase); if (FAILED(hr)) { goto Exit; } hr = _pCodebaseList->RemoveCodebase(0); if (FAILED(hr)) { goto Exit; } // Check if we are a UNC or file:// URL. If we are, we don't have // to do a download, and can call setup right away. bIsFileUrl = UrlIsW(wzNextCodebase, URLIS_FILEURL); if (bIsFileUrl) { dwSize = cbLen; if (FAILED(PathCreateFromUrlWrap(wzNextCodebase, wzFilePath, &dwSize, 0))) { wzFilePath[0] = L'\0'; } if (GetFileAttributes(wzFilePath) == (DWORD) -1) { // File doesn't exist. Try the next URL. DEBUGOUT1(_pdbglog, 0, ID_FUSLOG_ATTEMPT_NEW_DOWNLOAD, wzNextCodebase); ReportProgress(0, 0, 0, ASM_NOTIFICATION_ATTEMPT_NEXT_CODEBASE, (LPCWSTR)wzNextCodebase, _hrResult); _hrResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); SAFEDELETEARRAY(wzNextCodebase); continue; } } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto Exit; } break; } *pbIsFileUrl = bIsFileUrl; PrepNextDownload(wzNextCodebase); Exit: SAFEDELETEARRAY(wzNextCodebase); return hr; }