~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/msi/patch.c

Version: ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Implementation of the Microsoft Installer (msi.dll)
  3  *
  4  * Copyright 2004,2005 Aric Stewart for CodeWeavers
  5  * Copyright 2011 Hans Leidekker for CodeWeavers
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  */
 21 
 22 #include <stdarg.h>
 23 #define COBJMACROS
 24 #include "windef.h"
 25 #include "winbase.h"
 26 #include "winreg.h"
 27 #include "objbase.h"
 28 #include "shlwapi.h"
 29 #include "wine/debug.h"
 30 #include "wine/unicode.h"
 31 #include "msipriv.h"
 32 
 33 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 34 
 35 static BOOL match_language( MSIPACKAGE *package, LANGID langid )
 36 {
 37     UINT i;
 38 
 39     if (!package->num_langids || !langid) return TRUE;
 40     for (i = 0; i < package->num_langids; i++)
 41     {
 42         if (package->langids[i] == langid) return TRUE;
 43     }
 44     return FALSE;
 45 }
 46 
 47 static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
 48 {
 49     LPWSTR prod_code, patch_product, template = NULL;
 50     UINT ret = ERROR_FUNCTION_FAILED;
 51 
 52     prod_code = msi_dup_property( package->db, szProductCode );
 53     patch_product = msi_get_suminfo_product( patch );
 54 
 55     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
 56 
 57     if (strstrW( patch_product, prod_code ))
 58     {
 59         MSISUMMARYINFO *si;
 60         const WCHAR *p;
 61 
 62         si = MSI_GetSummaryInformationW( patch, 0 );
 63         if (!si)
 64         {
 65             ERR("no summary information!\n");
 66             goto end;
 67         }
 68         template = msi_suminfo_dup_string( si, PID_TEMPLATE );
 69         if (!template)
 70         {
 71             ERR("no template property!\n");
 72             msiobj_release( &si->hdr );
 73             goto end;
 74         }
 75         if (!template[0])
 76         {
 77             ret = ERROR_SUCCESS;
 78             msiobj_release( &si->hdr );
 79             goto end;
 80         }
 81         TRACE("template: %s\n", debugstr_w(template));
 82         p = strchrW( template, ';' );
 83         if (p && match_language( package, atoiW( p + 1 ) ))
 84         {
 85             TRACE("applicable transform\n");
 86             ret = ERROR_SUCCESS;
 87         }
 88         /* FIXME: check platform */
 89         msiobj_release( &si->hdr );
 90     }
 91 
 92 end:
 93     msi_free( patch_product );
 94     msi_free( prod_code );
 95     msi_free( template );
 96     return ret;
 97 }
 98 
 99 static UINT apply_substorage_transform( MSIPACKAGE *package, MSIDATABASE *patch_db, LPCWSTR name )
100 {
101     UINT ret = ERROR_FUNCTION_FAILED;
102     IStorage *stg = NULL;
103     HRESULT r;
104 
105     TRACE("%p %s\n", package, debugstr_w(name));
106 
107     if (*name++ != ':')
108     {
109         ERR("expected a colon in %s\n", debugstr_w(name));
110         return ERROR_FUNCTION_FAILED;
111     }
112     r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
113     if (SUCCEEDED(r))
114     {
115         ret = check_transform_applicable( package, stg );
116         if (ret == ERROR_SUCCESS)
117             msi_table_apply_transform( package->db, stg );
118         else
119             TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
120         IStorage_Release( stg );
121     }
122     else
123     {
124         ERR("failed to open substorage %s\n", debugstr_w(name));
125     }
126     return ERROR_SUCCESS;
127 }
128 
129 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
130 {
131     LPWSTR guid_list, *guids, product_code;
132     UINT i, ret = ERROR_FUNCTION_FAILED;
133 
134     product_code = msi_dup_property( package->db, szProductCode );
135     if (!product_code)
136     {
137         /* FIXME: the property ProductCode should be written into the DB somewhere */
138         ERR("no product code to check\n");
139         return ERROR_SUCCESS;
140     }
141     guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
142     guids = msi_split_string( guid_list, ';' );
143     for (i = 0; guids[i] && ret != ERROR_SUCCESS; i++)
144     {
145         if (!strcmpW( guids[i], product_code )) ret = ERROR_SUCCESS;
146     }
147     msi_free( guids );
148     msi_free( guid_list );
149     msi_free( product_code );
150     return ret;
151 }
152 
153 static UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
154 {
155     MSIPATCHINFO *pi;
156     UINT r = ERROR_SUCCESS;
157     WCHAR *p;
158 
159     if (!(pi = msi_alloc_zero( sizeof(MSIPATCHINFO) )))
160     {
161         return ERROR_OUTOFMEMORY;
162     }
163     if (!(pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER )))
164     {
165         msi_free( pi );
166         return ERROR_OUTOFMEMORY;
167     }
168     p = pi->patchcode;
169     if (*p != '{')
170     {
171         msi_free( pi->patchcode );
172         msi_free( pi );
173         return ERROR_PATCH_PACKAGE_INVALID;
174     }
175     if (!(p = strchrW( p + 1, '}' )))
176     {
177         msi_free( pi->patchcode );
178         msi_free( pi );
179         return ERROR_PATCH_PACKAGE_INVALID;
180     }
181     if (p[1])
182     {
183         FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
184         p[1] = 0;
185     }
186     TRACE("patch code %s\n", debugstr_w(pi->patchcode));
187     if (!(pi->products = msi_suminfo_dup_string( si, PID_TEMPLATE )))
188     {
189         msi_free( pi->patchcode );
190         msi_free( pi );
191         return ERROR_OUTOFMEMORY;
192     }
193     if (!(pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR )))
194     {
195         msi_free( pi->patchcode );
196         msi_free( pi->products );
197         msi_free( pi );
198         return ERROR_OUTOFMEMORY;
199     }
200     *patch = pi;
201     return r;
202 }
203 
204 static UINT patch_set_media_source_prop( MSIPACKAGE *package )
205 {
206     static const WCHAR query[] = {
207         'S','E','L','E','C','T',' ','`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
208         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ',
209         'I','S',' ','N','O','T',' ','N','U','L','L',0};
210     MSIQUERY *view;
211     MSIRECORD *rec;
212     const WCHAR *property;
213     WCHAR *patch;
214     UINT r;
215 
216     r = MSI_DatabaseOpenViewW( package->db, query, &view );
217     if (r != ERROR_SUCCESS)
218         return r;
219 
220     r = MSI_ViewExecute( view, 0 );
221     if (r != ERROR_SUCCESS)
222         goto done;
223 
224     if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
225     {
226         property = MSI_RecordGetString( rec, 1 );
227         patch = msi_dup_property( package->db, szPatch );
228         msi_set_property( package->db, property, patch );
229         msi_free( patch );
230         msiobj_release( &rec->hdr );
231     }
232 
233 done:
234     msiobj_release( &view->hdr );
235     return r;
236 }
237 
238 struct patch_offset
239 {
240     struct list entry;
241     WCHAR *name;
242     UINT sequence;
243 };
244 
245 struct patch_offset_list
246 {
247     struct list files;
248     UINT count, min, max;
249     UINT offset_to_apply;
250 };
251 
252 static struct patch_offset_list *patch_offset_list_create( void )
253 {
254     struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
255     list_init( &pos->files );
256     pos->count = pos->max = 0;
257     pos->min = 999999;
258     return pos;
259 }
260 
261 static void patch_offset_list_free( struct patch_offset_list *pos )
262 {
263     struct patch_offset *po, *po2;
264 
265     LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct patch_offset, entry )
266     {
267         msi_free( po->name );
268         msi_free( po );
269     }
270     msi_free( pos );
271 }
272 
273 static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
274 {
275     static const WCHAR query[] = {
276         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
277         'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
278         'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
279     MSIQUERY *view;
280     MSIRECORD *rec;
281     UINT r;
282 
283     r = MSI_DatabaseOpenViewW( db, query, &view );
284     if (r != ERROR_SUCCESS)
285         return;
286 
287     rec = MSI_CreateRecord( 1 );
288     MSI_RecordSetInteger( rec, 1, last_sequence );
289 
290     r = MSI_ViewExecute( view, rec );
291     msiobj_release( &rec->hdr );
292     if (r != ERROR_SUCCESS)
293         return;
294 
295     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
296     {
297         UINT sequence = MSI_RecordGetInteger( rec, 2 );
298 
299         /* FIXME: we only use the max/min sequence numbers for now */
300         pos->min = min( pos->min, sequence );
301         pos->max = max( pos->max, sequence );
302         pos->count++;
303         msiobj_release( &rec->hdr );
304     }
305     msiobj_release( &view->hdr );
306 }
307 
308 static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
309 {
310     static const WCHAR query[] = {
311         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
312         'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
313         'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
314     MSIQUERY *view;
315     MSIRECORD *rec;
316     UINT r;
317 
318     r = MSI_DatabaseOpenViewW( db, query, &view );
319     if (r != ERROR_SUCCESS)
320         return;
321 
322     rec = MSI_CreateRecord( 1 );
323     MSI_RecordSetInteger( rec, 1, last_sequence );
324 
325     r = MSI_ViewExecute( view, rec );
326     msiobj_release( &rec->hdr );
327     if (r != ERROR_SUCCESS)
328         return;
329 
330     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
331     {
332         UINT attributes = MSI_RecordGetInteger( rec, 7 );
333         if (attributes & msidbFileAttributesPatchAdded)
334         {
335             struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
336 
337             po->name     = msi_dup_record_field( rec, 1 );
338             po->sequence = MSI_RecordGetInteger( rec, 8 );
339             pos->min     = min( pos->min, po->sequence );
340             pos->max     = max( pos->max, po->sequence );
341             list_add_tail( &pos->files, &po->entry );
342             pos->count++;
343         }
344         msiobj_release( &rec->hdr );
345     }
346     msiobj_release( &view->hdr );
347 }
348 
349 static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos )
350 {
351     static const WCHAR query[] = {
352         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
353         'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
354         'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
355         'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
356     struct patch_offset *po;
357     MSIRECORD *rec;
358     MSIQUERY *view;
359     UINT r;
360 
361     r = MSI_DatabaseOpenViewW( db, query, &view );
362     if (r != ERROR_SUCCESS)
363         return ERROR_SUCCESS;
364 
365     rec = MSI_CreateRecord( 2 );
366     MSI_RecordSetInteger( rec, 1, pos->min );
367     MSI_RecordSetInteger( rec, 2, pos->max );
368 
369     r = MSI_ViewExecute( view, rec );
370     msiobj_release( &rec->hdr );
371     if (r != ERROR_SUCCESS)
372         goto done;
373 
374     LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
375     {
376         UINT r_fetch;
377         while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
378         {
379             const WCHAR *file = MSI_RecordGetString( rec, 1 );
380             UINT seq;
381 
382             if (!strcmpiW( file, po->name ))
383             {
384                 /* update record */
385                 seq = MSI_RecordGetInteger( rec, 8 );
386                 MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
387                 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
388                 if (r != ERROR_SUCCESS)
389                     ERR("Failed to update offset for file %s\n", debugstr_w(file));
390                 msiobj_release( &rec->hdr );
391                 break;
392             }
393             msiobj_release( &rec->hdr );
394         }
395         if (r_fetch != ERROR_SUCCESS) break;
396     }
397 
398 done:
399     msiobj_release( &view->hdr );
400     return ERROR_SUCCESS;
401 }
402 
403 static const WCHAR patch_media_query[] = {
404     'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
405     'W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
406     'A','N','D',' ','`','C','a','b','i','n','e','t','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
407     'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
408 
409 struct patch_media
410 {
411     struct list entry;
412     UINT    disk_id;
413     UINT    last_sequence;
414     WCHAR  *prompt;
415     WCHAR  *cabinet;
416     WCHAR  *volume;
417     WCHAR  *source;
418 };
419 
420 static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
421 {
422     static const WCHAR delete_query[] = {
423         'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
424         'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0};
425     static const WCHAR insert_query[] = {
426         'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ',
427         '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',',
428         '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',',
429         '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ',
430         'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
431     MSIQUERY *view;
432     MSIRECORD *rec;
433     UINT r, disk_id;
434     struct list media_list;
435     struct patch_media *media, *next;
436 
437     r = MSI_DatabaseOpenViewW( package->db, patch_media_query, &view );
438     if (r != ERROR_SUCCESS) return r;
439 
440     r = MSI_ViewExecute( view, 0 );
441     if (r != ERROR_SUCCESS)
442     {
443         msiobj_release( &view->hdr );
444         TRACE("query failed %u\n", r);
445         return r;
446     }
447     list_init( &media_list );
448     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
449     {
450         disk_id = MSI_RecordGetInteger( rec, 1 );
451         TRACE("disk_id %u\n", disk_id);
452         if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
453         {
454             msiobj_release( &rec->hdr );
455             continue;
456         }
457         if (!(media = msi_alloc( sizeof( *media )))) goto done;
458         media->disk_id = disk_id;
459         media->last_sequence = MSI_RecordGetInteger( rec, 2 );
460         media->prompt  = msi_dup_record_field( rec, 3 );
461         media->cabinet = msi_dup_record_field( rec, 4 );
462         media->volume  = msi_dup_record_field( rec, 5 );
463         media->source  = msi_dup_record_field( rec, 6 );
464 
465         list_add_tail( &media_list, &media->entry );
466         msiobj_release( &rec->hdr );
467     }
468     LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry )
469     {
470         MSIQUERY *delete_view, *insert_view;
471 
472         r = MSI_DatabaseOpenViewW( package->db, delete_query, &delete_view );
473         if (r != ERROR_SUCCESS) goto done;
474 
475         rec = MSI_CreateRecord( 1 );
476         MSI_RecordSetInteger( rec, 1, media->disk_id );
477 
478         r = MSI_ViewExecute( delete_view, rec );
479         msiobj_release( &delete_view->hdr );
480         msiobj_release( &rec->hdr );
481         if (r != ERROR_SUCCESS) goto done;
482 
483         r = MSI_DatabaseOpenViewW( package->db, insert_query, &insert_view );
484         if (r != ERROR_SUCCESS) goto done;
485 
486         disk_id = package->db->media_transform_disk_id;
487         TRACE("disk id       %u\n", disk_id);
488         TRACE("last sequence %u\n", media->last_sequence);
489         TRACE("prompt        %s\n", debugstr_w(media->prompt));
490         TRACE("cabinet       %s\n", debugstr_w(media->cabinet));
491         TRACE("volume        %s\n", debugstr_w(media->volume));
492         TRACE("source        %s\n", debugstr_w(media->source));
493 
494         rec = MSI_CreateRecord( 6 );
495         MSI_RecordSetInteger( rec, 1, disk_id );
496         MSI_RecordSetInteger( rec, 2, media->last_sequence );
497         MSI_RecordSetStringW( rec, 3, media->prompt );
498         MSI_RecordSetStringW( rec, 4, media->cabinet );
499         MSI_RecordSetStringW( rec, 5, media->volume );
500         MSI_RecordSetStringW( rec, 6, media->source );
501 
502         r = MSI_ViewExecute( insert_view, rec );
503         msiobj_release( &insert_view->hdr );
504         msiobj_release( &rec->hdr );
505         if (r != ERROR_SUCCESS) goto done;
506 
507         r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet );
508         if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r);
509         package->db->media_transform_disk_id++;
510     }
511 
512 done:
513     msiobj_release( &view->hdr );
514     LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry )
515     {
516         list_remove( &media->entry );
517         msi_free( media->prompt );
518         msi_free( media->cabinet );
519         msi_free( media->volume );
520         msi_free( media->source );
521         msi_free( media );
522     }
523     return r;
524 }
525 
526 static UINT set_patch_offsets( MSIDATABASE *db )
527 {
528     MSIQUERY *view;
529     MSIRECORD *rec;
530     UINT r;
531 
532     r = MSI_DatabaseOpenViewW( db, patch_media_query, &view );
533     if (r != ERROR_SUCCESS)
534         return r;
535 
536     r = MSI_ViewExecute( view, 0 );
537     if (r != ERROR_SUCCESS)
538         goto done;
539 
540     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
541     {
542         UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
543         struct patch_offset_list *pos;
544 
545         /* FIXME: set/check Source field instead? */
546         if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
547         {
548             msiobj_release( &rec->hdr );
549             continue;
550         }
551         pos = patch_offset_list_create();
552         patch_offset_get_files( db, last_sequence, pos );
553         patch_offset_get_patches( db, last_sequence, pos );
554         if (pos->count)
555         {
556             UINT offset = db->media_transform_offset - pos->min;
557             last_sequence = offset + pos->max;
558 
559             /* FIXME: this is for the patch table, which is not yet properly transformed */
560             last_sequence += pos->min;
561             pos->offset_to_apply = offset;
562             patch_offset_modify_db( db, pos );
563 
564             MSI_RecordSetInteger( rec, 2, last_sequence );
565             r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
566             if (r != ERROR_SUCCESS)
567                 ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
568             db->media_transform_offset = last_sequence + 1;
569         }
570         patch_offset_list_free( pos );
571         msiobj_release( &rec->hdr );
572     }
573 
574 done:
575     msiobj_release( &view->hdr );
576     return r;
577 }
578 
579 static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
580 {
581     UINT i, r = ERROR_SUCCESS;
582     WCHAR **substorage;
583 
584     /* apply substorage transforms */
585     substorage = msi_split_string( patch->transforms, ';' );
586     for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
587     {
588         r = apply_substorage_transform( package, patch_db, substorage[i] );
589         if (r == ERROR_SUCCESS)
590         {
591             add_patch_media( package, patch_db->storage );
592             set_patch_offsets( package->db );
593         }
594     }
595     msi_free( substorage );
596     if (r != ERROR_SUCCESS)
597         return r;
598 
599     patch_set_media_source_prop( package );
600 
601     patch->state = MSIPATCHSTATE_APPLIED;
602     list_add_tail( &package->patches, &patch->entry );
603     return ERROR_SUCCESS;
604 }
605 
606 void msi_free_patchinfo( MSIPATCHINFO *patch )
607 {
608     msi_free( patch->patchcode );
609     msi_free( patch->products );
610     msi_free( patch->transforms );
611     msi_free( patch->filename );
612     msi_free( patch->localfile );
613     msi_free( patch );
614 }
615 
616 static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
617 {
618     static const WCHAR dotmsp[] = {'.','m','s','p',0};
619     MSIDATABASE *patch_db = NULL;
620     WCHAR localfile[MAX_PATH];
621     MSISUMMARYINFO *si;
622     MSIPATCHINFO *patch = NULL;
623     UINT r = ERROR_SUCCESS;
624 
625     TRACE("%p %s\n", package, debugstr_w(file));
626 
627     r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
628     if (r != ERROR_SUCCESS)
629     {
630         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
631         return r;
632     }
633     if (!(si = MSI_GetSummaryInformationW( patch_db->storage, 0 )))
634     {
635         msiobj_release( &patch_db->hdr );
636         return ERROR_FUNCTION_FAILED;
637     }
638     r = msi_check_patch_applicable( package, si );
639     if (r != ERROR_SUCCESS)
640     {
641         TRACE("patch not applicable\n");
642         r = ERROR_SUCCESS;
643         goto done;
644     }
645     r = msi_parse_patch_summary( si, &patch );
646     if ( r != ERROR_SUCCESS )
647         goto done;
648 
649     r = msi_create_empty_local_file( localfile, dotmsp );
650     if ( r != ERROR_SUCCESS )
651         goto done;
652 
653     r = ERROR_OUTOFMEMORY;
654     if (!(patch->filename = strdupW( file ))) goto done;
655     if (!(patch->localfile = strdupW( localfile ))) goto done;
656 
657     r = msi_apply_patch_db( package, patch_db, patch );
658     if (r != ERROR_SUCCESS) WARN("patch failed to apply %u\n", r);
659 
660 done:
661     msiobj_release( &si->hdr );
662     msiobj_release( &patch_db->hdr );
663     if (patch && r != ERROR_SUCCESS)
664     {
665         DeleteFileW( patch->localfile );
666         msi_free_patchinfo( patch );
667     }
668     return r;
669 }
670 
671 /* get the PATCH property, and apply all the patches it specifies */
672 UINT msi_apply_patches( MSIPACKAGE *package )
673 {
674     LPWSTR patch_list, *patches;
675     UINT i, r = ERROR_SUCCESS;
676 
677     patch_list = msi_dup_property( package->db, szPatch );
678 
679     TRACE("patches to be applied: %s\n", debugstr_w(patch_list));
680 
681     patches = msi_split_string( patch_list, ';' );
682     for (i = 0; patches && patches[i] && r == ERROR_SUCCESS; i++)
683         r = msi_apply_patch_package( package, patches[i] );
684 
685     msi_free( patches );
686     msi_free( patch_list );
687     return r;
688 }
689 
690 UINT msi_apply_transforms( MSIPACKAGE *package )
691 {
692     static const WCHAR szTransforms[] = {'T','R','A','N','S','F','O','R','M','S',0};
693     LPWSTR xform_list, *xforms;
694     UINT i, r = ERROR_SUCCESS;
695 
696     xform_list = msi_dup_property( package->db, szTransforms );
697     xforms = msi_split_string( xform_list, ';' );
698 
699     for (i = 0; xforms && xforms[i] && r == ERROR_SUCCESS; i++)
700     {
701         if (xforms[i][0] == ':')
702             r = apply_substorage_transform( package, package->db, xforms[i] );
703         else
704         {
705             WCHAR *transform;
706 
707             if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
708             else
709             {
710                 WCHAR *p = strrchrW( package->PackagePath, '\\' );
711                 DWORD len = p - package->PackagePath + 1;
712 
713                 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
714                 {
715                     msi_free( xforms );
716                     msi_free( xform_list );
717                     return ERROR_OUTOFMEMORY;
718                 }
719                 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
720                 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
721             }
722             r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
723             if (transform != xforms[i]) msi_free( transform );
724         }
725     }
726     msi_free( xforms );
727     msi_free( xform_list );
728     return r;
729 }
730 
731 UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
732 {
733     UINT r;
734     DWORD len;
735     WCHAR patch_file[MAX_PATH];
736     MSIDATABASE *patch_db;
737     MSIPATCHINFO *patch_info;
738     MSISUMMARYINFO *si;
739 
740     len = sizeof(patch_file) / sizeof(WCHAR);
741     r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
742                             INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
743     if (r != ERROR_SUCCESS)
744     {
745         ERR("failed to get patch filename %u\n", r);
746         return r;
747     }
748     r = MSI_OpenDatabaseW( patch_file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
749     if (r != ERROR_SUCCESS)
750     {
751         ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
752         return r;
753     }
754     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
755     if (!si)
756     {
757         msiobj_release( &patch_db->hdr );
758         return ERROR_FUNCTION_FAILED;
759     }
760     r = msi_parse_patch_summary( si, &patch_info );
761     msiobj_release( &si->hdr );
762     if (r != ERROR_SUCCESS)
763     {
764         ERR("failed to parse patch summary %u\n", r);
765         msiobj_release( &patch_db->hdr );
766         return r;
767     }
768     patch_info->localfile = strdupW( patch_file );
769     if (!patch_info->localfile)
770     {
771         msiobj_release( &patch_db->hdr );
772         msi_free_patchinfo( patch_info );
773         return ERROR_OUTOFMEMORY;
774     }
775     r = msi_apply_patch_db( package, patch_db, patch_info );
776     msiobj_release( &patch_db->hdr );
777     if (r != ERROR_SUCCESS)
778     {
779         ERR("failed to apply patch %u\n", r);
780         msi_free_patchinfo( patch_info );
781     }
782     return r;
783 }
784 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.