Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpatch.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of the Microsoft Installer (msi.dll) 00003 * 00004 * Copyright 2004,2005 Aric Stewart for CodeWeavers 00005 * Copyright 2011 Hans Leidekker for CodeWeavers 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <stdarg.h> 00023 #define COBJMACROS 00024 #include "windef.h" 00025 #include "winbase.h" 00026 #include "winreg.h" 00027 #include "objbase.h" 00028 #include "shlwapi.h" 00029 #include "wine/debug.h" 00030 #include "wine/unicode.h" 00031 #include "msipriv.h" 00032 00033 WINE_DEFAULT_DEBUG_CHANNEL(msi); 00034 00035 static BOOL match_language( MSIPACKAGE *package, LANGID langid ) 00036 { 00037 UINT i; 00038 00039 if (!package->num_langids || !langid) return TRUE; 00040 for (i = 0; i < package->num_langids; i++) 00041 { 00042 if (package->langids[i] == langid) return TRUE; 00043 } 00044 return FALSE; 00045 } 00046 00047 static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *patch ) 00048 { 00049 LPWSTR prod_code, patch_product, template = NULL; 00050 UINT ret = ERROR_FUNCTION_FAILED; 00051 00052 prod_code = msi_dup_property( package->db, szProductCode ); 00053 patch_product = msi_get_suminfo_product( patch ); 00054 00055 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product)); 00056 00057 if (strstrW( patch_product, prod_code )) 00058 { 00059 MSISUMMARYINFO *si; 00060 const WCHAR *p; 00061 00062 si = MSI_GetSummaryInformationW( patch, 0 ); 00063 if (!si) 00064 { 00065 ERR("no summary information!\n"); 00066 goto end; 00067 } 00068 template = msi_suminfo_dup_string( si, PID_TEMPLATE ); 00069 if (!template) 00070 { 00071 ERR("no template property!\n"); 00072 msiobj_release( &si->hdr ); 00073 goto end; 00074 } 00075 if (!template[0]) 00076 { 00077 ret = ERROR_SUCCESS; 00078 msiobj_release( &si->hdr ); 00079 goto end; 00080 } 00081 TRACE("template: %s\n", debugstr_w(template)); 00082 p = strchrW( template, ';' ); 00083 if (p && match_language( package, atoiW( p + 1 ) )) 00084 { 00085 TRACE("applicable transform\n"); 00086 ret = ERROR_SUCCESS; 00087 } 00088 /* FIXME: check platform */ 00089 msiobj_release( &si->hdr ); 00090 } 00091 00092 end: 00093 msi_free( patch_product ); 00094 msi_free( prod_code ); 00095 msi_free( template ); 00096 return ret; 00097 } 00098 00099 static UINT apply_substorage_transform( MSIPACKAGE *package, MSIDATABASE *patch_db, LPCWSTR name ) 00100 { 00101 UINT ret = ERROR_FUNCTION_FAILED; 00102 IStorage *stg = NULL; 00103 HRESULT r; 00104 00105 TRACE("%p %s\n", package, debugstr_w(name)); 00106 00107 if (*name++ != ':') 00108 { 00109 ERR("expected a colon in %s\n", debugstr_w(name)); 00110 return ERROR_FUNCTION_FAILED; 00111 } 00112 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg ); 00113 if (SUCCEEDED(r)) 00114 { 00115 ret = check_transform_applicable( package, stg ); 00116 if (ret == ERROR_SUCCESS) 00117 msi_table_apply_transform( package->db, stg ); 00118 else 00119 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name)); 00120 IStorage_Release( stg ); 00121 } 00122 else 00123 { 00124 ERR("failed to open substorage %s\n", debugstr_w(name)); 00125 } 00126 return ERROR_SUCCESS; 00127 } 00128 00129 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si ) 00130 { 00131 LPWSTR guid_list, *guids, product_code; 00132 UINT i, ret = ERROR_FUNCTION_FAILED; 00133 00134 product_code = msi_dup_property( package->db, szProductCode ); 00135 if (!product_code) 00136 { 00137 /* FIXME: the property ProductCode should be written into the DB somewhere */ 00138 ERR("no product code to check\n"); 00139 return ERROR_SUCCESS; 00140 } 00141 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE ); 00142 guids = msi_split_string( guid_list, ';' ); 00143 for (i = 0; guids[i] && ret != ERROR_SUCCESS; i++) 00144 { 00145 if (!strcmpW( guids[i], product_code )) ret = ERROR_SUCCESS; 00146 } 00147 msi_free( guids ); 00148 msi_free( guid_list ); 00149 msi_free( product_code ); 00150 return ret; 00151 } 00152 00153 static UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch ) 00154 { 00155 MSIPATCHINFO *pi; 00156 UINT r = ERROR_SUCCESS; 00157 WCHAR *p; 00158 00159 if (!(pi = msi_alloc_zero( sizeof(MSIPATCHINFO) ))) 00160 { 00161 return ERROR_OUTOFMEMORY; 00162 } 00163 if (!(pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER ))) 00164 { 00165 msi_free( pi ); 00166 return ERROR_OUTOFMEMORY; 00167 } 00168 p = pi->patchcode; 00169 if (*p != '{') 00170 { 00171 msi_free( pi->patchcode ); 00172 msi_free( pi ); 00173 return ERROR_PATCH_PACKAGE_INVALID; 00174 } 00175 if (!(p = strchrW( p + 1, '}' ))) 00176 { 00177 msi_free( pi->patchcode ); 00178 msi_free( pi ); 00179 return ERROR_PATCH_PACKAGE_INVALID; 00180 } 00181 if (p[1]) 00182 { 00183 FIXME("patch obsoletes %s\n", debugstr_w(p + 1)); 00184 p[1] = 0; 00185 } 00186 TRACE("patch code %s\n", debugstr_w(pi->patchcode)); 00187 if (!(pi->products = msi_suminfo_dup_string( si, PID_TEMPLATE ))) 00188 { 00189 msi_free( pi->patchcode ); 00190 msi_free( pi ); 00191 return ERROR_OUTOFMEMORY; 00192 } 00193 if (!(pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR ))) 00194 { 00195 msi_free( pi->patchcode ); 00196 msi_free( pi->products ); 00197 msi_free( pi ); 00198 return ERROR_OUTOFMEMORY; 00199 } 00200 *patch = pi; 00201 return r; 00202 } 00203 00204 static UINT patch_set_media_source_prop( MSIPACKAGE *package ) 00205 { 00206 static const WCHAR query[] = { 00207 'S','E','L','E','C','T',' ','`','S','o','u','r','c','e','`',' ','F','R','O','M',' ', 00208 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ', 00209 'I','S',' ','N','O','T',' ','N','U','L','L',0}; 00210 MSIQUERY *view; 00211 MSIRECORD *rec; 00212 const WCHAR *property; 00213 WCHAR *patch; 00214 UINT r; 00215 00216 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 00217 if (r != ERROR_SUCCESS) 00218 return r; 00219 00220 r = MSI_ViewExecute( view, 0 ); 00221 if (r != ERROR_SUCCESS) 00222 goto done; 00223 00224 if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS) 00225 { 00226 property = MSI_RecordGetString( rec, 1 ); 00227 patch = msi_dup_property( package->db, szPatch ); 00228 msi_set_property( package->db, property, patch ); 00229 msi_free( patch ); 00230 msiobj_release( &rec->hdr ); 00231 } 00232 00233 done: 00234 msiobj_release( &view->hdr ); 00235 return r; 00236 } 00237 00238 struct patch_offset 00239 { 00240 struct list entry; 00241 WCHAR *name; 00242 UINT sequence; 00243 }; 00244 00245 struct patch_offset_list 00246 { 00247 struct list files; 00248 UINT count, min, max; 00249 UINT offset_to_apply; 00250 }; 00251 00252 static struct patch_offset_list *patch_offset_list_create( void ) 00253 { 00254 struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) ); 00255 list_init( &pos->files ); 00256 pos->count = pos->max = 0; 00257 pos->min = 999999; 00258 return pos; 00259 } 00260 00261 static void patch_offset_list_free( struct patch_offset_list *pos ) 00262 { 00263 struct patch_offset *po, *po2; 00264 00265 LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct patch_offset, entry ) 00266 { 00267 msi_free( po->name ); 00268 msi_free( po ); 00269 } 00270 msi_free( pos ); 00271 } 00272 00273 static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos ) 00274 { 00275 static const WCHAR query[] = { 00276 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ', 00277 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ', 00278 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0}; 00279 MSIQUERY *view; 00280 MSIRECORD *rec; 00281 UINT r; 00282 00283 r = MSI_DatabaseOpenViewW( db, query, &view ); 00284 if (r != ERROR_SUCCESS) 00285 return; 00286 00287 rec = MSI_CreateRecord( 1 ); 00288 MSI_RecordSetInteger( rec, 1, last_sequence ); 00289 00290 r = MSI_ViewExecute( view, rec ); 00291 msiobj_release( &rec->hdr ); 00292 if (r != ERROR_SUCCESS) 00293 return; 00294 00295 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS) 00296 { 00297 UINT sequence = MSI_RecordGetInteger( rec, 2 ); 00298 00299 /* FIXME: we only use the max/min sequence numbers for now */ 00300 pos->min = min( pos->min, sequence ); 00301 pos->max = max( pos->max, sequence ); 00302 pos->count++; 00303 msiobj_release( &rec->hdr ); 00304 } 00305 msiobj_release( &view->hdr ); 00306 } 00307 00308 static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos ) 00309 { 00310 static const WCHAR query[] = { 00311 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ', 00312 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ', 00313 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0}; 00314 MSIQUERY *view; 00315 MSIRECORD *rec; 00316 UINT r; 00317 00318 r = MSI_DatabaseOpenViewW( db, query, &view ); 00319 if (r != ERROR_SUCCESS) 00320 return; 00321 00322 rec = MSI_CreateRecord( 1 ); 00323 MSI_RecordSetInteger( rec, 1, last_sequence ); 00324 00325 r = MSI_ViewExecute( view, rec ); 00326 msiobj_release( &rec->hdr ); 00327 if (r != ERROR_SUCCESS) 00328 return; 00329 00330 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS) 00331 { 00332 UINT attributes = MSI_RecordGetInteger( rec, 7 ); 00333 if (attributes & msidbFileAttributesPatchAdded) 00334 { 00335 struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) ); 00336 00337 po->name = msi_dup_record_field( rec, 1 ); 00338 po->sequence = MSI_RecordGetInteger( rec, 8 ); 00339 pos->min = min( pos->min, po->sequence ); 00340 pos->max = max( pos->max, po->sequence ); 00341 list_add_tail( &pos->files, &po->entry ); 00342 pos->count++; 00343 } 00344 msiobj_release( &rec->hdr ); 00345 } 00346 msiobj_release( &view->hdr ); 00347 } 00348 00349 static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos ) 00350 { 00351 static const WCHAR query[] = { 00352 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ', 00353 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ', 00354 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ', 00355 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0}; 00356 struct patch_offset *po; 00357 MSIRECORD *rec; 00358 MSIQUERY *view; 00359 UINT r; 00360 00361 r = MSI_DatabaseOpenViewW( db, query, &view ); 00362 if (r != ERROR_SUCCESS) 00363 return ERROR_SUCCESS; 00364 00365 rec = MSI_CreateRecord( 2 ); 00366 MSI_RecordSetInteger( rec, 1, pos->min ); 00367 MSI_RecordSetInteger( rec, 2, pos->max ); 00368 00369 r = MSI_ViewExecute( view, rec ); 00370 msiobj_release( &rec->hdr ); 00371 if (r != ERROR_SUCCESS) 00372 goto done; 00373 00374 LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry ) 00375 { 00376 UINT r_fetch; 00377 while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS) 00378 { 00379 const WCHAR *file = MSI_RecordGetString( rec, 1 ); 00380 UINT seq; 00381 00382 if (!strcmpiW( file, po->name )) 00383 { 00384 /* update record */ 00385 seq = MSI_RecordGetInteger( rec, 8 ); 00386 MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply ); 00387 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec ); 00388 if (r != ERROR_SUCCESS) 00389 ERR("Failed to update offset for file %s\n", debugstr_w(file)); 00390 msiobj_release( &rec->hdr ); 00391 break; 00392 } 00393 msiobj_release( &rec->hdr ); 00394 } 00395 if (r_fetch != ERROR_SUCCESS) break; 00396 } 00397 00398 done: 00399 msiobj_release( &view->hdr ); 00400 return ERROR_SUCCESS; 00401 } 00402 00403 static const WCHAR patch_media_query[] = { 00404 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ', 00405 'W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ', 00406 'A','N','D',' ','`','C','a','b','i','n','e','t','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ', 00407 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0}; 00408 00409 struct patch_media 00410 { 00411 struct list entry; 00412 UINT disk_id; 00413 UINT last_sequence; 00414 WCHAR *prompt; 00415 WCHAR *cabinet; 00416 WCHAR *volume; 00417 WCHAR *source; 00418 }; 00419 00420 static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch ) 00421 { 00422 static const WCHAR delete_query[] = { 00423 'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ', 00424 'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0}; 00425 static const WCHAR insert_query[] = { 00426 'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ', 00427 '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',', 00428 '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',', 00429 '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ', 00430 'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0}; 00431 MSIQUERY *view; 00432 MSIRECORD *rec; 00433 UINT r, disk_id; 00434 struct list media_list; 00435 struct patch_media *media, *next; 00436 00437 r = MSI_DatabaseOpenViewW( package->db, patch_media_query, &view ); 00438 if (r != ERROR_SUCCESS) return r; 00439 00440 r = MSI_ViewExecute( view, 0 ); 00441 if (r != ERROR_SUCCESS) 00442 { 00443 msiobj_release( &view->hdr ); 00444 TRACE("query failed %u\n", r); 00445 return r; 00446 } 00447 list_init( &media_list ); 00448 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS) 00449 { 00450 disk_id = MSI_RecordGetInteger( rec, 1 ); 00451 TRACE("disk_id %u\n", disk_id); 00452 if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID) 00453 { 00454 msiobj_release( &rec->hdr ); 00455 continue; 00456 } 00457 if (!(media = msi_alloc( sizeof( *media )))) goto done; 00458 media->disk_id = disk_id; 00459 media->last_sequence = MSI_RecordGetInteger( rec, 2 ); 00460 media->prompt = msi_dup_record_field( rec, 3 ); 00461 media->cabinet = msi_dup_record_field( rec, 4 ); 00462 media->volume = msi_dup_record_field( rec, 5 ); 00463 media->source = msi_dup_record_field( rec, 6 ); 00464 00465 list_add_tail( &media_list, &media->entry ); 00466 msiobj_release( &rec->hdr ); 00467 } 00468 LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry ) 00469 { 00470 MSIQUERY *delete_view, *insert_view; 00471 00472 r = MSI_DatabaseOpenViewW( package->db, delete_query, &delete_view ); 00473 if (r != ERROR_SUCCESS) goto done; 00474 00475 rec = MSI_CreateRecord( 1 ); 00476 MSI_RecordSetInteger( rec, 1, media->disk_id ); 00477 00478 r = MSI_ViewExecute( delete_view, rec ); 00479 msiobj_release( &delete_view->hdr ); 00480 msiobj_release( &rec->hdr ); 00481 if (r != ERROR_SUCCESS) goto done; 00482 00483 r = MSI_DatabaseOpenViewW( package->db, insert_query, &insert_view ); 00484 if (r != ERROR_SUCCESS) goto done; 00485 00486 disk_id = package->db->media_transform_disk_id; 00487 TRACE("disk id %u\n", disk_id); 00488 TRACE("last sequence %u\n", media->last_sequence); 00489 TRACE("prompt %s\n", debugstr_w(media->prompt)); 00490 TRACE("cabinet %s\n", debugstr_w(media->cabinet)); 00491 TRACE("volume %s\n", debugstr_w(media->volume)); 00492 TRACE("source %s\n", debugstr_w(media->source)); 00493 00494 rec = MSI_CreateRecord( 6 ); 00495 MSI_RecordSetInteger( rec, 1, disk_id ); 00496 MSI_RecordSetInteger( rec, 2, media->last_sequence ); 00497 MSI_RecordSetStringW( rec, 3, media->prompt ); 00498 MSI_RecordSetStringW( rec, 4, media->cabinet ); 00499 MSI_RecordSetStringW( rec, 5, media->volume ); 00500 MSI_RecordSetStringW( rec, 6, media->source ); 00501 00502 r = MSI_ViewExecute( insert_view, rec ); 00503 msiobj_release( &insert_view->hdr ); 00504 msiobj_release( &rec->hdr ); 00505 if (r != ERROR_SUCCESS) goto done; 00506 00507 r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet ); 00508 if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r); 00509 package->db->media_transform_disk_id++; 00510 } 00511 00512 done: 00513 msiobj_release( &view->hdr ); 00514 LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry ) 00515 { 00516 list_remove( &media->entry ); 00517 msi_free( media->prompt ); 00518 msi_free( media->cabinet ); 00519 msi_free( media->volume ); 00520 msi_free( media->source ); 00521 msi_free( media ); 00522 } 00523 return r; 00524 } 00525 00526 static UINT set_patch_offsets( MSIDATABASE *db ) 00527 { 00528 MSIQUERY *view; 00529 MSIRECORD *rec; 00530 UINT r; 00531 00532 r = MSI_DatabaseOpenViewW( db, patch_media_query, &view ); 00533 if (r != ERROR_SUCCESS) 00534 return r; 00535 00536 r = MSI_ViewExecute( view, 0 ); 00537 if (r != ERROR_SUCCESS) 00538 goto done; 00539 00540 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS) 00541 { 00542 UINT last_sequence = MSI_RecordGetInteger( rec, 2 ); 00543 struct patch_offset_list *pos; 00544 00545 /* FIXME: set/check Source field instead? */ 00546 if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET) 00547 { 00548 msiobj_release( &rec->hdr ); 00549 continue; 00550 } 00551 pos = patch_offset_list_create(); 00552 patch_offset_get_files( db, last_sequence, pos ); 00553 patch_offset_get_patches( db, last_sequence, pos ); 00554 if (pos->count) 00555 { 00556 UINT offset = db->media_transform_offset - pos->min; 00557 last_sequence = offset + pos->max; 00558 00559 /* FIXME: this is for the patch table, which is not yet properly transformed */ 00560 last_sequence += pos->min; 00561 pos->offset_to_apply = offset; 00562 patch_offset_modify_db( db, pos ); 00563 00564 MSI_RecordSetInteger( rec, 2, last_sequence ); 00565 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec ); 00566 if (r != ERROR_SUCCESS) 00567 ERR("Failed to update Media table entry, expect breakage (%u)\n", r); 00568 db->media_transform_offset = last_sequence + 1; 00569 } 00570 patch_offset_list_free( pos ); 00571 msiobj_release( &rec->hdr ); 00572 } 00573 00574 done: 00575 msiobj_release( &view->hdr ); 00576 return r; 00577 } 00578 00579 static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch ) 00580 { 00581 UINT i, r = ERROR_SUCCESS; 00582 WCHAR **substorage; 00583 00584 /* apply substorage transforms */ 00585 substorage = msi_split_string( patch->transforms, ';' ); 00586 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++) 00587 { 00588 r = apply_substorage_transform( package, patch_db, substorage[i] ); 00589 if (r == ERROR_SUCCESS) 00590 { 00591 add_patch_media( package, patch_db->storage ); 00592 set_patch_offsets( package->db ); 00593 } 00594 } 00595 msi_free( substorage ); 00596 if (r != ERROR_SUCCESS) 00597 return r; 00598 00599 patch_set_media_source_prop( package ); 00600 00601 patch->state = MSIPATCHSTATE_APPLIED; 00602 list_add_tail( &package->patches, &patch->entry ); 00603 return ERROR_SUCCESS; 00604 } 00605 00606 void msi_free_patchinfo( MSIPATCHINFO *patch ) 00607 { 00608 msi_free( patch->patchcode ); 00609 msi_free( patch->products ); 00610 msi_free( patch->transforms ); 00611 msi_free( patch->filename ); 00612 msi_free( patch->localfile ); 00613 msi_free( patch ); 00614 } 00615 00616 static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file ) 00617 { 00618 static const WCHAR dotmsp[] = {'.','m','s','p',0}; 00619 MSIDATABASE *patch_db = NULL; 00620 WCHAR localfile[MAX_PATH]; 00621 MSISUMMARYINFO *si; 00622 MSIPATCHINFO *patch = NULL; 00623 UINT r = ERROR_SUCCESS; 00624 00625 TRACE("%p %s\n", package, debugstr_w(file)); 00626 00627 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db ); 00628 if (r != ERROR_SUCCESS) 00629 { 00630 ERR("failed to open patch collection %s\n", debugstr_w( file ) ); 00631 return r; 00632 } 00633 if (!(si = MSI_GetSummaryInformationW( patch_db->storage, 0 ))) 00634 { 00635 msiobj_release( &patch_db->hdr ); 00636 return ERROR_FUNCTION_FAILED; 00637 } 00638 r = msi_check_patch_applicable( package, si ); 00639 if (r != ERROR_SUCCESS) 00640 { 00641 TRACE("patch not applicable\n"); 00642 r = ERROR_SUCCESS; 00643 goto done; 00644 } 00645 r = msi_parse_patch_summary( si, &patch ); 00646 if ( r != ERROR_SUCCESS ) 00647 goto done; 00648 00649 r = msi_create_empty_local_file( localfile, dotmsp ); 00650 if ( r != ERROR_SUCCESS ) 00651 goto done; 00652 00653 r = ERROR_OUTOFMEMORY; 00654 if (!(patch->filename = strdupW( file ))) goto done; 00655 if (!(patch->localfile = strdupW( localfile ))) goto done; 00656 00657 r = msi_apply_patch_db( package, patch_db, patch ); 00658 if (r != ERROR_SUCCESS) WARN("patch failed to apply %u\n", r); 00659 00660 done: 00661 msiobj_release( &si->hdr ); 00662 msiobj_release( &patch_db->hdr ); 00663 if (patch && r != ERROR_SUCCESS) 00664 { 00665 DeleteFileW( patch->localfile ); 00666 msi_free_patchinfo( patch ); 00667 } 00668 return r; 00669 } 00670 00671 /* get the PATCH property, and apply all the patches it specifies */ 00672 UINT msi_apply_patches( MSIPACKAGE *package ) 00673 { 00674 LPWSTR patch_list, *patches; 00675 UINT i, r = ERROR_SUCCESS; 00676 00677 patch_list = msi_dup_property( package->db, szPatch ); 00678 00679 TRACE("patches to be applied: %s\n", debugstr_w(patch_list)); 00680 00681 patches = msi_split_string( patch_list, ';' ); 00682 for (i = 0; patches && patches[i] && r == ERROR_SUCCESS; i++) 00683 r = msi_apply_patch_package( package, patches[i] ); 00684 00685 msi_free( patches ); 00686 msi_free( patch_list ); 00687 return r; 00688 } 00689 00690 UINT msi_apply_transforms( MSIPACKAGE *package ) 00691 { 00692 static const WCHAR szTransforms[] = {'T','R','A','N','S','F','O','R','M','S',0}; 00693 LPWSTR xform_list, *xforms; 00694 UINT i, r = ERROR_SUCCESS; 00695 00696 xform_list = msi_dup_property( package->db, szTransforms ); 00697 xforms = msi_split_string( xform_list, ';' ); 00698 00699 for (i = 0; xforms && xforms[i] && r == ERROR_SUCCESS; i++) 00700 { 00701 if (xforms[i][0] == ':') 00702 r = apply_substorage_transform( package, package->db, xforms[i] ); 00703 else 00704 { 00705 WCHAR *transform; 00706 00707 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i]; 00708 else 00709 { 00710 WCHAR *p = strrchrW( package->PackagePath, '\\' ); 00711 DWORD len = p - package->PackagePath + 1; 00712 00713 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) )) 00714 { 00715 msi_free( xforms ); 00716 msi_free( xform_list ); 00717 return ERROR_OUTOFMEMORY; 00718 } 00719 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) ); 00720 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) ); 00721 } 00722 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 ); 00723 if (transform != xforms[i]) msi_free( transform ); 00724 } 00725 } 00726 msi_free( xforms ); 00727 msi_free( xform_list ); 00728 return r; 00729 } 00730 00731 UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code ) 00732 { 00733 UINT r; 00734 DWORD len; 00735 WCHAR patch_file[MAX_PATH]; 00736 MSIDATABASE *patch_db; 00737 MSIPATCHINFO *patch_info; 00738 MSISUMMARYINFO *si; 00739 00740 len = sizeof(patch_file) / sizeof(WCHAR); 00741 r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context, 00742 INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len ); 00743 if (r != ERROR_SUCCESS) 00744 { 00745 ERR("failed to get patch filename %u\n", r); 00746 return r; 00747 } 00748 r = MSI_OpenDatabaseW( patch_file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db ); 00749 if (r != ERROR_SUCCESS) 00750 { 00751 ERR("failed to open patch database %s\n", debugstr_w( patch_file )); 00752 return r; 00753 } 00754 si = MSI_GetSummaryInformationW( patch_db->storage, 0 ); 00755 if (!si) 00756 { 00757 msiobj_release( &patch_db->hdr ); 00758 return ERROR_FUNCTION_FAILED; 00759 } 00760 r = msi_parse_patch_summary( si, &patch_info ); 00761 msiobj_release( &si->hdr ); 00762 if (r != ERROR_SUCCESS) 00763 { 00764 ERR("failed to parse patch summary %u\n", r); 00765 msiobj_release( &patch_db->hdr ); 00766 return r; 00767 } 00768 patch_info->localfile = strdupW( patch_file ); 00769 if (!patch_info->localfile) 00770 { 00771 msiobj_release( &patch_db->hdr ); 00772 msi_free_patchinfo( patch_info ); 00773 return ERROR_OUTOFMEMORY; 00774 } 00775 r = msi_apply_patch_db( package, patch_db, patch_info ); 00776 msiobj_release( &patch_db->hdr ); 00777 if (r != ERROR_SUCCESS) 00778 { 00779 ERR("failed to apply patch %u\n", r); 00780 msi_free_patchinfo( patch_info ); 00781 } 00782 return r; 00783 } Generated on Sat May 26 2012 04:23:50 for ReactOS by
1.7.6.1
|