static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, LPWSTR *appValue) { static const WCHAR dwordFmt[] = { '#','%','d','\0' }; static const WCHAR binPre[] = { '#','x','\0' }; static const WCHAR binFmt[] = { '%','0','2','X','\0' }; LPWSTR ptr; DWORD i; switch (regType) { case REG_SZ: if (*(LPCWSTR)value == '#') { /* escape leading pound with another */ *appValue = msi_alloc(sz + sizeof(WCHAR)); (*appValue)[0] = '#'; strcpyW(*appValue + 1, (LPCWSTR)value); } else { *appValue = msi_alloc(sz); strcpyW(*appValue, (LPCWSTR)value); } break; case REG_DWORD: /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign * char if needed */ *appValue = msi_alloc(10 * sizeof(WCHAR)); sprintfW(*appValue, dwordFmt, *(const DWORD *)value); break; case REG_EXPAND_SZ: sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0); *appValue = msi_alloc(sz * sizeof(WCHAR)); ExpandEnvironmentStringsW((LPCWSTR)value, *appValue, sz); break; case REG_BINARY: /* #x<nibbles>\0 */ *appValue = msi_alloc((sz * 2 + 3) * sizeof(WCHAR)); lstrcpyW(*appValue, binPre); ptr = *appValue + lstrlenW(binPre); for (i = 0; i < sz; i++, ptr += 2) sprintfW(ptr, binFmt, value[i]); break; default: WARN("unimplemented for values of type %d\n", regType); *appValue = NULL; } }
static LANGID *parse_languages( const WCHAR *languages, DWORD *num_ids ) { UINT i, count = 1; WCHAR *str = strdupW( languages ), *p, *q; LANGID *ret; if (!str) return NULL; for (p = q = str; (q = strchrW( q, ',' )); q++) count++; if (!(ret = msi_alloc( count * sizeof(LANGID) ))) { msi_free( str ); return NULL; } i = 0; while (*p) { q = strchrW( p, ',' ); if (q) *q = 0; ret[i] = atoiW( p ); if (!q) break; p = q + 1; i++; } msi_free( str ); *num_ids = count; return ret; }
WCHAR *msi_font_version_from_file( const WCHAR *filename ) { static const WCHAR fmtW[] = {'%','u','.','%','u','.','0','.','0',0}; WCHAR *version, *p, *q, *ret = NULL; if ((version = load_ttf_name_id( filename, NAME_ID_VERSION ))) { int len, major = 0, minor = 0; if ((p = strchrW( version, ';' ))) *p = 0; p = version; while (*p && !isdigitW( *p )) p++; if ((q = strchrW( p, '.' ))) { major = atoiW( p ); p = ++q; while (*q && isdigitW( *q )) q++; if (!*q || *q == ' ') minor = atoiW( p ); else major = 0; } len = strlenW( fmtW ) + 20; ret = msi_alloc( len * sizeof(WCHAR) ); sprintfW( ret, fmtW, major, minor ); msi_free( version ); } return ret; }
WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field ) { DWORD sz = 0; WCHAR *str; UINT r; if (MSI_RecordIsNull( rec, field )) return NULL; r = MSI_RecordGetStringW( rec, field, NULL, &sz ); if (r != ERROR_SUCCESS) return NULL; sz++; str = msi_alloc( sz * sizeof(WCHAR) ); if (!str) return NULL; str[0] = 0; r = MSI_RecordGetStringW( rec, field, str, &sz ); if (r != ERROR_SUCCESS) { ERR("failed to get string!\n"); msi_free( str ); return NULL; } return str; }
static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, LPWSTR *appValue) { static const WCHAR dwordFmt[] = { '#','%','d','\0' }; static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' }; static const WCHAR binFmt[] = { '#','x','%','x','\0' }; DWORD i; switch (regType) { case REG_SZ: if (*(LPCWSTR)value == '#') { /* escape leading pound with another */ *appValue = msi_alloc(sz + sizeof(WCHAR)); (*appValue)[0] = '#'; strcpyW(*appValue + 1, (LPCWSTR)value); } else { *appValue = msi_alloc(sz); strcpyW(*appValue, (LPCWSTR)value); } break; case REG_DWORD: /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign * char if needed */ *appValue = msi_alloc(10 * sizeof(WCHAR)); sprintfW(*appValue, dwordFmt, *(const DWORD *)value); break; case REG_EXPAND_SZ: /* space for extra #% characters in front */ *appValue = msi_alloc(sz + 2 * sizeof(WCHAR)); sprintfW(*appValue, expandSzFmt, (LPCWSTR)value); break; case REG_BINARY: /* 3 == length of "#x<nibble>" */ *appValue = msi_alloc((sz * 3 + 1) * sizeof(WCHAR)); for (i = 0; i < sz; i++) sprintfW(*appValue + i * 3, binFmt, value[i]); break; default: WARN("unimplemented for values of type %d\n", regType); *appValue = NULL; } }
LPWSTR msi_version_dword_to_str(DWORD version) { const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 }; LPWSTR str = msi_alloc(20); sprintfW(str, fmt, (version&0xff000000)>>24, (version&0x00ff0000)>>16, version&0x0000ffff); return str; }
WCHAR *msi_strdupW( const WCHAR *value, int len ) { WCHAR *ret; if (!value) return NULL; if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL; memcpy( ret, value, len * sizeof(WCHAR) ); ret[len] = 0; return ret; }
/* Sets *matches to whether the file (whose path is filePath) matches the * versions set in sig. * Return ERROR_SUCCESS in case of success (whether or not the file matches), * something else if an install-halting error occurs. */ static UINT ACTION_FileVersionMatches(const MSISIGNATURE *sig, LPCWSTR filePath, BOOL *matches) { UINT len; void *version; VS_FIXEDFILEINFO *info = NULL; DWORD zero, size = GetFileVersionInfoSizeW( filePath, &zero ); *matches = FALSE; if (!size) return ERROR_SUCCESS; if (!(version = msi_alloc( size ))) return ERROR_OUTOFMEMORY; if (GetFileVersionInfoW( filePath, 0, size, version )) VerQueryValueW( version, szBackSlash, (void **)&info, &len ); if (info) { TRACE("comparing file version %d.%d.%d.%d:\n", HIWORD(info->dwFileVersionMS), LOWORD(info->dwFileVersionMS), HIWORD(info->dwFileVersionLS), LOWORD(info->dwFileVersionLS)); if (info->dwFileVersionMS < sig->MinVersionMS || (info->dwFileVersionMS == sig->MinVersionMS && info->dwFileVersionLS < sig->MinVersionLS)) { TRACE("less than minimum version %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS), LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS), LOWORD(sig->MinVersionLS)); } else if ((sig->MaxVersionMS || sig->MaxVersionLS) && (info->dwFileVersionMS > sig->MaxVersionMS || (info->dwFileVersionMS == sig->MaxVersionMS && info->dwFileVersionLS > sig->MaxVersionLS))) { TRACE("greater than maximum version %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), LOWORD(sig->MaxVersionLS)); } else if (!match_languages( version, sig->Languages )) { TRACE("languages %s not supported\n", debugstr_w( sig->Languages )); } else *matches = TRUE; } msi_free( version ); return ERROR_SUCCESS; }
/* Sets *matches to whether the file (whose path is filePath) matches the * versions set in sig. * Return ERROR_SUCCESS in case of success (whether or not the file matches), * something else if an install-halting error occurs. */ static UINT file_version_matches( MSIPACKAGE *package, const MSISIGNATURE *sig, const WCHAR *filePath, BOOL *matches ) { UINT len; void *version; VS_FIXEDFILEINFO *info = NULL; DWORD size = msi_get_file_version_info( package, filePath, 0, NULL ); *matches = FALSE; if (!size) return ERROR_SUCCESS; if (!(version = msi_alloc( size ))) return ERROR_OUTOFMEMORY; if (msi_get_file_version_info( package, filePath, size, version )) VerQueryValueW( version, szBackSlash, (void **)&info, &len ); if (info) { TRACE("comparing file version %d.%d.%d.%d:\n", HIWORD(info->dwFileVersionMS), LOWORD(info->dwFileVersionMS), HIWORD(info->dwFileVersionLS), LOWORD(info->dwFileVersionLS)); if (info->dwFileVersionMS < sig->MinVersionMS || (info->dwFileVersionMS == sig->MinVersionMS && info->dwFileVersionLS < sig->MinVersionLS)) { TRACE("less than minimum version %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS), LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS), LOWORD(sig->MinVersionLS)); } else if ((sig->MaxVersionMS || sig->MaxVersionLS) && (info->dwFileVersionMS > sig->MaxVersionMS || (info->dwFileVersionMS == sig->MaxVersionMS && info->dwFileVersionLS > sig->MaxVersionLS))) { TRACE("greater than maximum version %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), LOWORD(sig->MaxVersionLS)); } else if (!match_languages( version, sig->Languages )) { TRACE("languages %s not supported\n", debugstr_w( sig->Languages )); } else *matches = TRUE; } msi_free( version ); return ERROR_SUCCESS; }
WCHAR *font_version_from_file( const WCHAR *filename ) { WCHAR *version, *p, *ret = NULL; if ((p = version = load_ttf_name_id( filename, NAME_ID_VERSION ))) { while (*p && !isdigitW( *p )) p++; ret = msi_alloc( (strlenW( p ) + 1) * sizeof(WCHAR) ); strcpyW( ret, p ); msi_free( version ); } return ret; }
static WCHAR *font_name_from_file( const WCHAR *filename ) { static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0}; WCHAR *name, *ret = NULL; if ((name = load_ttf_name_id( filename, NAME_ID_FULL_FONT_NAME ))) { ret = msi_alloc( (strlenW( name ) + strlenW( truetypeW ) + 1 ) * sizeof(WCHAR) ); strcpyW( ret, name ); strcatW( ret, truetypeW ); msi_free( name ); } return ret; }
static struct media_info *create_media_info( void ) { struct media_info *mi; mi = msi_alloc( sizeof *mi ); if (mi) { mi->last_sequence = 0; mi->last_volume = NULL; mi->last_path = NULL; mi->count = 0; mi->source[0] = 0; } return mi; }
LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name ) { DWORD len = 0; LPWSTR val; LONG r; r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len); if (r != ERROR_SUCCESS) return NULL; len += sizeof (WCHAR); val = msi_alloc( len ); if (!val) return NULL; val[0] = 0; RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len); return val; }
static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, LPCWSTR productid) { LPWSTR prop; LPWSTR newprop; DWORD len; UINT r; prop = msi_dup_property(package->db, action_property ); if (prop) len = strlenW(prop); else len = 0; /*separator*/ len ++; len += strlenW(productid); /*null*/ len++; newprop = msi_alloc( len*sizeof(WCHAR) ); if (prop) { strcpyW(newprop,prop); strcatW(newprop,szSemiColon); } else newprop[0] = 0; strcatW(newprop,productid); r = msi_set_property( package->db, action_property, newprop ); if (r == ERROR_SUCCESS && !strcmpW( action_property, szSourceDir )) msi_reset_folders( package, TRUE ); TRACE("Found Related Product... %s now %s\n", debugstr_w(action_property), debugstr_w(newprop)); msi_free( prop ); msi_free( newprop ); }
static HRESULT create_activescriptsite(MsiActiveScriptSite **obj) { MsiActiveScriptSite* object; TRACE("(%p)\n", obj); *obj = NULL; object = msi_alloc( sizeof(MsiActiveScriptSite) ); if (!object) return E_OUTOFMEMORY; object->IActiveScriptSite_iface.lpVtbl = &activescriptsitevtbl; object->ref = 1; object->installer = NULL; object->session = NULL; *obj = object; return S_OK; }
static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, LPCWSTR productid) { LPWSTR prop; LPWSTR newprop; DWORD len; static const WCHAR separator[] = {';',0}; prop = msi_dup_property(package, action_property ); if (prop) len = strlenW(prop); else len = 0; /*separator*/ len ++; len += strlenW(productid); /*null*/ len++; newprop = msi_alloc( len*sizeof(WCHAR) ); if (prop) { strcpyW(newprop,prop); strcatW(newprop,separator); } else newprop[0] = 0; strcatW(newprop,productid); MSI_SetPropertyW(package, action_property, newprop); TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property), debugstr_w(newprop)); msi_free( prop ); msi_free( newprop ); }
/* 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; }
static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig) { static const WCHAR query[] = { 's','e','l','e','c','t',' ','*',' ', 'f','r','o','m',' ', 'R','e','g','L','o','c','a','t','o','r',' ', 'w','h','e','r','e',' ', 'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; LPWSTR keyPath = NULL, valueName = NULL; LPWSTR deformatted = NULL; LPWSTR ptr = NULL, end; int root, type; HKEY rootKey, key = NULL; DWORD sz = 0, regType; LPBYTE value = NULL; MSIRECORD *row; UINT rc; TRACE("%s\n", debugstr_w(sig->Name)); *appValue = NULL; row = MSI_QueryGetRecord( package->db, query, sig->Name ); if (!row) { TRACE("failed to query RegLocator for %s\n", debugstr_w(sig->Name)); return ERROR_SUCCESS; } root = MSI_RecordGetInteger(row,2); keyPath = msi_dup_record_field(row,3); valueName = msi_dup_record_field(row,4); type = MSI_RecordGetInteger(row,5); deformat_string(package, keyPath, &deformatted); switch (root) { case msidbRegistryRootClassesRoot: rootKey = HKEY_CLASSES_ROOT; break; case msidbRegistryRootCurrentUser: rootKey = HKEY_CURRENT_USER; break; case msidbRegistryRootLocalMachine: rootKey = HKEY_LOCAL_MACHINE; break; case msidbRegistryRootUsers: rootKey = HKEY_USERS; break; default: WARN("Unknown root key %d\n", root); goto end; } rc = RegOpenKeyW(rootKey, deformatted, &key); if (rc) { TRACE("RegOpenKeyW returned %d\n", rc); goto end; } rc = RegQueryValueExW(key, valueName, NULL, NULL, NULL, &sz); if (rc) { TRACE("RegQueryValueExW returned %d\n", rc); goto end; } /* FIXME: sanity-check sz before allocating (is there an upper-limit * on the value of a property?) */ value = msi_alloc( sz ); rc = RegQueryValueExW(key, valueName, NULL, ®Type, value, &sz); if (rc) { TRACE("RegQueryValueExW returned %d\n", rc); goto end; } /* bail out if the registry key is empty */ if (sz == 0) goto end; if ((regType == REG_SZ || regType == REG_EXPAND_SZ) && (ptr = strchrW((LPWSTR)value, '"')) && (end = strchrW(++ptr, '"'))) *end = '\0'; else ptr = (LPWSTR)value; switch (type & 0x0f) { case msidbLocatorTypeDirectory: rc = ACTION_SearchDirectory(package, sig, ptr, 0, appValue); break; case msidbLocatorTypeFileName: *appValue = app_search_file(ptr, sig); break; case msidbLocatorTypeRawValue: ACTION_ConvertRegValue(regType, value, sz, appValue); break; default: FIXME("unimplemented for type %d (key path %s, value %s)\n", type, debugstr_w(keyPath), debugstr_w(valueName)); } end: msi_free( value ); RegCloseKey( key ); msi_free( keyPath ); msi_free( valueName ); msi_free( deformatted ); msiobj_release(&row->hdr); return ERROR_SUCCESS; }
/* Sets *matches to whether the file (whose path is filePath) matches the * versions set in sig. * Return ERROR_SUCCESS in case of success (whether or not the file matches), * something else if an install-halting error occurs. */ static UINT ACTION_FileVersionMatches(const MSISIGNATURE *sig, LPCWSTR filePath, BOOL *matches) { UINT rc = ERROR_SUCCESS; *matches = FALSE; if (sig->Languages) { FIXME(": need to check version for languages %s\n", debugstr_w(sig->Languages)); } else { DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero); if (size) { LPVOID buf = msi_alloc( size); if (buf) { UINT versionLen; LPVOID subBlock = NULL; if (GetFileVersionInfoW(filePath, 0, size, buf)) VerQueryValueW(buf, szBackSlash, &subBlock, &versionLen); if (subBlock) { VS_FIXEDFILEINFO *info = subBlock; TRACE("Comparing file version %d.%d.%d.%d:\n", HIWORD(info->dwFileVersionMS), LOWORD(info->dwFileVersionMS), HIWORD(info->dwFileVersionLS), LOWORD(info->dwFileVersionLS)); if (info->dwFileVersionMS < sig->MinVersionMS || (info->dwFileVersionMS == sig->MinVersionMS && info->dwFileVersionLS < sig->MinVersionLS)) { TRACE("Less than minimum version %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS), LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS), LOWORD(sig->MinVersionLS)); } else if ((sig->MaxVersionMS || sig->MaxVersionLS) && (info->dwFileVersionMS > sig->MaxVersionMS || (info->dwFileVersionMS == sig->MaxVersionMS && info->dwFileVersionLS > sig->MaxVersionLS))) { TRACE("Greater than maximum version %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), LOWORD(sig->MaxVersionLS)); } else *matches = TRUE; } msi_free( buf); } else rc = ERROR_OUTOFMEMORY; } } return rc; }
static LPWSTR app_search_file(LPWSTR path, MSISIGNATURE *sig) { VS_FIXEDFILEINFO *info; DWORD attr, handle, size; LPWSTR val = NULL; LPBYTE buffer; if (!sig->File) { PathRemoveFileSpecW(path); PathAddBackslashW(path); attr = GetFileAttributesW(path); if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) return strdupW(path); return NULL; } attr = GetFileAttributesW(path); if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) return NULL; size = GetFileVersionInfoSizeW(path, &handle); if (!size) return strdupW(path); buffer = msi_alloc(size); if (!buffer) return NULL; if (!GetFileVersionInfoW(path, 0, size, buffer)) goto done; if (!VerQueryValueW(buffer, szBackSlash, (LPVOID)&info, &size) || !info) goto done; if (sig->MinVersionLS || sig->MinVersionMS) { if (info->dwFileVersionMS < sig->MinVersionMS) goto done; if (info->dwFileVersionMS == sig->MinVersionMS && info->dwFileVersionLS < sig->MinVersionLS) goto done; } if (sig->MaxVersionLS || sig->MaxVersionMS) { if (info->dwFileVersionMS > sig->MaxVersionMS) goto done; if (info->dwFileVersionMS == sig->MaxVersionMS && info->dwFileVersionLS > sig->MaxVersionLS) goto done; } val = strdupW(path); done: msi_free(buffer); return val; }
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; }
static void * cabinet_alloc(ULONG cb) { return msi_alloc(cb); }
static int nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { return (msi_alloc(dev, count, maxcount, irqs)); }
static WCHAR *search_file( MSIPACKAGE *package, WCHAR *path, MSISIGNATURE *sig ) { VS_FIXEDFILEINFO *info; DWORD attr, size; LPWSTR val = NULL; LPBYTE buffer; if (!sig->File) { PathRemoveFileSpecW(path); PathAddBackslashW(path); attr = msi_get_file_attributes( package, path ); if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) return strdupW(path); return NULL; } attr = msi_get_file_attributes( package, path ); if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) return NULL; size = msi_get_file_version_info( package, path, 0, NULL ); if (!size) return strdupW(path); buffer = msi_alloc(size); if (!buffer) return NULL; size = msi_get_file_version_info( package, path, size, buffer ); if (!size) goto done; if (!VerQueryValueW(buffer, szBackSlash, (LPVOID)&info, &size) || !info) goto done; if (sig->MinVersionLS || sig->MinVersionMS) { if (info->dwFileVersionMS < sig->MinVersionMS) goto done; if (info->dwFileVersionMS == sig->MinVersionMS && info->dwFileVersionLS < sig->MinVersionLS) goto done; } if (sig->MaxVersionLS || sig->MaxVersionMS) { if (info->dwFileVersionMS > sig->MaxVersionMS) goto done; if (info->dwFileVersionMS == sig->MaxVersionMS && info->dwFileVersionLS > sig->MaxVersionLS) goto done; } val = strdupW(path); done: msi_free(buffer); return val; }
static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, awstring *lpQualBuf, LPDWORD pcchQual, awstring *lpAppBuf, LPDWORD pcchAppBuf ) { DWORD name_sz, val_sz, name_max, val_max, type, ofs; LPWSTR name = NULL, val = NULL; UINT r, r2; HKEY key; TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf); if (!szComponent) return ERROR_INVALID_PARAMETER; r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE ); if (r != ERROR_SUCCESS) return ERROR_UNKNOWN_COMPONENT; /* figure out how big the name is we want to return */ name_max = 0x10; r = ERROR_OUTOFMEMORY; name = msi_alloc( name_max * sizeof(WCHAR) ); if (!name) goto end; val_max = 0x10; r = ERROR_OUTOFMEMORY; val = msi_alloc( val_max ); if (!val) goto end; /* loop until we allocate enough memory */ while (1) { name_sz = name_max; val_sz = val_max; r = RegEnumValueW( key, iIndex, name, &name_sz, NULL, &type, (LPBYTE)val, &val_sz ); if (r == ERROR_SUCCESS) break; if (r != ERROR_MORE_DATA) goto end; if (type != REG_MULTI_SZ) { ERR("component data has wrong type (%d)\n", type); goto end; } r = ERROR_OUTOFMEMORY; if ((name_sz+1) >= name_max) { name_max *= 2; msi_free( name ); name = msi_alloc( name_max * sizeof (WCHAR) ); if (!name) goto end; continue; } if (val_sz > val_max) { val_max = val_sz + sizeof (WCHAR); msi_free( val ); val = msi_alloc( val_max * sizeof (WCHAR) ); if (!val) goto end; continue; } ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz ); goto end; } ofs = 0; r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs ); if (r != ERROR_SUCCESS) goto end; TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs)); r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual ); r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf ); if (r2 != ERROR_SUCCESS) r = r2; end: msi_free(val); msi_free(name); RegCloseKey(key); return r; }
static UINT search_reg( MSIPACKAGE *package, WCHAR **appValue, MSISIGNATURE *sig ) { static const WCHAR query[] = { 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 'R','e','g','L','o','c','a','t','o','r',' ','W','H','E','R','E',' ', 'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; const WCHAR *keyPath, *valueName; WCHAR *deformatted = NULL, *ptr = NULL, *end; int root, type; REGSAM access = KEY_READ; HKEY rootKey, key = NULL; DWORD sz = 0, regType; LPBYTE value = NULL; MSIRECORD *row; UINT rc; TRACE("%s\n", debugstr_w(sig->Name)); *appValue = NULL; row = MSI_QueryGetRecord( package->db, query, sig->Name ); if (!row) { TRACE("failed to query RegLocator for %s\n", debugstr_w(sig->Name)); return ERROR_SUCCESS; } root = MSI_RecordGetInteger(row, 2); keyPath = MSI_RecordGetString(row, 3); valueName = MSI_RecordGetString(row, 4); type = MSI_RecordGetInteger(row, 5); deformat_string(package, keyPath, &deformatted); switch (root) { case msidbRegistryRootClassesRoot: rootKey = HKEY_CLASSES_ROOT; break; case msidbRegistryRootCurrentUser: rootKey = HKEY_CURRENT_USER; break; case msidbRegistryRootLocalMachine: rootKey = HKEY_LOCAL_MACHINE; if (type & msidbLocatorType64bit) access |= KEY_WOW64_64KEY; else access |= KEY_WOW64_32KEY; break; case msidbRegistryRootUsers: rootKey = HKEY_USERS; break; default: WARN("Unknown root key %d\n", root); goto end; } rc = RegOpenKeyExW( rootKey, deformatted, 0, access, &key ); if (rc) { TRACE("RegOpenKeyExW returned %d\n", rc); goto end; } msi_free(deformatted); deformat_string(package, valueName, &deformatted); rc = RegQueryValueExW(key, deformatted, NULL, NULL, NULL, &sz); if (rc) { TRACE("RegQueryValueExW returned %d\n", rc); goto end; } /* FIXME: sanity-check sz before allocating (is there an upper-limit * on the value of a property?) */ value = msi_alloc( sz ); rc = RegQueryValueExW(key, deformatted, NULL, ®Type, value, &sz); if (rc) { TRACE("RegQueryValueExW returned %d\n", rc); goto end; } /* bail out if the registry key is empty */ if (sz == 0) goto end; /* expand if needed */ if (regType == REG_EXPAND_SZ) { sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0); if (sz) { LPWSTR buf = msi_alloc(sz * sizeof(WCHAR)); ExpandEnvironmentStringsW((LPCWSTR)value, buf, sz); msi_free(value); value = (LPBYTE)buf; } } if ((regType == REG_SZ || regType == REG_EXPAND_SZ) && (ptr = strchrW((LPWSTR)value, '"')) && (end = strchrW(++ptr, '"'))) *end = '\0'; else ptr = (LPWSTR)value; switch (type & 0x0f) { case msidbLocatorTypeDirectory: search_directory( package, sig, ptr, 0, appValue ); break; case msidbLocatorTypeFileName: *appValue = search_file( package, ptr, sig ); break; case msidbLocatorTypeRawValue: convert_reg_value( regType, value, sz, appValue ); break; default: FIXME("unimplemented for type %d (key path %s, value %s)\n", type, debugstr_w(keyPath), debugstr_w(valueName)); } end: msi_free( value ); RegCloseKey( key ); msi_free( deformatted ); msiobj_release(&row->hdr); return ERROR_SUCCESS; }
static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig) { static const WCHAR query[] = { 's','e','l','e','c','t',' ','*',' ', 'f','r','o','m',' ', 'D','r','L','o','c','a','t','o','r',' ', 'w','h','e','r','e',' ', 'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; LPWSTR parentName = NULL, path = NULL, parent = NULL; WCHAR expanded[MAX_PATH]; MSIRECORD *row; int depth; UINT rc; TRACE("%s\n", debugstr_w(sig->Name)); msi_free(sig->File); sig->File = NULL; *appValue = NULL; row = MSI_QueryGetRecord( package->db, query, sig->Name ); if (!row) { TRACE("failed to query DrLocator for %s\n", debugstr_w(sig->Name)); return ERROR_SUCCESS; } /* check whether parent is set */ parentName = msi_dup_record_field(row,2); if (parentName) { MSISIGNATURE parentSig; rc = ACTION_AppSearchSigName(package, parentName, &parentSig, &parent); ACTION_FreeSignature(&parentSig); msi_free(parentName); } /* now look for path */ path = msi_dup_record_field(row,3); if (MSI_RecordIsNull(row,4)) depth = 0; else depth = MSI_RecordGetInteger(row,4); ACTION_ExpandAnyPath(package, path, expanded, MAX_PATH); msi_free(path); if (parent) { path = msi_alloc((strlenW(parent) + strlenW(expanded) + 1) * sizeof(WCHAR)); if (!path) { rc = ERROR_OUTOFMEMORY; goto end; } strcpyW(path, parent); strcatW(path, expanded); } else path = expanded; rc = ACTION_SearchDirectory(package, sig, path, depth, appValue); end: if (path != expanded) msi_free(path); msi_free(parent); msiobj_release(&row->hdr); TRACE("returning %d\n", rc); 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; }