ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

patch.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.