ReactOS  0.4.15-dev-4863-gba0d16f
media.c
Go to the documentation of this file.
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2008 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
25 #include "windef.h"
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "fdi.h"
29 #include "msipriv.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
33 #include "objidl.h"
34 #include "resource.h"
35 
37 
38 /* from msvcrt/fcntl.h */
39 #define _O_RDONLY 0
40 #define _O_WRONLY 1
41 #define _O_RDWR 2
42 #define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
43 #define _O_APPEND 0x0008
44 #define _O_RANDOM 0x0010
45 #define _O_SEQUENTIAL 0x0020
46 #define _O_TEMPORARY 0x0040
47 #define _O_NOINHERIT 0x0080
48 #define _O_CREAT 0x0100
49 #define _O_TRUNC 0x0200
50 #define _O_EXCL 0x0400
51 #define _O_SHORT_LIVED 0x1000
52 #define _O_TEXT 0x4000
53 #define _O_BINARY 0x8000
54 
56 {
58  const WCHAR *p;
59  int len, len2;
60 
61  lstrcpyW(root, source_root);
64 
66  {
67  WARN( "failed to get volume information for %s (%lu)\n", debugstr_w(root), GetLastError() );
68  return FALSE;
69  }
70 
72  len2 = lstrlenW( mi->volume_label );
73  if (len2 > len) return FALSE;
74  p = volume_name + len - len2;
75 
76  return !wcsicmp( mi->volume_label, p );
77 }
78 
80 {
82  LPWSTR source_dir;
83  UINT r = IDRETRY;
84 
85  source_dir = msi_dup_property(package->db, L"SourceDir");
87 
88  while (r == IDRETRY && !source_matches_volume(mi, source_dir))
89  {
92  MSI_RecordSetStringW(record, 2, mi->disk_prompt);
94  }
95 
96  msiobj_release(&record->hdr);
97  msi_free(source_dir);
98 
100 }
101 
103 {
104  MSICABINETSTREAM *cab;
105 
107  {
108  if (cab->disk_id == disk_id) return cab;
109  }
110  return NULL;
111 }
112 
113 static void * CDECL cabinet_alloc(ULONG cb)
114 {
115  return msi_alloc(cb);
116 }
117 
118 static void CDECL cabinet_free(void *pv)
119 {
120  msi_free(pv);
121 }
122 
123 static INT_PTR CDECL cabinet_open(char *pszFile, int oflag, int pmode)
124 {
125  DWORD dwAccess = 0;
126  DWORD dwShareMode = 0;
127  DWORD dwCreateDisposition = OPEN_EXISTING;
128 
129  switch (oflag & _O_ACCMODE)
130  {
131  case _O_RDONLY:
132  dwAccess = GENERIC_READ;
133  dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
134  break;
135  case _O_WRONLY:
136  dwAccess = GENERIC_WRITE;
138  break;
139  case _O_RDWR:
140  dwAccess = GENERIC_READ | GENERIC_WRITE;
142  break;
143  }
144 
145  if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
146  dwCreateDisposition = CREATE_NEW;
147  else if (oflag & _O_CREAT)
148  dwCreateDisposition = CREATE_ALWAYS;
149 
150  return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
151  dwCreateDisposition, 0, NULL);
152 }
153 
154 static UINT CDECL cabinet_read(INT_PTR hf, void *pv, UINT cb)
155 {
156  HANDLE handle = (HANDLE)hf;
157  DWORD read;
158 
159  if (ReadFile(handle, pv, cb, &read, NULL))
160  return read;
161 
162  return 0;
163 }
164 
165 static UINT CDECL cabinet_write(INT_PTR hf, void *pv, UINT cb)
166 {
167  HANDLE handle = (HANDLE)hf;
168  DWORD written;
169 
170  if (WriteFile(handle, pv, cb, &written, NULL))
171  return written;
172 
173  return 0;
174 }
175 
177 {
178  HANDLE handle = (HANDLE)hf;
179  return CloseHandle(handle) ? 0 : -1;
180 }
181 
182 static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
183 {
184  HANDLE handle = (HANDLE)hf;
185  /* flags are compatible and so are passed straight through */
186  return SetFilePointer(handle, dist, NULL, seektype);
187 }
188 
190 {
193 };
194 
196 
197 static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
198 {
199  MSICABINETSTREAM *cab;
200  IStream *stream;
201 
203  {
204  WARN("failed to get cabinet stream\n");
205  return -1;
206  }
207  if (cab->storage == package_disk.package->db->storage)
208  {
210  if (r != ERROR_SUCCESS)
211  {
212  WARN("failed to get stream %u\n", r);
213  return -1;
214  }
215  }
216  else /* patch storage */
217  {
218  HRESULT hr;
219  WCHAR *encoded;
220 
221  if (!(encoded = encode_streamname( FALSE, cab->stream + 1 )))
222  {
223  WARN("failed to encode stream name\n");
224  return -1;
225  }
226  hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
227  msi_free( encoded );
228  if (FAILED(hr))
229  {
230  WARN( "failed to open stream %#lx\n", hr );
231  return -1;
232  }
233  }
234  return (INT_PTR)stream;
235 }
236 
237 static UINT CDECL cabinet_read_stream( INT_PTR hf, void *pv, UINT cb )
238 {
239  IStream *stm = (IStream *)hf;
240  DWORD read;
241  HRESULT hr;
242 
243  hr = IStream_Read( stm, pv, cb, &read );
244  if (hr == S_OK || hr == S_FALSE)
245  return read;
246 
247  return 0;
248 }
249 
251 {
252  IStream *stm = (IStream *)hf;
253  IStream_Release( stm );
254  return 0;
255 }
256 
257 static LONG CDECL cabinet_seek_stream( INT_PTR hf, LONG dist, int seektype )
258 {
259  IStream *stm = (IStream *)hf;
260  LARGE_INTEGER move;
261  ULARGE_INTEGER newpos;
262  HRESULT hr;
263 
264  move.QuadPart = dist;
265  hr = IStream_Seek( stm, move, seektype, &newpos );
266  if (SUCCEEDED(hr))
267  {
268  if (newpos.QuadPart <= MAXLONG) return newpos.QuadPart;
269  ERR("Too big!\n");
270  }
271  return -1;
272 }
273 
275 {
276  MSIRECORD *row;
277 
278  row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `DiskId` = %d", mi->disk_id);
279  if (!row)
280  {
281  TRACE("Unable to query row\n");
282  return ERROR_FUNCTION_FAILED;
283  }
284 
285  mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
286  mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
287  mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
288 
289  msiobj_release(&row->hdr);
290  return ERROR_SUCCESS;
291 }
292 
294  PFDINOTIFICATION pfdin)
295 {
296  MSICABDATA *data = pfdin->pv;
297  data->mi->is_continuous = FALSE;
298  return 0;
299 }
300 
302 {
303  int len;
304  WCHAR *ret;
305 
306  len = lstrlenW(mi->sourcedir) + lstrlenW(mi->cabinet) + 1;
307  if (!(ret = msi_alloc(len * sizeof(WCHAR)))) return NULL;
308  lstrcpyW(ret, mi->sourcedir);
309  lstrcatW(ret, mi->cabinet);
310  return ret;
311 }
312 
314  PFDINOTIFICATION pfdin)
315 {
316  MSICABDATA *data = pfdin->pv;
317  MSIMEDIAINFO *mi = data->mi;
318  LPWSTR cabinet_file = NULL, cab = strdupAtoW(pfdin->psz1);
319  INT_PTR res = -1;
320  UINT rc;
321 
322  msi_free(mi->disk_prompt);
323  msi_free(mi->cabinet);
324  msi_free(mi->volume_label);
325  mi->disk_prompt = NULL;
326  mi->cabinet = NULL;
327  mi->volume_label = NULL;
328 
329  mi->disk_id++;
330  mi->is_continuous = TRUE;
331 
332  rc = msi_media_get_disk_info(data->package, mi);
333  if (rc != ERROR_SUCCESS)
334  {
335  ERR("Failed to get next cabinet information: %d\n", rc);
336  goto done;
337  }
338 
339  if (wcsicmp( mi->cabinet, cab ))
340  {
341  char *next_cab;
342  ULONG length;
343 
344  WARN("Continuous cabinet %s does not match the next cabinet %s in the media table => use latter one\n", debugstr_w(cab), debugstr_w(mi->cabinet));
345 
346  /* Use cabinet name from the media table */
347  next_cab = strdupWtoA(mi->cabinet);
348  /* Modify path to cabinet file with full filename (psz3 points to a 256 bytes buffer that can be modified contrary to psz1 and psz2) */
349  length = strlen(pfdin->psz3) + 1 + strlen(next_cab) + 1;
350  if (length > 256)
351  {
352  WARN( "cannot update next cabinet filename with a string size %lu > 256\n", length );
353  msi_free(next_cab);
354  goto done;
355  }
356  else
357  {
358  strcat(pfdin->psz3, "\\");
359  strcat(pfdin->psz3, next_cab);
360  }
361  /* Path psz3 and cabinet psz1 are concatenated by FDI so just reset psz1 */
362  *pfdin->psz1 = 0;
363  msi_free(next_cab);
364  }
365 
366  if (!(cabinet_file = get_cabinet_filename(mi)))
367  goto done;
368 
369  TRACE("Searching for %s\n", debugstr_w(cabinet_file));
370 
371  res = 0;
372  if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
373  {
374  if (msi_change_media(data->package, mi) != ERROR_SUCCESS)
375  res = -1;
376  }
377 
378 done:
379  msi_free(cab);
380  msi_free(cabinet_file);
381  return res;
382 }
383 
385  PFDINOTIFICATION pfdin )
386 {
387  MSICABDATA *data = pfdin->pv;
388  MSIMEDIAINFO *mi = data->mi;
389  UINT rc;
390 
391  msi_free( mi->disk_prompt );
392  msi_free( mi->cabinet );
393  msi_free( mi->volume_label );
394  mi->disk_prompt = NULL;
395  mi->cabinet = NULL;
396  mi->volume_label = NULL;
397 
398  mi->disk_id++;
399  mi->is_continuous = TRUE;
400 
401  rc = msi_media_get_disk_info( data->package, mi );
402  if (rc != ERROR_SUCCESS)
403  {
404  ERR("Failed to get next cabinet information: %u\n", rc);
405  return -1;
406  }
407  package_disk.id = mi->disk_id;
408 
409  TRACE("next cabinet is %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
410  return 0;
411 }
412 
414  PFDINOTIFICATION pfdin)
415 {
416  MSICABDATA *data = pfdin->pv;
417  HANDLE handle = 0;
418  LPWSTR path = NULL;
419  DWORD attrs;
420 
421  data->curfile = strdupAtoW(pfdin->psz1);
422  if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
423  &attrs, data->user))
424  {
425  /* We're not extracting this file, so free the filename. */
426  msi_free(data->curfile);
427  data->curfile = NULL;
428  goto done;
429  }
430 
431  TRACE("extracting %s -> %s\n", debugstr_w(data->curfile), debugstr_w(path));
432 
434  if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
435 
438  {
439  DWORD err = GetLastError();
440  DWORD attrs2 = msi_get_file_attributes( data->package, path );
441 
442  if (attrs2 == INVALID_FILE_ATTRIBUTES)
443  {
444  ERR( "failed to create %s (error %lu)\n", debugstr_w(path), err );
445  goto done;
446  }
447  else if (err == ERROR_ACCESS_DENIED && (attrs2 & FILE_ATTRIBUTE_READONLY))
448  {
449  TRACE("removing read-only attribute on %s\n", debugstr_w(path));
452 
453  if (handle != INVALID_HANDLE_VALUE) goto done;
454  err = GetLastError();
455  }
457  {
458  WCHAR *tmpfileW, *tmppathW, *p;
459  DWORD len;
460 
461  TRACE("file in use, scheduling rename operation\n");
462 
463  if (!(tmppathW = strdupW( path ))) return ERROR_OUTOFMEMORY;
464  if ((p = wcsrchr(tmppathW, '\\'))) *p = 0;
465  len = lstrlenW( tmppathW ) + 16;
466  if (!(tmpfileW = msi_alloc(len * sizeof(WCHAR))))
467  {
468  msi_free( tmppathW );
469  return ERROR_OUTOFMEMORY;
470  }
471  if (!GetTempFileNameW(tmppathW, L"msi", 0, tmpfileW)) tmpfileW[0] = 0;
472  msi_free( tmppathW );
473 
474  handle = CreateFileW(tmpfileW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs, NULL);
475 
476  if (handle != INVALID_HANDLE_VALUE &&
478  msi_move_file( data->package, tmpfileW, path, MOVEFILE_DELAY_UNTIL_REBOOT ))
479  {
480  data->package->need_reboot_at_end = 1;
481  }
482  else
483  {
484  WARN( "failed to schedule rename operation %s (error %lu)\n", debugstr_w(path), GetLastError() );
485  DeleteFileW( tmpfileW );
486  }
487  msi_free(tmpfileW);
488  }
489  else WARN( "failed to create %s (error %lu)\n", debugstr_w(path), err );
490  }
491 
492 done:
493  msi_free(path);
494 
495  return (INT_PTR)handle;
496 }
497 
499  PFDINOTIFICATION pfdin)
500 {
501  MSICABDATA *data = pfdin->pv;
502  FILETIME ft;
503  FILETIME ftLocal;
504  HANDLE handle = (HANDLE)pfdin->hf;
505 
506  data->mi->is_continuous = FALSE;
507 
508  if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
509  {
511  return -1;
512  }
513  if (!LocalFileTimeToFileTime(&ft, &ftLocal))
514  {
516  return -1;
517  }
518  if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
519  {
521  return -1;
522  }
523 
525  data->cb(data->package, data->curfile, MSICABEXTRACT_FILEEXTRACTED, NULL, NULL, data->user);
526 
527  msi_free(data->curfile);
528  data->curfile = NULL;
529 
530  return 1;
531 }
532 
534 {
535  switch (fdint)
536  {
537  case fdintPARTIAL_FILE:
538  return cabinet_partial_file(fdint, pfdin);
539 
540  case fdintNEXT_CABINET:
541  return cabinet_next_cabinet(fdint, pfdin);
542 
543  case fdintCOPY_FILE:
544  return cabinet_copy_file(fdint, pfdin);
545 
547  return cabinet_close_file_info(fdint, pfdin);
548 
549  default:
550  return 0;
551  }
552 }
553 
555 {
556  switch (fdint)
557  {
558  case fdintPARTIAL_FILE:
559  return cabinet_partial_file( fdint, pfdin );
560 
561  case fdintNEXT_CABINET:
562  return cabinet_next_cabinet_stream( fdint, pfdin );
563 
564  case fdintCOPY_FILE:
565  return cabinet_copy_file( fdint, pfdin );
566 
568  return cabinet_close_file_info( fdint, pfdin );
569 
570  case fdintCABINET_INFO:
571  return 0;
572 
573  default:
574  ERR("Unexpected notification %d\n", fdint);
575  return 0;
576  }
577 }
578 
580 {
581  LPSTR cabinet, cab_path = NULL;
582  HFDI hfdi;
583  ERF erf;
584  BOOL ret = FALSE;
585 
586  TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
587 
590  if (!hfdi)
591  {
592  ERR("FDICreate failed\n");
593  return FALSE;
594  }
595 
596  cabinet = strdupWtoA( mi->cabinet );
597  if (!cabinet)
598  goto done;
599 
600  cab_path = strdupWtoA( mi->sourcedir );
601  if (!cab_path)
602  goto done;
603 
604  ret = FDICopy( hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data );
605  if (!ret)
606  ERR("FDICopy failed\n");
607 
608 done:
609  FDIDestroy( hfdi );
610  msi_free(cabinet );
611  msi_free( cab_path );
612 
613  if (ret)
614  mi->is_extracted = TRUE;
615 
616  return ret;
617 }
618 
620 {
621  static char filename[] = {'<','S','T','R','E','A','M','>',0};
622  HFDI hfdi;
623  ERF erf;
624  BOOL ret = FALSE;
625 
626  TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
627 
630  if (!hfdi)
631  {
632  ERR("FDICreate failed\n");
633  return FALSE;
634  }
635 
637  package_disk.id = mi->disk_id;
638 
640  if (!ret) ERR("FDICopy failed\n");
641 
642  FDIDestroy( hfdi );
643  if (ret) mi->is_extracted = TRUE;
644  return ret;
645 }
646 
647 /***********************************************************************
648  * msi_cabextract
649  *
650  * Extract files from a cabinet file or stream.
651  */
653 {
654  if (mi->cabinet[0] == '#')
655  {
657  }
658  return extract_cabinet( package, mi, data );
659 }
660 
662 {
663  msi_free(mi->disk_prompt);
664  msi_free(mi->cabinet);
665  msi_free(mi->volume_label);
666  msi_free(mi->last_volume);
667  msi_free(mi);
668 }
669 
671 {
672  WCHAR root[MAX_PATH + 1];
673 
674  lstrcpyW(root, path);
677 
678  return GetDriveTypeW(root);
679 }
680 
682 {
683  WCHAR *p, *ret = NULL, *orig_db = msi_dup_property( db, L"OriginalDatabase" );
684  if (UrlIsW( orig_db, URLIS_URL ) && (ret = strdupW( orig_db )) && (p = wcsrchr( ret, '/'))) p[1] = 0;
685  msi_free( orig_db );
686  return ret;
687 }
688 
690 {
691  MSIRECORD *row;
692  WCHAR *source_dir, *source, *base_url = NULL;
693  DWORD options;
694 
695  if (Sequence <= mi->last_sequence) /* already loaded */
696  return ERROR_SUCCESS;
697 
698  row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `LastSequence` >= %d ORDER BY `DiskId`", Sequence);
699  if (!row)
700  {
701  TRACE("Unable to query row\n");
702  return ERROR_FUNCTION_FAILED;
703  }
704 
705  mi->is_extracted = FALSE;
706  mi->disk_id = MSI_RecordGetInteger(row, 1);
707  mi->last_sequence = MSI_RecordGetInteger(row, 2);
708  msi_free(mi->disk_prompt);
709  mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
710  msi_free(mi->cabinet);
711  mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
712  msi_free(mi->volume_label);
713  mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
714  msiobj_release(&row->hdr);
715 
717  source_dir = msi_dup_property(package->db, L"SourceDir");
718  lstrcpyW(mi->sourcedir, source_dir);
719  PathAddBackslashW(mi->sourcedir);
720  mi->type = get_drive_type(source_dir);
721 
723  if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
724  {
725  source = source_dir;
727  }
728  else if ((base_url = get_base_url(package->db)))
729  {
730  source = base_url;
732  }
733  else
734  {
735  source = mi->sourcedir;
737  }
738 
740  MSICODE_PRODUCT, mi->disk_id,
741  mi->volume_label, mi->disk_prompt);
742 
745 
746  TRACE("sequence %u -> cabinet %s disk id %u\n", Sequence, debugstr_w(mi->cabinet), mi->disk_id);
747 
749  msi_free(source_dir);
750  return ERROR_SUCCESS;
751 }
752 
753 /* FIXME: search URL sources as well */
755 {
758  WCHAR prompt[MAX_PATH];
759  DWORD volumesz, promptsz;
760  DWORD index, size, id;
761  WCHAR last_type[2];
762  UINT r;
763 
764  size = 2;
767  INSTALLPROPERTY_LASTUSEDTYPEW, last_type, &size);
768  if (r != ERROR_SUCCESS)
769  return r;
770 
771  size = MAX_PATH;
775  if (r != ERROR_SUCCESS)
776  return r;
777 
778  if (last_type[0] == 'n')
779  {
780  WCHAR cabinet_file[MAX_PATH];
781  BOOL check_all = FALSE;
782 
783  while(TRUE)
784  {
785  index = 0;
786  volumesz = MAX_PATH;
788  package->Context,
790  volume, &volumesz) == ERROR_SUCCESS)
791  {
792  if (check_all || !wcsnicmp(source, volume, lstrlenW(source)))
793  {
794  lstrcpyW(cabinet_file, volume);
795  PathAddBackslashW(cabinet_file);
796  lstrcatW(cabinet_file, mi->cabinet);
797 
798  if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
799  {
800  volumesz = MAX_PATH;
801  if(!check_all)
802  break;
803  continue;
804  }
805 
806  lstrcpyW(mi->sourcedir, volume);
807  PathAddBackslashW(mi->sourcedir);
808  TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
809  return ERROR_SUCCESS;
810  }
811  }
812 
813  if (!check_all)
814  check_all = TRUE;
815  else
816  break;
817  }
818  }
819 
820  index = 0;
821  volumesz = MAX_PATH;
822  promptsz = MAX_PATH;
824  package->Context,
825  MSICODE_PRODUCT, index++, &id,
826  volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS)
827  {
828  mi->disk_id = id;
829  msi_free( mi->volume_label );
830  if (!(mi->volume_label = msi_alloc( ++volumesz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
831  lstrcpyW( mi->volume_label, volume );
832 
833  msi_free( mi->disk_prompt );
834  if (!(mi->disk_prompt = msi_alloc( ++promptsz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
835  lstrcpyW( mi->disk_prompt, prompt );
836 
838  {
839  /* FIXME: what about SourceDir */
840  lstrcpyW(mi->sourcedir, source);
841  PathAddBackslashW(mi->sourcedir);
842  TRACE("Found disk source %s\n", debugstr_w(mi->sourcedir));
843  return ERROR_SUCCESS;
844  }
845  }
846 
847  return ERROR_FUNCTION_FAILED;
848 }
849 
851 {
852  UINT rc;
853  WCHAR *cabinet_file = NULL;
854 
855  /* media info for continuous cabinet is already loaded */
856  if (mi->is_continuous) return ERROR_SUCCESS;
857 
858  if (mi->cabinet)
859  {
860  WCHAR *base_url;
861 
862  /* cabinet is internal, no checks needed */
863  if (mi->cabinet[0] == '#') return ERROR_SUCCESS;
864 
865  if (!(cabinet_file = get_cabinet_filename( mi ))) return ERROR_OUTOFMEMORY;
866 
867  /* package should be downloaded */
868  if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES &&
870  {
871  WCHAR temppath[MAX_PATH], *p, *url;
872 
873  msi_free( cabinet_file );
874  if (!(url = msi_alloc( (lstrlenW( base_url ) + lstrlenW( mi->cabinet ) + 1) * sizeof(WCHAR) )))
875  {
876  return ERROR_OUTOFMEMORY;
877  }
878  lstrcpyW( url, base_url );
879  lstrcatW( url, mi->cabinet );
880  if ((rc = msi_download_file( url, temppath )) != ERROR_SUCCESS)
881  {
882  ERR("failed to download %s (%u)\n", debugstr_w(url), rc);
883  msi_free( url );
884  return rc;
885  }
886  if ((p = wcsrchr( temppath, '\\' ))) *p = 0;
887  lstrcpyW( mi->sourcedir, temppath );
888  PathAddBackslashW( mi->sourcedir );
889  msi_free( mi->cabinet );
890  mi->cabinet = strdupW( p + 1 );
891 
892  msi_free( url );
893  return ERROR_SUCCESS;
894  }
895  }
896  /* check volume matches, change media if not */
897  if (mi->volume_label)
898  {
899  /* assume first volume is in the drive */
900  if (mi->last_volume && wcsicmp( mi->last_volume, mi->volume_label ))
901  {
902  WCHAR *source = msi_dup_property( package->db, L"SourceDir" );
904  msi_free( source );
905 
906  if (!match && (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE))
907  {
908  if ((rc = msi_change_media( package, mi )) != ERROR_SUCCESS)
909  {
910  msi_free( cabinet_file );
911  return rc;
912  }
913  }
914  }
915 
916  msi_free(mi->last_volume);
917  mi->last_volume = strdupW(mi->volume_label);
918  }
919  if (mi->cabinet)
920  {
921  if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES)
922  {
923  if ((rc = find_published_source( package, mi )) != ERROR_SUCCESS)
924  {
925  ERR("cabinet not found: %s\n", debugstr_w(cabinet_file));
926  msi_free( cabinet_file );
927  return ERROR_INSTALL_FAILURE;
928  }
929  }
930  }
931  msi_free( cabinet_file );
932  return ERROR_SUCCESS;
933 }
934 
936 {
937  MSICABINETSTREAM *cab, *item;
938 
939  TRACE("%p, %u, %p, %s\n", package, disk_id, storage, debugstr_w(name));
940 
942  {
943  if (item->disk_id == disk_id)
944  {
945  TRACE("duplicate disk id %u\n", disk_id);
946  return ERROR_FUNCTION_FAILED;
947  }
948  }
949  if (!(cab = msi_alloc( sizeof(*cab) ))) return ERROR_OUTOFMEMORY;
950  if (!(cab->stream = msi_alloc( (lstrlenW( name ) + 1) * sizeof(WCHAR ) )))
951  {
952  msi_free( cab );
953  return ERROR_OUTOFMEMORY;
954  }
955  lstrcpyW( cab->stream, name );
956  cab->disk_id = disk_id;
957  cab->storage = storage;
958  IStorage_AddRef( storage );
960 
961  return ERROR_SUCCESS;
962 }
LPWSTR ProductCode
Definition: msipriv.h:448
static UINT msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:274
#define ERROR_USER_MAPPED_FILE
Definition: winerror.h:727
static INT_PTR CDECL cabinet_open_stream(char *pszFile, int oflag, int pmode)
Definition: media.c:197
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
static INT_PTR CDECL cabinet_notify_stream(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:554
BOOL __cdecl FDIDestroy(HFDI hfdi)
Definition: fdi.c:2831
static BOOL extract_cabinet(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:579
static WCHAR * get_cabinet_filename(MSIMEDIAINFO *mi)
Definition: media.c:301
static WCHAR * get_base_url(MSIDATABASE *db)
Definition: media.c:681
UINT msi_get_stream(MSIDATABASE *, const WCHAR *, IStream **) DECLSPEC_HIDDEN
Definition: streams.c:499
UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi)
Definition: media.c:689
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:597
#define CloseHandle
Definition: compat.h:598
UINT WINAPI MsiSourceListGetInfoW(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szProperty, LPWSTR szValue, LPDWORD pcchValue)
Definition: source.c:523
#define ERROR_SUCCESS
Definition: deptool.c:10
HRESULT hr
Definition: shlfolder.c:183
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:922
#define MAXLONG
Definition: umtypes.h:116
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define TRUE
Definition: types.h:120
Definition: match.c:28
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
static void *CDECL cabinet_alloc(ULONG cb)
Definition: media.c:113
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
UINT WINAPI MsiSourceListEnumMediaDisksW(const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, DWORD *pdwDiskId, WCHAR *szVolumeLabel, DWORD *pcchVolumeLabel, WCHAR *szDiskPrompt, DWORD *pcchDiskPrompt)
Definition: source.c:198
#define WARN(fmt,...)
Definition: debug.h:112
UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
Definition: action.c:354
static int CDECL cabinet_close_stream(INT_PTR hf)
Definition: media.c:250
static LPSTR strdupWtoA(LPCWSTR str)
Definition: hhctrl.h:299
static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:413
static int CDECL cabinet_close(INT_PTR hf)
Definition: media.c:176
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
USHORT time
Definition: fdi.h:236
static MONITORINFO mi
Definition: win.c:7338
static void msi_free(void *mem)
Definition: msipriv.h:1159
MSIPACKAGE * package
Definition: media.c:191
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
static BOOL extract_cabinet_stream(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:619
int32_t INT_PTR
Definition: typedefs.h:64
if(dx==0 &&dy==0)
Definition: linetemp.h:174
char * LPSTR
Definition: xmlstorage.h:182
UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR) DECLSPEC_HIDDEN
Definition: package.c:2569
const char * filename
Definition: ioapi.h:135
UINT ready_media(MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi)
Definition: media.c:850
#define lstrlenW
Definition: compat.h:609
#define FILE_SHARE_READ
Definition: compat.h:136
static const WCHAR INSTALLPROPERTY_LASTUSEDSOURCEW[]
Definition: msi.h:405
#define DRIVE_REMOVABLE
Definition: winbase.h:248
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:948
BOOL WINAPI LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime, OUT LPFILETIME lpFileTime)
Definition: time.c:253
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:313
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define _O_WRONLY
Definition: media.c:40
#define L(x)
Definition: ntvdm.h:50
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:280
BOOL msi_set_file_attributes(MSIPACKAGE *package, const WCHAR *filename, DWORD attrs)
Definition: files.c:97
UINT WINAPI MsiSourceListEnumSourcesW(const WCHAR *szProductCodeOrPatch, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, WCHAR *szSource, DWORD *pcchSource)
Definition: source.c:398
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
IStorage * storage
Definition: msipriv.h:194
#define DRIVE_CDROM
Definition: machpc98.h:115
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define FALSE
Definition: types.h:117
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
Definition: path.c:733
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:294
struct list entry
Definition: msipriv.h:192
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
FDINOTIFICATIONTYPE
Definition: fdi.h:246
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
UINT msi_download_file(LPCWSTR szUrl, LPWSTR filename) DECLSPEC_HIDDEN
Definition: package.c:1027
Definition: fci.h:44
BOOL __cdecl FDICopy(HFDI hfdi, char *pszCabinet, char *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void *pvUser)
Definition: fdi.c:2431
if SUCCEEDED(hr)
#define GENERIC_WRITE
Definition: nt_native.h:90
#define debugstr_w
Definition: kernel32.h:32
INT MSI_ProcessMessage(MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD *) DECLSPEC_HIDDEN
Definition: package.c:1858
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
#define S_FALSE
Definition: winerror.h:2357
char * psz1
Definition: fdi.h:228
#define MOVEFILE_DELAY_UNTIL_REBOOT
Definition: winbase.h:397
HFDI __cdecl FDICreate(PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf)
Definition: fdi.c:412
static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
Definition: media.c:55
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:433
GLuint index
Definition: glext.h:6031
int options
Definition: main.c:106
#define OPEN_EXISTING
Definition: compat.h:634
MSIRECORD *WINAPIV MSI_QueryGetRecord(MSIDATABASE *db, LPCWSTR query,...) DECLSPEC_HIDDEN
Definition: msiquery.c:201
static MSICABINETSTREAM * msi_get_cabinet_stream(MSIPACKAGE *package, UINT disk_id)
Definition: media.c:102
#define STGM_READ
Definition: objbase.h:916
#define _O_EXCL
Definition: media.c:50
static INT_PTR cabinet_close_file_info(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:498
HANDLE msi_create_file(MSIPACKAGE *package, const WCHAR *filename, DWORD access, DWORD sharing, DWORD creation, DWORD flags)
Definition: files.c:51
#define _O_RDWR
Definition: media.c:41
#define TRACE(s)
Definition: solgame.cpp:4
#define MSICABEXTRACT_FILEEXTRACTED
Definition: msipriv.h:1096
GLsizeiptr size
Definition: glext.h:5919
char * psz3
Definition: fdi.h:230
BOOL msi_move_file(MSIPACKAGE *package, const WCHAR *from, const WCHAR *to, DWORD flags)
Definition: files.c:133
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
LONG HRESULT
Definition: typedefs.h:79
static INT_PTR CDECL cabinet_open(char *pszFile, int oflag, int pmode)
Definition: media.c:123
double __cdecl erf(double)
static const WCHAR url[]
Definition: encode.c:1432
LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN
Definition: table.c:119
static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
Definition: media.c:182
#define ERROR_INSTALL_FAILURE
Definition: winerror.h:961
#define MAX_PATH
Definition: compat.h:34
static UINT CDECL cabinet_read_stream(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:237
UINT WINAPI GetTempFileNameW(IN LPCWSTR lpPathName, IN LPCWSTR lpPrefixString, IN UINT uUnique, OUT LPWSTR lpTempFileName)
Definition: filename.c:84
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
static INT_PTR cabinet_partial_file(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:293
UINT id
Definition: media.c:192
PVOID HANDLE
Definition: typedefs.h:73
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIDATABASE * db
Definition: msipriv.h:394
#define _O_CREAT
Definition: media.c:48
static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:754
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
#define IDRETRY
Definition: winuser.h:827
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
#define wcsicmp
Definition: compat.h:15
int ret
#define wcsnicmp
Definition: compat.h:14
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:76
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define index(s, c)
Definition: various.h:29
USHORT date
Definition: fdi.h:235
Definition: parse.h:22
DWORD msi_get_file_attributes(MSIPACKAGE *package, const WCHAR *path)
Definition: files.c:106
static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:79
GLuint GLuint stream
Definition: glext.h:7522
uint32_t entry
Definition: isohybrid.c:63
static const WCHAR INSTALLPROPERTY_LASTUSEDTYPEW[]
Definition: msi.h:409
GLenum GLsizei len
Definition: glext.h:6722
INT_PTR hf
Definition: fdi.h:233
#define GENERIC_READ
Definition: compat.h:135
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:135
UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR) DECLSPEC_HIDDEN
Definition: package.c:2592
#define err(...)
#define wcsrchr
Definition: compat.h:16
BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis)
Definition: url.c:1933
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi)
struct list cabinet_streams
Definition: msipriv.h:408
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:213
#define ERR(fmt,...)
Definition: debug.h:110
BOOL WINAPI GetVolumeInformationW(IN LPCWSTR lpRootPathName, IN LPWSTR lpVolumeNameBuffer, IN DWORD nVolumeNameSize, OUT LPDWORD lpVolumeSerialNumber OPTIONAL, OUT LPDWORD lpMaximumComponentLength OPTIONAL, OUT LPDWORD lpFileSystemFlags OPTIONAL, OUT LPWSTR lpFileSystemNameBuffer OPTIONAL, IN DWORD nFileSystemNameSize)
Definition: volume.c:226
static char volume_name[]
Definition: mkdosfs.c:526
#define S_OK
Definition: intsafe.h:52
#define CREATE_ALWAYS
Definition: disk.h:72
static ATOM item
Definition: dde.c:856
#define lstrcpyW
Definition: compat.h:608
#define CDECL
Definition: compat.h:29
GLsizei GLsizei GLchar * source
Definition: glext.h:6048
const char * base_url
Definition: mimeole.c:1466
#define ReadFile(a, b, c, d, e)
Definition: compat.h:601
#define MSICABEXTRACT_BEGINEXTRACT
Definition: msipriv.h:1095
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
void * pv
Definition: fdi.h:231
#define _O_RDONLY
Definition: media.c:39
static LONG CDECL cabinet_seek_stream(INT_PTR hf, LONG dist, int seektype)
Definition: media.c:257
UINT Context
Definition: msipriv.h:459
#define CreateFileW
Definition: compat.h:600
static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:533
static HMODULE MODULEINFO DWORD cb
Definition: module.c:32
BOOL msi_cabextract(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:652
#define ERROR_INSTALL_SOURCE_ABSENT
Definition: winerror.h:970
Definition: name.c:38
static UINT CDECL cabinet_read(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:154
GLuint res
Definition: glext.h:9613
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1142
unsigned int ULONG
Definition: retypes.h:1
GLenum GLuint id
Definition: glext.h:5579
UINT msi_add_cabinet_stream(MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name)
Definition: media.c:935
#define MB_RETRYCANCEL
Definition: winuser.h:799
static UINT CDECL cabinet_write(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:165
static INT_PTR cabinet_next_cabinet_stream(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:384
static UINT get_drive_type(const WCHAR *path)
Definition: media.c:670
#define CREATE_NEW
Definition: disk.h:69
IStorage * storage
Definition: msipriv.h:109
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
void msi_free_media_info(MSIMEDIAINFO *mi)
Definition: media.c:661
static void CDECL cabinet_free(void *pv)
Definition: media.c:118
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:599
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define _O_ACCMODE
Definition: media.c:42
#define MSIERR_CABNOTFOUND
Definition: resource.h:31
static WCHAR * strdupAtoW(const char *str)
Definition: main.c:65
#define SetFilePointer
Definition: compat.h:602
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
LONGLONG QuadPart
Definition: typedefs.h:114
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop) DECLSPEC_HIDDEN
Definition: package.c:2227