ReactOS  0.4.13-dev-101-g0ca4b50
patch.c
Go to the documentation of this file.
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 
34 
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 
48 {
54 };
55 
56 static void free_transform_desc( struct transform_desc *desc )
57 {
58  msi_free( desc->product_code_from );
59  msi_free( desc->product_code_to );
60  msi_free( desc->version_from );
61  msi_free( desc->version_to );
62  msi_free( desc->upgrade_code );
63  msi_free( desc );
64 }
65 
66 static struct transform_desc *parse_transform_desc( const WCHAR *str )
67 {
68  struct transform_desc *ret;
69  const WCHAR *p = str, *q;
70  UINT len;
71 
72  if (!(ret = msi_alloc_zero( sizeof(*ret) ))) return NULL;
73 
74  q = strchrW( p, '}' );
75  if (*p != '{' || !q) goto error;
76 
77  len = q - p + 1;
78  if (!(ret->product_code_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
79  memcpy( ret->product_code_from, p, len * sizeof(WCHAR) );
80  ret->product_code_from[len] = 0;
81 
82  p = q + 1;
83  if (!(q = strchrW( p, ';' ))) goto error;
84  len = q - p;
85  if (!(ret->version_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
86  memcpy( ret->version_from, p, len * sizeof(WCHAR) );
87  ret->version_from[len] = 0;
88 
89  p = q + 1;
90  q = strchrW( p, '}' );
91  if (*p != '{' || !q) goto error;
92 
93  len = q - p + 1;
94  if (!(ret->product_code_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
95  memcpy( ret->product_code_to, p, len * sizeof(WCHAR) );
96  ret->product_code_to[len] = 0;
97 
98  p = q + 1;
99  if (!(q = strchrW( p, ';' ))) goto error;
100  len = q - p;
101  if (!(ret->version_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
102  memcpy( ret->version_to, p, len * sizeof(WCHAR) );
103  ret->version_to[len] = 0;
104 
105  p = q + 1;
106  q = strchrW( p, '}' );
107  if (*p != '{' || !q) goto error;
108 
109  len = q - p + 1;
110  if (!(ret->upgrade_code = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
111  memcpy( ret->upgrade_code, p, len * sizeof(WCHAR) );
112  ret->upgrade_code[len] = 0;
113 
114  return ret;
115 
116 error:
118  return NULL;
119 }
120 
122 {
123  static const UINT supported_flags =
127  MSISUMMARYINFO *si;
128  UINT r, valid_flags = 0, wanted_flags = 0;
129  WCHAR *template, *product, *p;
130  struct transform_desc *desc;
131 
132  r = msi_get_suminfo( transform, 0, &si );
133  if (r != ERROR_SUCCESS)
134  {
135  WARN("no summary information!\n");
136  return r;
137  }
138  wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
139  wanted_flags &= 0xffff; /* mask off error condition flags */
140  TRACE("validation flags 0x%04x\n", wanted_flags);
141 
142  /* native is not validating platform */
143  wanted_flags &= ~MSITRANSFORM_VALIDATE_PLATFORM;
144 
145  if (wanted_flags & ~supported_flags)
146  {
147  FIXME("unsupported validation flags 0x%04x\n", wanted_flags);
148  msiobj_release( &si->hdr );
149  return ERROR_FUNCTION_FAILED;
150  }
151  if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
152  {
153  WARN("no template property!\n");
154  msiobj_release( &si->hdr );
155  return ERROR_FUNCTION_FAILED;
156  }
157  TRACE("template property: %s\n", debugstr_w(template));
158  if (!(product = msi_get_suminfo_product( transform )))
159  {
160  WARN("no product property!\n");
161  msi_free( template );
162  msiobj_release( &si->hdr );
163  return ERROR_FUNCTION_FAILED;
164  }
165  TRACE("product property: %s\n", debugstr_w(product));
166  if (!(desc = parse_transform_desc( product )))
167  {
168  msi_free( template );
169  msiobj_release( &si->hdr );
170  return ERROR_FUNCTION_FAILED;
171  }
172  msi_free( product );
173 
174  if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE)
175  {
176  if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) )))
177  {
178  valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
179  }
180  }
181  if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT)
182  {
183  WCHAR *product_code_installed = msi_dup_property( package->db, szProductCode );
184 
185  if (!product_code_installed)
186  {
187  msi_free( template );
189  msiobj_release( &si->hdr );
191  }
192  if (!strcmpW( desc->product_code_from, product_code_installed ))
193  {
194  valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT;
195  }
196  msi_free( product_code_installed );
197  }
198  msi_free( template );
199  if (wanted_flags & MSITRANSFORM_VALIDATE_MAJORVERSION)
200  {
201  WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion );
202  DWORD major_installed, minor_installed, major, minor;
203 
204  if (!product_version_installed)
205  {
207  msiobj_release( &si->hdr );
209  }
210  msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
211  msi_parse_version_string( desc->version_from, &major, &minor );
212 
213  if (major_installed == major)
214  {
215  valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION;
216  wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION;
217  }
218  msi_free( product_version_installed );
219  }
220  else if (wanted_flags & MSITRANSFORM_VALIDATE_MINORVERSION)
221  {
222  WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion );
223  DWORD major_installed, minor_installed, major, minor;
224 
225  if (!product_version_installed)
226  {
228  msiobj_release( &si->hdr );
230  }
231  msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
232  msi_parse_version_string( desc->version_from, &major, &minor );
233 
234  if (major_installed == major && minor_installed == minor)
235  valid_flags |= MSITRANSFORM_VALIDATE_MINORVERSION;
236  msi_free( product_version_installed );
237  }
238  if (wanted_flags & MSITRANSFORM_VALIDATE_UPGRADECODE)
239  {
240  WCHAR *upgrade_code_installed = msi_dup_property( package->db, szUpgradeCode );
241 
242  if (!upgrade_code_installed)
243  {
245  msiobj_release( &si->hdr );
247  }
248  if (!strcmpW( desc->upgrade_code, upgrade_code_installed ))
249  valid_flags |= MSITRANSFORM_VALIDATE_UPGRADECODE;
250  msi_free( upgrade_code_installed );
251  }
252 
254  msiobj_release( &si->hdr );
255  if ((valid_flags & wanted_flags) != wanted_flags) return ERROR_FUNCTION_FAILED;
256  TRACE("applicable transform\n");
257  return ERROR_SUCCESS;
258 }
259 
261 {
263  IStorage *stg = NULL;
264  HRESULT r;
265 
266  TRACE("%p %s\n", package, debugstr_w(name));
267 
268  if (*name++ != ':')
269  {
270  ERR("expected a colon in %s\n", debugstr_w(name));
271  return ERROR_FUNCTION_FAILED;
272  }
273  r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
274  if (SUCCEEDED(r))
275  {
276  ret = check_transform_applicable( package, stg );
277  if (ret == ERROR_SUCCESS)
278  msi_table_apply_transform( package->db, stg );
279  else
280  TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
281  IStorage_Release( stg );
282  }
283  else
284  {
285  ERR("failed to open substorage %s\n", debugstr_w(name));
286  }
287  return ERROR_SUCCESS;
288 }
289 
291 {
292  LPWSTR guid_list, *guids, product_code;
294 
295  product_code = msi_dup_property( package->db, szProductCode );
296  if (!product_code)
297  {
298  /* FIXME: the property ProductCode should be written into the DB somewhere */
299  ERR("no product code to check\n");
300  return ERROR_SUCCESS;
301  }
303  guids = msi_split_string( guid_list, ';' );
304  for (i = 0; guids[i] && ret != ERROR_SUCCESS; i++)
305  {
306  if (!strcmpW( guids[i], product_code )) ret = ERROR_SUCCESS;
307  }
308  msi_free( guids );
309  msi_free( guid_list );
310  msi_free( product_code );
311  return ret;
312 }
313 
315 {
316  MSIPATCHINFO *pi;
317  UINT r = ERROR_SUCCESS;
318  WCHAR *p;
319 
320  if (!(pi = msi_alloc_zero( sizeof(MSIPATCHINFO) )))
321  {
322  return ERROR_OUTOFMEMORY;
323  }
324  if (!(pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER )))
325  {
326  msi_free( pi );
327  return ERROR_OUTOFMEMORY;
328  }
329  p = pi->patchcode;
330  if (*p != '{')
331  {
332  msi_free( pi->patchcode );
333  msi_free( pi );
335  }
336  if (!(p = strchrW( p + 1, '}' )))
337  {
338  msi_free( pi->patchcode );
339  msi_free( pi );
341  }
342  if (p[1])
343  {
344  FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
345  p[1] = 0;
346  }
347  TRACE("patch code %s\n", debugstr_w(pi->patchcode));
348  if (!(pi->products = msi_suminfo_dup_string( si, PID_TEMPLATE )))
349  {
350  msi_free( pi->patchcode );
351  msi_free( pi );
352  return ERROR_OUTOFMEMORY;
353  }
354  if (!(pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR )))
355  {
356  msi_free( pi->patchcode );
357  msi_free( pi->products );
358  msi_free( pi );
359  return ERROR_OUTOFMEMORY;
360  }
361  *patch = pi;
362  return r;
363 }
364 
366 {
367  static const WCHAR query[] = {
368  'S','E','L','E','C','T',' ','`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
369  '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ',
370  'I','S',' ','N','O','T',' ','N','U','L','L',0};
371  MSIQUERY *view;
372  MSIRECORD *rec;
373  const WCHAR *property;
374  WCHAR *patch;
375  UINT r;
376 
377  r = MSI_DatabaseOpenViewW( package->db, query, &view );
378  if (r != ERROR_SUCCESS)
379  return r;
380 
381  r = MSI_ViewExecute( view, 0 );
382  if (r != ERROR_SUCCESS)
383  goto done;
384 
385  if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
386  {
387  property = MSI_RecordGetString( rec, 1 );
388  patch = msi_dup_property( package->db, szPatch );
389  msi_set_property( package->db, property, patch, -1 );
390  msi_free( patch );
391  msiobj_release( &rec->hdr );
392  }
393 
394 done:
395  msiobj_release( &view->hdr );
396  return r;
397 }
398 
400 {
401  struct list entry;
404 };
405 
407 {
408  struct list files;
409  struct list patches;
412 };
413 
415 {
416  struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
417  list_init( &pos->files );
418  list_init( &pos->patches );
419  pos->count = pos->max = 0;
420  pos->min = 999999;
421  return pos;
422 }
423 
425 {
426  struct patch_offset *po, *po2;
427 
428  LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct patch_offset, entry )
429  {
430  msi_free( po->name );
431  msi_free( po );
432  }
433  LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->patches, struct patch_offset, entry )
434  {
435  msi_free( po->name );
436  msi_free( po );
437  }
438  msi_free( pos );
439 }
440 
441 static void patch_offset_get_filepatches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
442 {
443  static const WCHAR query[] = {
444  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
445  'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
446  'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
447  MSIQUERY *view;
448  MSIRECORD *rec;
449  UINT r;
450 
451  r = MSI_DatabaseOpenViewW( db, query, &view );
452  if (r != ERROR_SUCCESS)
453  return;
454 
455  rec = MSI_CreateRecord( 1 );
456  MSI_RecordSetInteger( rec, 1, last_sequence );
457 
458  r = MSI_ViewExecute( view, rec );
459  msiobj_release( &rec->hdr );
460  if (r != ERROR_SUCCESS)
461  return;
462 
463  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
464  {
465  struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
466 
467  po->name = msi_dup_record_field( rec, 1 );
468  po->sequence = MSI_RecordGetInteger( rec, 2 );
469  pos->min = min( pos->min, po->sequence );
470  pos->max = max( pos->max, po->sequence );
471  list_add_tail( &pos->patches, &po->entry );
472  pos->count++;
473 
474  msiobj_release( &rec->hdr );
475  }
476  msiobj_release( &view->hdr );
477 }
478 
479 static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
480 {
481  static const WCHAR query[] = {
482  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
483  'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
484  'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
485  MSIQUERY *view;
486  MSIRECORD *rec;
487  UINT r;
488 
489  r = MSI_DatabaseOpenViewW( db, query, &view );
490  if (r != ERROR_SUCCESS)
491  return;
492 
493  rec = MSI_CreateRecord( 1 );
494  MSI_RecordSetInteger( rec, 1, last_sequence );
495 
496  r = MSI_ViewExecute( view, rec );
497  msiobj_release( &rec->hdr );
498  if (r != ERROR_SUCCESS)
499  return;
500 
501  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
502  {
503  UINT attributes = MSI_RecordGetInteger( rec, 7 );
504  if (attributes & msidbFileAttributesPatchAdded)
505  {
506  struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
507 
508  po->name = msi_dup_record_field( rec, 1 );
509  po->sequence = MSI_RecordGetInteger( rec, 8 );
510  pos->min = min( pos->min, po->sequence );
511  pos->max = max( pos->max, po->sequence );
512  list_add_tail( &pos->files, &po->entry );
513  pos->count++;
514  }
515  msiobj_release( &rec->hdr );
516  }
517  msiobj_release( &view->hdr );
518 }
519 
521  MSIQUERY *view, MSIRECORD *rec )
522 {
523  struct patch_offset *po;
524  const WCHAR *file = MSI_RecordGetString( rec, 1 );
525  UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 8 );
526 
527  LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
528  {
529  if (!strcmpiW( file, po->name ))
530  {
531  MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
533  if (r != ERROR_SUCCESS)
534  ERR("Failed to update offset for file %s (%u)\n", debugstr_w(file), r);
535  break;
536  }
537  }
538  return r;
539 }
540 
542  MSIQUERY *view, MSIRECORD *rec )
543 {
544  static const WCHAR delete_query[] = {
545  'D','E','L','E','T','E',' ','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
546  'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','?',' ',
547  'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','=',' ','?',0};
548  static const WCHAR insert_query[] = {
549  'I','N','S','E','R','T',' ','I','N','T','O',' ','`','P','a','t','c','h','`',' ',
550  '(','`','F','i','l','e','_','`',',','`','S','e','q','u','e','n','c','e','`',',',
551  '`','P','a','t','c','h','S','i','z','e','`',',','`','A','t','t','r','i','b','u','t','e','s','`',',',
552  '`','H','e','a','d','e','r','`',',','`','S','t','r','e','a','m','R','e','f','_','`',')',' ',
553  'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
554  struct patch_offset *po;
555  const WCHAR *file = MSI_RecordGetString( rec, 1 );
556  UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 2 );
557 
558  LIST_FOR_EACH_ENTRY( po, &pos->patches, struct patch_offset, entry )
559  {
560  if (seq == po->sequence && !strcmpiW( file, po->name ))
561  {
562  MSIQUERY *delete_view, *insert_view;
563  MSIRECORD *rec2;
564 
565  r = MSI_DatabaseOpenViewW( db, delete_query, &delete_view );
566  if (r != ERROR_SUCCESS) return r;
567 
568  rec2 = MSI_CreateRecord( 2 );
569  MSI_RecordSetStringW( rec2, 1, po->name );
570  MSI_RecordSetInteger( rec2, 2, po->sequence );
571  r = MSI_ViewExecute( delete_view, rec2 );
572  msiobj_release( &delete_view->hdr );
573  msiobj_release( &rec2->hdr );
574  if (r != ERROR_SUCCESS) return r;
575 
576  r = MSI_DatabaseOpenViewW( db, insert_query, &insert_view );
577  if (r != ERROR_SUCCESS) return r;
578 
579  MSI_RecordSetInteger( rec, 2, po->sequence + pos->offset_to_apply );
580 
581  r = MSI_ViewExecute( insert_view, rec );
582  msiobj_release( &insert_view->hdr );
583  if (r != ERROR_SUCCESS)
584  ERR("Failed to update offset for filepatch %s (%u)\n", debugstr_w(file), r);
585  break;
586  }
587  }
588  return r;
589 }
590 
592 {
593  static const WCHAR file_query[] = {
594  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','i','l','e','`',' ',
595  'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
596  'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
597  'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
598  static const WCHAR patch_query[] = {
599  'S','E','L','E','C','T',' ','*','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
600  'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
601  'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
602  'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
603  MSIRECORD *rec;
604  MSIQUERY *view;
605  UINT r, min = pos->min, max = pos->max, r_fetch;
606 
607  r = MSI_DatabaseOpenViewW( db, file_query, &view );
608  if (r != ERROR_SUCCESS)
609  return ERROR_SUCCESS;
610 
611  rec = MSI_CreateRecord( 2 );
612  MSI_RecordSetInteger( rec, 1, min );
613  MSI_RecordSetInteger( rec, 2, max );
614 
615  r = MSI_ViewExecute( view, rec );
616  msiobj_release( &rec->hdr );
617  if (r != ERROR_SUCCESS)
618  goto done;
619 
620  while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
621  {
622  r = patch_update_file_sequence( db, pos, view, rec );
623  msiobj_release( &rec->hdr );
624  if (r != ERROR_SUCCESS) goto done;
625  }
626  msiobj_release( &view->hdr );
627 
628  r = MSI_DatabaseOpenViewW( db, patch_query, &view );
629  if (r != ERROR_SUCCESS)
630  return ERROR_SUCCESS;
631 
632  rec = MSI_CreateRecord( 2 );
633  MSI_RecordSetInteger( rec, 1, min );
634  MSI_RecordSetInteger( rec, 2, max );
635 
636  r = MSI_ViewExecute( view, rec );
637  msiobj_release( &rec->hdr );
638  if (r != ERROR_SUCCESS)
639  goto done;
640 
641  while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
642  {
643  r = patch_update_filepatch_sequence( db, pos, view, rec );
644  msiobj_release( &rec->hdr );
645  if (r != ERROR_SUCCESS) goto done;
646  }
647 
648 done:
649  msiobj_release( &view->hdr );
650  return r;
651 }
652 
653 static const WCHAR patch_media_query[] = {
654  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
655  'W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
656  'A','N','D',' ','`','C','a','b','i','n','e','t','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
657  'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
658 
660 {
661  struct list entry;
668 };
669 
670 static UINT patch_add_media( MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch )
671 {
672  static const WCHAR delete_query[] = {
673  'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
674  'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0};
675  static const WCHAR insert_query[] = {
676  'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ',
677  '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',',
678  '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',',
679  '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ',
680  'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
681  MSIQUERY *view;
682  MSIRECORD *rec;
683  UINT r, disk_id;
684  struct list media_list;
685  struct patch_media *media, *next;
686 
688  if (r != ERROR_SUCCESS) return r;
689 
690  r = MSI_ViewExecute( view, 0 );
691  if (r != ERROR_SUCCESS)
692  {
693  msiobj_release( &view->hdr );
694  TRACE("query failed %u\n", r);
695  return r;
696  }
697  list_init( &media_list );
698  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
699  {
700  disk_id = MSI_RecordGetInteger( rec, 1 );
701  TRACE("disk_id %u\n", disk_id);
702  if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
703  {
704  msiobj_release( &rec->hdr );
705  continue;
706  }
707  if (!(media = msi_alloc( sizeof( *media )))) {
708  msiobj_release( &rec->hdr );
709  goto done;
710  }
711  media->disk_id = disk_id;
712  media->last_sequence = MSI_RecordGetInteger( rec, 2 );
713  media->prompt = msi_dup_record_field( rec, 3 );
714  media->cabinet = msi_dup_record_field( rec, 4 );
715  media->volume = msi_dup_record_field( rec, 5 );
716  media->source = msi_dup_record_field( rec, 6 );
717 
718  list_add_tail( &media_list, &media->entry );
719  msiobj_release( &rec->hdr );
720  }
721  LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry )
722  {
723  MSIQUERY *delete_view, *insert_view;
724 
725  r = MSI_DatabaseOpenViewW( package->db, delete_query, &delete_view );
726  if (r != ERROR_SUCCESS) goto done;
727 
728  rec = MSI_CreateRecord( 1 );
729  MSI_RecordSetInteger( rec, 1, media->disk_id );
730 
731  r = MSI_ViewExecute( delete_view, rec );
732  msiobj_release( &delete_view->hdr );
733  msiobj_release( &rec->hdr );
734  if (r != ERROR_SUCCESS) goto done;
735 
736  r = MSI_DatabaseOpenViewW( package->db, insert_query, &insert_view );
737  if (r != ERROR_SUCCESS) goto done;
738 
739  disk_id = package->db->media_transform_disk_id;
740  TRACE("disk id %u\n", disk_id);
741  TRACE("last sequence %u\n", media->last_sequence);
742  TRACE("prompt %s\n", debugstr_w(media->prompt));
743  TRACE("cabinet %s\n", debugstr_w(media->cabinet));
744  TRACE("volume %s\n", debugstr_w(media->volume));
745  TRACE("source %s\n", debugstr_w(media->source));
746 
747  rec = MSI_CreateRecord( 6 );
748  MSI_RecordSetInteger( rec, 1, disk_id );
749  MSI_RecordSetInteger( rec, 2, media->last_sequence );
750  MSI_RecordSetStringW( rec, 3, media->prompt );
751  MSI_RecordSetStringW( rec, 4, media->cabinet );
752  MSI_RecordSetStringW( rec, 5, media->volume );
753  MSI_RecordSetStringW( rec, 6, media->source );
754 
755  r = MSI_ViewExecute( insert_view, rec );
756  msiobj_release( &insert_view->hdr );
757  msiobj_release( &rec->hdr );
758  if (r != ERROR_SUCCESS) goto done;
759 
760  r = msi_add_cabinet_stream( package, disk_id, storage, media->cabinet );
761  if (r != ERROR_SUCCESS) ERR("failed to add cabinet stream %u\n", r);
762  else
763  {
764  patch->disk_id = disk_id;
765  package->db->media_transform_disk_id++;
766  }
767  }
768 
769 done:
770  msiobj_release( &view->hdr );
771  LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry )
772  {
773  list_remove( &media->entry );
774  msi_free( media->prompt );
775  msi_free( media->cabinet );
776  msi_free( media->volume );
777  msi_free( media->source );
778  msi_free( media );
779  }
780  return r;
781 }
782 
784 {
785  MSIQUERY *view;
786  MSIRECORD *rec;
787  UINT r;
788 
790  if (r != ERROR_SUCCESS)
791  return r;
792 
793  r = MSI_ViewExecute( view, 0 );
794  if (r != ERROR_SUCCESS)
795  goto done;
796 
797  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
798  {
799  UINT offset, last_sequence = MSI_RecordGetInteger( rec, 2 );
800  struct patch_offset_list *pos;
801 
802  /* FIXME: set/check Source field instead? */
803  if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
804  {
805  msiobj_release( &rec->hdr );
806  continue;
807  }
809  patch_offset_get_files( db, last_sequence, pos );
810  patch_offset_get_filepatches( db, last_sequence, pos );
811 
812  offset = db->media_transform_offset - pos->min;
813  last_sequence = offset + pos->max;
814 
815  last_sequence += pos->min;
816  pos->offset_to_apply = offset;
817  if (pos->count)
818  {
819  r = patch_offset_modify_db( db, pos );
820  if (r != ERROR_SUCCESS)
821  ERR("Failed to set offsets, expect breakage (%u)\n", r);
822  }
823  MSI_RecordSetInteger( rec, 2, last_sequence );
825  if (r != ERROR_SUCCESS)
826  ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
827 
828  db->media_transform_offset = last_sequence + 1;
829 
831  msiobj_release( &rec->hdr );
832  }
833 
834 done:
835  msiobj_release( &view->hdr );
836  return r;
837 }
838 
840 {
841  static const WCHAR query[] = {
842  'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ','F','R','O','M',' ',
843  '`','M','s','i','P','a','t','c','h','M','e','t','a','d','a','t','a','`',' ',
844  'W','H','E','R','E',' ','`','C','o','m','p','a','n','y','`',' ','I','S',' ',
845  'N','U','L','L',' ','A','N','D',' ','`','P','r','o','p','e','r','t','y','`','=',
846  '\'','A','l','l','o','w','R','e','m','o','v','a','l','\'',0};
847  MSIQUERY *view;
848  MSIRECORD *rec;
849  DWORD ret = 0;
850 
851  if (MSI_DatabaseOpenViewW( db, query, &view ) != ERROR_SUCCESS) return 0;
852  if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
853  {
854  msiobj_release( &view->hdr );
855  return 0;
856  }
857 
858  if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
859  {
860  const WCHAR *value = MSI_RecordGetString( rec, 1 );
861  ret = atoiW( value );
862  msiobj_release( &rec->hdr );
863  }
864 
865  FIXME( "check other criteria\n" );
866 
867  msiobj_release( &view->hdr );
868  return ret;
869 }
870 
871 static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
872 {
873  UINT i, r = ERROR_SUCCESS;
874  WCHAR **substorage;
875 
876  /* apply substorage transforms */
877  substorage = msi_split_string( patch->transforms, ';' );
878  for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
879  {
880  r = apply_substorage_transform( package, patch_db, substorage[i] );
881  if (r == ERROR_SUCCESS)
882  {
883  r = patch_set_offsets( package->db, patch );
884  if (r == ERROR_SUCCESS)
885  r = patch_add_media( package, patch_db->storage, patch );
886  }
887  }
888  msi_free( substorage );
889  if (r != ERROR_SUCCESS)
890  return r;
891 
892  r = patch_set_media_source_prop( package );
893  if (r != ERROR_SUCCESS)
894  return r;
895 
896  patch->uninstallable = is_uninstallable( patch_db );
897  patch->state = MSIPATCHSTATE_APPLIED;
898  list_add_tail( &package->patches, &patch->entry );
899  return ERROR_SUCCESS;
900 }
901 
903 {
904  msi_free( patch->patchcode );
905  msi_free( patch->products );
906  msi_free( patch->transforms );
907  msi_free( patch->filename );
908  msi_free( patch->localfile );
909  msi_free( patch );
910 }
911 
913 {
914  static const WCHAR dotmsp[] = {'.','m','s','p',0};
915  MSIDATABASE *patch_db = NULL;
916  WCHAR localfile[MAX_PATH];
917  MSISUMMARYINFO *si;
918  MSIPATCHINFO *patch = NULL;
919  UINT r;
920 
921  TRACE("%p, %s\n", package, debugstr_w(file));
922 
924  if (r != ERROR_SUCCESS)
925  {
926  ERR("failed to open patch collection %s\n", debugstr_w( file ) );
927  return r;
928  }
929  r = msi_get_suminfo( patch_db->storage, 0, &si );
930  if (r != ERROR_SUCCESS)
931  {
932  msiobj_release( &patch_db->hdr );
933  return r;
934  }
935  r = msi_check_patch_applicable( package, si );
936  if (r != ERROR_SUCCESS)
937  {
938  TRACE("patch not applicable\n");
939  r = ERROR_SUCCESS;
940  goto done;
941  }
942  r = msi_parse_patch_summary( si, &patch );
943  if ( r != ERROR_SUCCESS )
944  goto done;
945 
946  r = msi_create_empty_local_file( localfile, dotmsp );
947  if ( r != ERROR_SUCCESS )
948  goto done;
949 
951  patch->registered = FALSE;
952  if (!(patch->filename = strdupW( file ))) goto done;
953  if (!(patch->localfile = strdupW( localfile ))) goto done;
954 
955  r = msi_apply_patch_db( package, patch_db, patch );
956  if (r != ERROR_SUCCESS) WARN("patch failed to apply %u\n", r);
957 
958 done:
959  msiobj_release( &si->hdr );
960  msiobj_release( &patch_db->hdr );
961  if (patch && r != ERROR_SUCCESS)
962  {
963  DeleteFileW( patch->localfile );
964  msi_free_patchinfo( patch );
965  }
966  return r;
967 }
968 
969 /* get the PATCH property, and apply all the patches it specifies */
971 {
972  LPWSTR patch_list, *patches;
973  UINT i, r = ERROR_SUCCESS;
974 
975  patch_list = msi_dup_property( package->db, szPatch );
976 
977  TRACE("patches to be applied: %s\n", debugstr_w(patch_list));
978 
979  patches = msi_split_string( patch_list, ';' );
980  for (i = 0; patches && patches[i] && r == ERROR_SUCCESS; i++)
981  r = msi_apply_patch_package( package, patches[i] );
982 
983  msi_free( patches );
984  msi_free( patch_list );
985  return r;
986 }
987 
989 {
990  static const WCHAR szTransforms[] = {'T','R','A','N','S','F','O','R','M','S',0};
991  LPWSTR xform_list, *xforms;
992  UINT i, r = ERROR_SUCCESS;
993 
994  xform_list = msi_dup_property( package->db, szTransforms );
995  xforms = msi_split_string( xform_list, ';' );
996 
997  for (i = 0; xforms && xforms[i] && r == ERROR_SUCCESS; i++)
998  {
999  if (xforms[i][0] == ':')
1000  r = apply_substorage_transform( package, package->db, xforms[i] );
1001  else
1002  {
1003  WCHAR *transform;
1004 
1005  if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
1006  else
1007  {
1008  WCHAR *p = strrchrW( package->PackagePath, '\\' );
1009  DWORD len = p - package->PackagePath + 1;
1010 
1011  if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
1012  {
1013  msi_free( xforms );
1014  msi_free( xform_list );
1015  return ERROR_OUTOFMEMORY;
1016  }
1017  memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
1018  memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
1019  }
1020  r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
1021  if (transform != xforms[i]) msi_free( transform );
1022  }
1023  }
1024  msi_free( xforms );
1025  msi_free( xform_list );
1026  return r;
1027 }
1028 
1030 {
1031  UINT r;
1032  DWORD len;
1034  MSIDATABASE *patch_db;
1035  MSIPATCHINFO *patch_info;
1036  MSISUMMARYINFO *si;
1037 
1038  TRACE("%p, %s\n", package, debugstr_w(patch_code));
1039 
1040  len = sizeof(patch_file) / sizeof(WCHAR);
1041  r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
1043  if (r != ERROR_SUCCESS)
1044  {
1045  ERR("failed to get patch filename %u\n", r);
1046  return r;
1047  }
1049  if (r != ERROR_SUCCESS)
1050  {
1051  ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
1052  return r;
1053  }
1054  r = msi_get_suminfo( patch_db->storage, 0, &si );
1055  if (r != ERROR_SUCCESS)
1056  {
1057  msiobj_release( &patch_db->hdr );
1058  return r;
1059  }
1060  r = msi_parse_patch_summary( si, &patch_info );
1061  msiobj_release( &si->hdr );
1062  if (r != ERROR_SUCCESS)
1063  {
1064  ERR("failed to parse patch summary %u\n", r);
1065  msiobj_release( &patch_db->hdr );
1066  return r;
1067  }
1068  patch_info->registered = TRUE;
1069  patch_info->localfile = strdupW( patch_file );
1070  if (!patch_info->localfile)
1071  {
1072  msiobj_release( &patch_db->hdr );
1073  msi_free_patchinfo( patch_info );
1074  return ERROR_OUTOFMEMORY;
1075  }
1076  r = msi_apply_patch_db( package, patch_db, patch_info );
1077  msiobj_release( &patch_db->hdr );
1078  if (r != ERROR_SUCCESS)
1079  {
1080  ERR("failed to apply patch %u\n", r);
1081  msi_free_patchinfo( patch_info );
1082  }
1083  return r;
1084 }
LPWSTR msi_suminfo_dup_string(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:681
UINT msi_table_apply_transform(MSIDATABASE *db, IStorage *stg) DECLSPEC_HIDDEN
Definition: table.c:2714
LPWSTR ProductCode
Definition: msipriv.h:426
#define PID_TEMPLATE
Definition: suminfo.c:49
#define MSIDBOPEN_READONLY
Definition: msiquery.h:66
#define max(a, b)
Definition: svc.c:63
void msi_free_patchinfo(MSIPATCHINFO *patch)
Definition: patch.c:902
#define TRUE
Definition: types.h:120
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1558
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:649
#define PID_CHARCOUNT
Definition: suminfo.c:58
static UINT msi_parse_patch_summary(MSISUMMARYINFO *si, MSIPATCHINFO **patch)
Definition: patch.c:314
UINT msi_check_patch_applicable(MSIPACKAGE *package, MSISUMMARYINFO *si)
Definition: patch.c:290
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
LPWSTR transforms
Definition: msipriv.h:191
#define ERROR_SUCCESS
Definition: deptool.c:10
#define MSIDBOPEN_PATCHFILE
Definition: msiquery.h:79
WCHAR * source
Definition: patch.c:667
#define error(str)
Definition: mkdosfs.c:1605
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID
Definition: msipriv.h:81
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:922
WCHAR * prompt
Definition: patch.c:664
WCHAR * product_code_to
Definition: patch.c:50
UINT MSI_ViewModify(MSIQUERY *, MSIMODIFY, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:601
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
MSIOBJECTHDR hdr
Definition: msipriv.h:141
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
WINE_UNICODE_INLINE WCHAR * strchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:248
GLuint GLuint GLsizei count
Definition: gl.h:1545
UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
Definition: database.c:149
uint8_t entry
Definition: isohybrid.c:63
LPWSTR PackagePath
Definition: msipriv.h:425
#define WARN(fmt,...)
Definition: debug.h:111
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:443
static UINT patch_set_media_source_prop(MSIPACKAGE *package)
Definition: patch.c:365
GLintptr offset
Definition: glext.h:5920
WCHAR * name
Definition: patch.c:402
static UINT msi_apply_patch_db(MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch)
Definition: patch.c:871
MSIPATCHSTATE state
Definition: msipriv.h:194
WORD LANGID
Definition: typedefs.h:79
DWORD uninstallable
Definition: msipriv.h:195
#define PID_REVNUMBER
Definition: suminfo.c:51
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
Definition: msipriv.h:80
static BOOL match_language(MSIPACKAGE *package, LANGID langid)
Definition: patch.c:35
UINT msi_apply_transforms(MSIPACKAGE *package)
Definition: patch.c:988
LANGID langid
Definition: msctf.idl:605
UINT sequence
Definition: patch.c:403
static const WCHAR INSTALLPROPERTY_LOCALPACKAGEW[]
Definition: msi.h:343
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1210
static UINT patch_add_media(MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch)
Definition: patch.c:670
static void patch_offset_get_filepatches(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:441
WCHAR * cabinet
Definition: patch.c:665
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
BOOL registered
Definition: msipriv.h:197
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:328
LPWSTR msi_get_suminfo_product(IStorage *stg) DECLSPEC_HIDDEN
Definition: suminfo.c:705
static UINT patch_update_file_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:520
static void patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:479
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:364
#define PID_LASTAUTHOR
Definition: suminfo.c:50
unsigned int BOOL
Definition: ntddk_ex.h:94
static const WCHAR szUpgradeCode[]
Definition: msipriv.h:1170
static void free_transform_desc(struct transform_desc *desc)
Definition: patch.c:56
#define debugstr_w
Definition: kernel32.h:32
#define ERROR_PATCH_PACKAGE_INVALID
Definition: winerror.h:994
#define FIXME(fmt,...)
Definition: debug.h:110
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
const WCHAR * str
const struct builtin_class_descr * desc
Definition: regcontrol.c:48
static const WCHAR patch_media_query[]
Definition: patch.c:653
LPWSTR filename
Definition: msipriv.h:192
smooth NULL
Definition: ftsmooth.c:416
UINT msi_get_suminfo(IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si) DECLSPEC_HIDDEN
Definition: suminfo.c:457
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:482
void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
Definition: appsearch.c:53
LPWSTR products
Definition: msipriv.h:190
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
__u8 media
Definition: mkdosfs.c:367
#define TRACE(s)
Definition: solgame.cpp:4
struct list entry
Definition: patch.c:401
#define ERROR_INSTALL_PACKAGE_INVALID
Definition: winerror.h:978
static const WCHAR szProductCode[]
Definition: msipriv.h:1127
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:77
#define MAX_PATH
Definition: compat.h:26
WCHAR * upgrade_code
Definition: patch.c:53
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIDATABASE * db
Definition: msipriv.h:386
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
MSIOBJECTHDR hdr
Definition: msipriv.h:118
LANGID * langids
Definition: msipriv.h:390
MSIOBJECTHDR hdr
Definition: msipriv.h:463
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:242
static DWORD pi
Definition: protocol.c:150
int ret
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:79
static struct patch_offset_list * patch_offset_list_create(void)
Definition: patch.c:414
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
static UINT check_transform_applicable(MSIPACKAGE *package, IStorage *transform)
Definition: patch.c:121
Definition: _list.h:228
static UINT msi_apply_patch_package(MSIPACKAGE *package, const WCHAR *file)
Definition: patch.c:912
struct list entry
Definition: msipriv.h:188
LPWSTR patchcode
Definition: msipriv.h:189
WCHAR * volume
Definition: patch.c:666
static DWORD is_uninstallable(MSIDATABASE *db)
Definition: patch.c:839
#define strcmpiW(s1, s2)
Definition: unicode.h:39
WINE_UNICODE_INLINE WCHAR * strrchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:254
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:245
#define ERR(fmt,...)
Definition: debug.h:109
UINT disk_id
Definition: patch.c:662
UINT msi_apply_registered_patch(MSIPACKAGE *package, LPCWSTR patch_code)
Definition: patch.c:1029
UINT num_langids
Definition: msipriv.h:389
static unsigned __int64 next
Definition: rand_nt.c:6
WINE_DEFAULT_DEBUG_CHANNEL(msi)
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
WCHAR ** msi_split_string(const WCHAR *str, WCHAR sep)
Definition: action.c:388
static struct transform_desc * parse_transform_desc(const WCHAR *str)
Definition: patch.c:66
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1055
static UINT patch_set_offsets(MSIDATABASE *db, MSIPATCHINFO *patch)
Definition: patch.c:783
#define major(rdev)
Definition: propsheet.cpp:879
WCHAR * version_to
Definition: patch.c:52
UINT msi_apply_patches(MSIPACKAGE *package)
Definition: patch.c:970
#define min(a, b)
Definition: monoChain.cc:55
static UINT apply_substorage_transform(MSIPACKAGE *package, MSIDATABASE *patch_db, LPCWSTR name)
Definition: patch.c:260
unsigned int UINT
Definition: ndis.h:50
UINT offset_to_apply
Definition: patch.c:411
UINT msi_set_property(MSIDATABASE *, const WCHAR *, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: package.c:2149
UINT msi_create_empty_local_file(LPWSTR path, LPCWSTR suffix) DECLSPEC_HIDDEN
Definition: package.c:1143
LPWSTR localfile
Definition: msipriv.h:193
UINT Context
Definition: msipriv.h:437
UINT media_transform_disk_id
Definition: msipriv.h:106
static BOOL msi_free(void *mem)
Definition: msipriv.h:1227
Definition: name.c:36
WINE_UNICODE_INLINE int strcmpW(const WCHAR *str1, const WCHAR *str2)
Definition: unicode.h:229
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1204
static const GUID * guid_list[]
Definition: metadata.c:2260
INT msi_suminfo_get_int32(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:693
UINT msi_add_cabinet_stream(MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name)
Definition: media.c:912
#define minor(rdev)
Definition: propsheet.cpp:880
static IOleDocumentView * view
Definition: activex.c:1749
GLuint GLenum GLenum transform
Definition: glext.h:9407
UINT last_sequence
Definition: patch.c:663
IStorage * storage
Definition: msipriv.h:98
static UINT patch_update_filepatch_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:541
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static const WCHAR szProductVersion[]
Definition: msipriv.h:1186
static const WCHAR szPatch[]
Definition: msipriv.h:1120
static void patch_offset_list_free(struct patch_offset_list *pos)
Definition: patch.c:424
MSIOBJECTHDR hdr
Definition: msipriv.h:97
WCHAR * product_code_from
Definition: patch.c:49
UINT media_transform_offset
Definition: msipriv.h:105
#define SUCCEEDED(hr)
Definition: intsafe.h:57
struct list patches
Definition: msipriv.h:391
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
WINE_UNICODE_INLINE int atoiW(const WCHAR *str)
Definition: unicode.h:315
UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
Definition: msi.c:1681
WCHAR * version_from
Definition: patch.c:51
UINT MSI_DatabaseApplyTransformW(MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond) DECLSPEC_HIDDEN
Definition: msiquery.c:716
static UINT patch_offset_modify_db(MSIDATABASE *db, struct patch_offset_list *pos)
Definition: patch.c:591
Definition: fci.c:126
LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop) DECLSPEC_HIDDEN
Definition: package.c:2370
static UINT patch_file(MSIPACKAGE *package, MSIFILEPATCH *patch)
Definition: files.c:505
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN
Definition: msiquery.c:111