ReactOS  0.4.14-dev-49-gfb4591c
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 "wine/unicode.h"
35 #include "resource.h"
36 
38 
39 /* from msvcrt/fcntl.h */
40 #define _O_RDONLY 0
41 #define _O_WRONLY 1
42 #define _O_RDWR 2
43 #define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
44 #define _O_APPEND 0x0008
45 #define _O_RANDOM 0x0010
46 #define _O_SEQUENTIAL 0x0020
47 #define _O_TEMPORARY 0x0040
48 #define _O_NOINHERIT 0x0080
49 #define _O_CREAT 0x0100
50 #define _O_TRUNC 0x0200
51 #define _O_EXCL 0x0400
52 #define _O_SHORT_LIVED 0x1000
53 #define _O_TEXT 0x4000
54 #define _O_BINARY 0x8000
55 
57 {
59  const WCHAR *p;
60  int len, len2;
61 
62  strcpyW(root, source_root);
65 
67  {
68  WARN("failed to get volume information for %s (%u)\n", debugstr_w(root), GetLastError());
69  return FALSE;
70  }
71 
72  len = strlenW( volume_name );
73  len2 = strlenW( mi->volume_label );
74  if (len2 > len) return FALSE;
75  p = volume_name + len - len2;
76 
77  return !strcmpiW( mi->volume_label, p );
78 }
79 
81 {
83  LPWSTR source_dir;
84  UINT r = IDRETRY;
85 
86  source_dir = msi_dup_property(package->db, szSourceDir);
88 
89  while (r == IDRETRY && !source_matches_volume(mi, source_dir))
90  {
93  MSI_RecordSetStringW(record, 2, mi->disk_prompt);
95  }
96 
97  msiobj_release(&record->hdr);
98  msi_free(source_dir);
99 
100  return r;
101 }
102 
104 {
105  MSICABINETSTREAM *cab;
106 
108  {
109  if (cab->disk_id == disk_id) return cab;
110  }
111  return NULL;
112 }
113 
114 static void * CDECL cabinet_alloc(ULONG cb)
115 {
116  return msi_alloc(cb);
117 }
118 
119 static void CDECL cabinet_free(void *pv)
120 {
121  msi_free(pv);
122 }
123 
124 static INT_PTR CDECL cabinet_open(char *pszFile, int oflag, int pmode)
125 {
126  DWORD dwAccess = 0;
127  DWORD dwShareMode = 0;
128  DWORD dwCreateDisposition = OPEN_EXISTING;
129 
130  switch (oflag & _O_ACCMODE)
131  {
132  case _O_RDONLY:
133  dwAccess = GENERIC_READ;
134  dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
135  break;
136  case _O_WRONLY:
137  dwAccess = GENERIC_WRITE;
139  break;
140  case _O_RDWR:
141  dwAccess = GENERIC_READ | GENERIC_WRITE;
143  break;
144  }
145 
146  if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
147  dwCreateDisposition = CREATE_NEW;
148  else if (oflag & _O_CREAT)
149  dwCreateDisposition = CREATE_ALWAYS;
150 
151  return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
152  dwCreateDisposition, 0, NULL);
153 }
154 
155 static UINT CDECL cabinet_read(INT_PTR hf, void *pv, UINT cb)
156 {
157  HANDLE handle = (HANDLE)hf;
158  DWORD read;
159 
160  if (ReadFile(handle, pv, cb, &read, NULL))
161  return read;
162 
163  return 0;
164 }
165 
166 static UINT CDECL cabinet_write(INT_PTR hf, void *pv, UINT cb)
167 {
168  HANDLE handle = (HANDLE)hf;
169  DWORD written;
170 
171  if (WriteFile(handle, pv, cb, &written, NULL))
172  return written;
173 
174  return 0;
175 }
176 
178 {
179  HANDLE handle = (HANDLE)hf;
180  return CloseHandle(handle) ? 0 : -1;
181 }
182 
183 static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
184 {
185  HANDLE handle = (HANDLE)hf;
186  /* flags are compatible and so are passed straight through */
187  return SetFilePointer(handle, dist, NULL, seektype);
188 }
189 
191 {
194 };
195 
197 
198 static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
199 {
200  MSICABINETSTREAM *cab;
201  IStream *stream;
202 
204  {
205  WARN("failed to get cabinet stream\n");
206  return -1;
207  }
208  if (cab->storage == package_disk.package->db->storage)
209  {
211  if (r != ERROR_SUCCESS)
212  {
213  WARN("failed to get stream %u\n", r);
214  return -1;
215  }
216  }
217  else /* patch storage */
218  {
219  HRESULT hr;
220  WCHAR *encoded;
221 
222  if (!(encoded = encode_streamname( FALSE, cab->stream + 1 )))
223  {
224  WARN("failed to encode stream name\n");
225  return -1;
226  }
227  hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
228  msi_free( encoded );
229  if (FAILED(hr))
230  {
231  WARN("failed to open stream 0x%08x\n", hr);
232  return -1;
233  }
234  }
235  return (INT_PTR)stream;
236 }
237 
238 static UINT CDECL cabinet_read_stream( INT_PTR hf, void *pv, UINT cb )
239 {
240  IStream *stm = (IStream *)hf;
241  DWORD read;
242  HRESULT hr;
243 
244  hr = IStream_Read( stm, pv, cb, &read );
245  if (hr == S_OK || hr == S_FALSE)
246  return read;
247 
248  return 0;
249 }
250 
252 {
253  IStream *stm = (IStream *)hf;
254  IStream_Release( stm );
255  return 0;
256 }
257 
258 static LONG CDECL cabinet_seek_stream( INT_PTR hf, LONG dist, int seektype )
259 {
260  IStream *stm = (IStream *)hf;
261  LARGE_INTEGER move;
262  ULARGE_INTEGER newpos;
263  HRESULT hr;
264 
265  move.QuadPart = dist;
266  hr = IStream_Seek( stm, move, seektype, &newpos );
267  if (SUCCEEDED(hr))
268  {
269  if (newpos.QuadPart <= MAXLONG) return newpos.QuadPart;
270  ERR("Too big!\n");
271  }
272  return -1;
273 }
274 
276 {
277  MSIRECORD *row;
278 
279  static const WCHAR query[] = {
280  'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
281  '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
282  '`','D','i','s','k','I','d','`',' ','=',' ','%','i',0};
283 
284  row = MSI_QueryGetRecord(package->db, query, mi->disk_id);
285  if (!row)
286  {
287  TRACE("Unable to query row\n");
288  return ERROR_FUNCTION_FAILED;
289  }
290 
291  mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
292  mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
293  mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
294 
295  msiobj_release(&row->hdr);
296  return ERROR_SUCCESS;
297 }
298 
300  PFDINOTIFICATION pfdin)
301 {
302  MSICABDATA *data = pfdin->pv;
303  data->mi->is_continuous = FALSE;
304  return 0;
305 }
306 
308 {
309  int len;
310  WCHAR *ret;
311 
312  len = strlenW(mi->sourcedir) + strlenW(mi->cabinet) + 1;
313  if (!(ret = msi_alloc(len * sizeof(WCHAR)))) return NULL;
314  strcpyW(ret, mi->sourcedir);
315  strcatW(ret, mi->cabinet);
316  return ret;
317 }
318 
320  PFDINOTIFICATION pfdin)
321 {
322  MSICABDATA *data = pfdin->pv;
323  MSIMEDIAINFO *mi = data->mi;
324  LPWSTR cabinet_file = NULL, cab = strdupAtoW(pfdin->psz1);
325  INT_PTR res = -1;
326  UINT rc;
327 
328  msi_free(mi->disk_prompt);
329  msi_free(mi->cabinet);
330  msi_free(mi->volume_label);
331  mi->disk_prompt = NULL;
332  mi->cabinet = NULL;
333  mi->volume_label = NULL;
334 
335  mi->disk_id++;
336  mi->is_continuous = TRUE;
337 
338  rc = msi_media_get_disk_info(data->package, mi);
339  if (rc != ERROR_SUCCESS)
340  {
341  ERR("Failed to get next cabinet information: %d\n", rc);
342  goto done;
343  }
344 
345  if (strcmpiW( mi->cabinet, cab ))
346  {
347  char *next_cab;
348  ULONG length;
349 
350  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));
351 
352  /* Use cabinet name from the media table */
353  next_cab = strdupWtoA(mi->cabinet);
354  /* Modify path to cabinet file with full filename (psz3 points to a 256 bytes buffer that can be modified contrary to psz1 and psz2) */
355  length = strlen(pfdin->psz3) + 1 + strlen(next_cab) + 1;
356  if (length > 256)
357  {
358  WARN("Cannot update next cabinet filename with a string size %u > 256\n", length);
359  msi_free(next_cab);
360  goto done;
361  }
362  else
363  {
364  strcat(pfdin->psz3, "\\");
365  strcat(pfdin->psz3, next_cab);
366  }
367  /* Path psz3 and cabinet psz1 are concatenated by FDI so just reset psz1 */
368  *pfdin->psz1 = 0;
369  msi_free(next_cab);
370  }
371 
372  if (!(cabinet_file = get_cabinet_filename(mi)))
373  goto done;
374 
375  TRACE("Searching for %s\n", debugstr_w(cabinet_file));
376 
377  res = 0;
378  if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
379  {
380  if (msi_change_media(data->package, mi) != ERROR_SUCCESS)
381  res = -1;
382  }
383 
384 done:
385  msi_free(cab);
386  msi_free(cabinet_file);
387  return res;
388 }
389 
391  PFDINOTIFICATION pfdin )
392 {
393  MSICABDATA *data = pfdin->pv;
394  MSIMEDIAINFO *mi = data->mi;
395  UINT rc;
396 
397  msi_free( mi->disk_prompt );
398  msi_free( mi->cabinet );
399  msi_free( mi->volume_label );
400  mi->disk_prompt = NULL;
401  mi->cabinet = NULL;
402  mi->volume_label = NULL;
403 
404  mi->disk_id++;
405  mi->is_continuous = TRUE;
406 
407  rc = msi_media_get_disk_info( data->package, mi );
408  if (rc != ERROR_SUCCESS)
409  {
410  ERR("Failed to get next cabinet information: %u\n", rc);
411  return -1;
412  }
413  package_disk.id = mi->disk_id;
414 
415  TRACE("next cabinet is %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
416  return 0;
417 }
418 
420  PFDINOTIFICATION pfdin)
421 {
422  MSICABDATA *data = pfdin->pv;
423  HANDLE handle = 0;
424  LPWSTR path = NULL;
425  DWORD attrs;
426 
427  data->curfile = strdupAtoW(pfdin->psz1);
428  if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
429  &attrs, data->user))
430  {
431  /* We're not extracting this file, so free the filename. */
432  msi_free(data->curfile);
433  data->curfile = NULL;
434  goto done;
435  }
436 
437  TRACE("extracting %s -> %s\n", debugstr_w(data->curfile), debugstr_w(path));
438 
440  if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
441 
443  NULL, CREATE_ALWAYS, attrs, NULL);
445  {
446  DWORD err = GetLastError();
447  DWORD attrs2 = GetFileAttributesW(path);
448 
449  if (attrs2 == INVALID_FILE_ATTRIBUTES)
450  {
451  ERR("failed to create %s (error %d)\n", debugstr_w(path), err);
452  goto done;
453  }
454  else if (err == ERROR_ACCESS_DENIED && (attrs2 & FILE_ATTRIBUTE_READONLY))
455  {
456  TRACE("removing read-only attribute on %s\n", debugstr_w(path));
459 
460  if (handle != INVALID_HANDLE_VALUE) goto done;
461  err = GetLastError();
462  }
464  {
465  WCHAR *tmpfileW, *tmppathW, *p;
466  DWORD len;
467 
468  TRACE("file in use, scheduling rename operation\n");
469 
470  if (!(tmppathW = strdupW( path ))) return ERROR_OUTOFMEMORY;
471  if ((p = strrchrW(tmppathW, '\\'))) *p = 0;
472  len = strlenW( tmppathW ) + 16;
473  if (!(tmpfileW = msi_alloc(len * sizeof(WCHAR))))
474  {
475  msi_free( tmppathW );
476  return ERROR_OUTOFMEMORY;
477  }
478  if (!GetTempFileNameW(tmppathW, szMsi, 0, tmpfileW)) tmpfileW[0] = 0;
479  msi_free( tmppathW );
480 
481  handle = CreateFileW(tmpfileW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs, NULL);
482 
483  if (handle != INVALID_HANDLE_VALUE &&
486  {
487  data->package->need_reboot_at_end = 1;
488  }
489  else
490  {
491  WARN("failed to schedule rename operation %s (error %d)\n", debugstr_w(path), GetLastError());
492  DeleteFileW( tmpfileW );
493  }
494  msi_free(tmpfileW);
495  }
496  else
497  WARN("failed to create %s (error %d)\n", debugstr_w(path), err);
498  }
499 
500 done:
501  msi_free(path);
502 
503  return (INT_PTR)handle;
504 }
505 
507  PFDINOTIFICATION pfdin)
508 {
509  MSICABDATA *data = pfdin->pv;
510  FILETIME ft;
511  FILETIME ftLocal;
512  HANDLE handle = (HANDLE)pfdin->hf;
513 
514  data->mi->is_continuous = FALSE;
515 
516  if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
517  return -1;
518  if (!LocalFileTimeToFileTime(&ft, &ftLocal))
519  return -1;
520  if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
521  return -1;
522 
524 
525  data->cb(data->package, data->curfile, MSICABEXTRACT_FILEEXTRACTED, NULL, NULL,
526  data->user);
527 
528  msi_free(data->curfile);
529  data->curfile = NULL;
530 
531  return 1;
532 }
533 
535 {
536  switch (fdint)
537  {
538  case fdintPARTIAL_FILE:
539  return cabinet_partial_file(fdint, pfdin);
540 
541  case fdintNEXT_CABINET:
542  return cabinet_next_cabinet(fdint, pfdin);
543 
544  case fdintCOPY_FILE:
545  return cabinet_copy_file(fdint, pfdin);
546 
548  return cabinet_close_file_info(fdint, pfdin);
549 
550  default:
551  return 0;
552  }
553 }
554 
556 {
557  switch (fdint)
558  {
559  case fdintPARTIAL_FILE:
560  return cabinet_partial_file( fdint, pfdin );
561 
562  case fdintNEXT_CABINET:
563  return cabinet_next_cabinet_stream( fdint, pfdin );
564 
565  case fdintCOPY_FILE:
566  return cabinet_copy_file( fdint, pfdin );
567 
569  return cabinet_close_file_info( fdint, pfdin );
570 
571  case fdintCABINET_INFO:
572  return 0;
573 
574  default:
575  ERR("Unexpected notification %d\n", fdint);
576  return 0;
577  }
578 }
579 
581 {
582  LPSTR cabinet, cab_path = NULL;
583  HFDI hfdi;
584  ERF erf;
585  BOOL ret = FALSE;
586 
587  TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
588 
591  if (!hfdi)
592  {
593  ERR("FDICreate failed\n");
594  return FALSE;
595  }
596 
597  cabinet = strdupWtoA( mi->cabinet );
598  if (!cabinet)
599  goto done;
600 
601  cab_path = strdupWtoA( mi->sourcedir );
602  if (!cab_path)
603  goto done;
604 
605  ret = FDICopy( hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data );
606  if (!ret)
607  ERR("FDICopy failed\n");
608 
609 done:
610  FDIDestroy( hfdi );
611  msi_free(cabinet );
612  msi_free( cab_path );
613 
614  if (ret)
615  mi->is_extracted = TRUE;
616 
617  return ret;
618 }
619 
621 {
622  static char filename[] = {'<','S','T','R','E','A','M','>',0};
623  HFDI hfdi;
624  ERF erf;
625  BOOL ret = FALSE;
626 
627  TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
628 
631  if (!hfdi)
632  {
633  ERR("FDICreate failed\n");
634  return FALSE;
635  }
636 
638  package_disk.id = mi->disk_id;
639 
641  if (!ret) ERR("FDICopy failed\n");
642 
643  FDIDestroy( hfdi );
644  if (ret) mi->is_extracted = TRUE;
645  return ret;
646 }
647 
648 /***********************************************************************
649  * msi_cabextract
650  *
651  * Extract files from a cabinet file or stream.
652  */
654 {
655  if (mi->cabinet[0] == '#')
656  {
658  }
659  return extract_cabinet( package, mi, data );
660 }
661 
663 {
664  msi_free(mi->disk_prompt);
665  msi_free(mi->cabinet);
666  msi_free(mi->volume_label);
667  msi_free(mi);
668 }
669 
671 {
672  WCHAR root[MAX_PATH + 1];
673 
674  strcpyW(root, path);
677 
678  return GetDriveTypeW(root);
679 }
680 
682 {
683  static const WCHAR query[] = {
684  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
685  'W','H','E','R','E',' ','`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
686  '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
687  MSIRECORD *row;
688  LPWSTR source_dir, source;
689  DWORD options;
690 
691  if (Sequence <= mi->last_sequence) /* already loaded */
692  return ERROR_SUCCESS;
693 
694  row = MSI_QueryGetRecord(package->db, query, Sequence);
695  if (!row)
696  {
697  TRACE("Unable to query row\n");
698  return ERROR_FUNCTION_FAILED;
699  }
700 
701  mi->is_extracted = FALSE;
702  mi->disk_id = MSI_RecordGetInteger(row, 1);
703  mi->last_sequence = MSI_RecordGetInteger(row, 2);
704  msi_free(mi->disk_prompt);
705  mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
706  msi_free(mi->cabinet);
707  mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
708  msi_free(mi->volume_label);
709  mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
710  msiobj_release(&row->hdr);
711 
713  source_dir = msi_dup_property(package->db, szSourceDir);
714  lstrcpyW(mi->sourcedir, source_dir);
715  PathAddBackslashW(mi->sourcedir);
716  mi->type = get_drive_type(source_dir);
717 
719  if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
720  {
721  source = source_dir;
723  }
724  else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
725  {
728  }
729  else
730  {
731  source = mi->sourcedir;
733  }
734 
736  MSICODE_PRODUCT, mi->disk_id,
737  mi->volume_label, mi->disk_prompt);
738 
741 
742  msi_free(source_dir);
743  TRACE("sequence %u -> cabinet %s disk id %u\n", Sequence, debugstr_w(mi->cabinet), mi->disk_id);
744  return ERROR_SUCCESS;
745 }
746 
747 /* FIXME: search URL sources as well */
749 {
752  WCHAR prompt[MAX_PATH];
753  DWORD volumesz, promptsz;
754  DWORD index, size, id;
755  WCHAR last_type[2];
756  UINT r;
757 
758  size = 2;
761  INSTALLPROPERTY_LASTUSEDTYPEW, last_type, &size);
762  if (r != ERROR_SUCCESS)
763  return r;
764 
765  size = MAX_PATH;
769  if (r != ERROR_SUCCESS)
770  return r;
771 
772  if (last_type[0] == 'n')
773  {
774  WCHAR cabinet_file[MAX_PATH];
775  BOOL check_all = FALSE;
776 
777  while(TRUE)
778  {
779  index = 0;
780  volumesz = MAX_PATH;
782  package->Context,
784  volume, &volumesz) == ERROR_SUCCESS)
785  {
786  if (check_all || !strncmpiW(source, volume, strlenW(source)))
787  {
788  lstrcpyW(cabinet_file, volume);
789  PathAddBackslashW(cabinet_file);
790  lstrcatW(cabinet_file, mi->cabinet);
791 
792  if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
793  {
794  volumesz = MAX_PATH;
795  if(!check_all)
796  break;
797  continue;
798  }
799 
800  lstrcpyW(mi->sourcedir, volume);
801  PathAddBackslashW(mi->sourcedir);
802  TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
803  return ERROR_SUCCESS;
804  }
805  }
806 
807  if (!check_all)
808  check_all = TRUE;
809  else
810  break;
811  }
812  }
813 
814  index = 0;
815  volumesz = MAX_PATH;
816  promptsz = MAX_PATH;
818  package->Context,
819  MSICODE_PRODUCT, index++, &id,
820  volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS)
821  {
822  mi->disk_id = id;
823  msi_free( mi->volume_label );
824  if (!(mi->volume_label = msi_alloc( ++volumesz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
825  strcpyW( mi->volume_label, volume );
826 
827  msi_free( mi->disk_prompt );
828  if (!(mi->disk_prompt = msi_alloc( ++promptsz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
829  strcpyW( mi->disk_prompt, prompt );
830 
832  {
833  /* FIXME: what about SourceDir */
834  lstrcpyW(mi->sourcedir, source);
835  PathAddBackslashW(mi->sourcedir);
836  TRACE("Found disk source %s\n", debugstr_w(mi->sourcedir));
837  return ERROR_SUCCESS;
838  }
839  }
840 
841  return ERROR_FUNCTION_FAILED;
842 }
843 
845 {
846  UINT rc;
847  WCHAR *cabinet_file = NULL;
848 
849  /* media info for continuous cabinet is already loaded */
850  if (mi->is_continuous) return ERROR_SUCCESS;
851 
852  if (mi->cabinet)
853  {
854  /* cabinet is internal, no checks needed */
855  if (mi->cabinet[0] == '#') return ERROR_SUCCESS;
856 
857  if (!(cabinet_file = get_cabinet_filename( mi ))) return ERROR_OUTOFMEMORY;
858 
859  /* package should be downloaded */
860  if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES &&
862  {
863  WCHAR temppath[MAX_PATH], *p;
864 
865  if ((rc = msi_download_file( cabinet_file, temppath )) != ERROR_SUCCESS)
866  {
867  ERR("failed to download %s (%u)\n", debugstr_w(cabinet_file), rc);
868  msi_free( cabinet_file );
869  return rc;
870  }
871  if ((p = strrchrW( temppath, '\\' ))) *p = 0;
872  strcpyW( mi->sourcedir, temppath );
873  PathAddBackslashW( mi->sourcedir );
874  msi_free( mi->cabinet );
875  mi->cabinet = strdupW( p + 1 );
876  msi_free( cabinet_file );
877  return ERROR_SUCCESS;
878  }
879  }
880  /* check volume matches, change media if not */
881  if (mi->volume_label && mi->disk_id > 1)
882  {
885  msi_free( source );
886 
887  if (!match && (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE))
888  {
889  if ((rc = msi_change_media( package, mi )) != ERROR_SUCCESS)
890  {
891  msi_free( cabinet_file );
892  return rc;
893  }
894  }
895  }
896  if (mi->cabinet)
897  {
898  if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES)
899  {
900  if ((rc = find_published_source( package, mi )) != ERROR_SUCCESS)
901  {
902  ERR("cabinet not found: %s\n", debugstr_w(cabinet_file));
903  msi_free( cabinet_file );
904  return ERROR_INSTALL_FAILURE;
905  }
906  }
907  }
908  msi_free( cabinet_file );
909  return ERROR_SUCCESS;
910 }
911 
913 {
914  MSICABINETSTREAM *cab, *item;
915 
916  TRACE("%p, %u, %p, %s\n", package, disk_id, storage, debugstr_w(name));
917 
919  {
920  if (item->disk_id == disk_id)
921  {
922  TRACE("duplicate disk id %u\n", disk_id);
923  return ERROR_FUNCTION_FAILED;
924  }
925  }
926  if (!(cab = msi_alloc( sizeof(*cab) ))) return ERROR_OUTOFMEMORY;
927  if (!(cab->stream = msi_alloc( (strlenW( name ) + 1) * sizeof(WCHAR ) )))
928  {
929  msi_free( cab );
930  return ERROR_OUTOFMEMORY;
931  }
932  strcpyW( cab->stream, name );
933  cab->disk_id = disk_id;
934  cab->storage = storage;
935  IStorage_AddRef( storage );
937 
938  return ERROR_SUCCESS;
939 }
BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:944
LPWSTR ProductCode
Definition: msipriv.h:426
#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:198
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:555
BOOL __cdecl FDIDestroy(HFDI hfdi)
Definition: fdi.c:2831
static BOOL extract_cabinet(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:580
static WCHAR * get_cabinet_filename(MSIMEDIAINFO *mi)
Definition: media.c:307
UINT msi_get_stream(MSIDATABASE *, const WCHAR *, IStream **) DECLSPEC_HIDDEN
Definition: streams.c:518
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define TRUE
Definition: types.h:120
UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi)
Definition: media.c:681
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:649
#define CloseHandle
Definition: compat.h:398
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
UINT WINAPI MsiSourceListGetInfoW(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szProperty, LPWSTR szValue, LPDWORD pcchValue)
Definition: source.c:538
#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
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:114
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define WARN(fmt,...)
Definition: debug.h:111
UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
Definition: action.c:441
static int CDECL cabinet_close_stream(INT_PTR hf)
Definition: media.c:251
static LPSTR strdupWtoA(LPCWSTR str)
Definition: hhctrl.h:296
static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:419
static int CDECL cabinet_close(INT_PTR hf)
Definition: media.c:177
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
USHORT time
Definition: fdi.h:236
static MONITORINFO mi
Definition: win.c:7331
MSIPACKAGE * package
Definition: media.c:192
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
static BOOL extract_cabinet_stream(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:620
#define strncmpiW(s1, s2, n)
Definition: unicode.h:40
int32_t INT_PTR
Definition: typedefs.h:62
UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId, LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel, LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt)
Definition: source.c:206
char * LPSTR
Definition: xmlstorage.h:182
UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR) DECLSPEC_HIDDEN
Definition: package.c:2800
const char * filename
Definition: ioapi.h:135
UINT ready_media(MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi)
Definition: media.c:844
#define FILE_SHARE_READ
Definition: compat.h:125
static const WCHAR INSTALLPROPERTY_LASTUSEDSOURCEW[]
Definition: msi.h:405
#define DRIVE_REMOVABLE
Definition: winbase.h:248
DWORD WINAPI DECLSPEC_HOTPATCH SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
Definition: fileinfo.c:204
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1098
BOOL WINAPI LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime, OUT LPFILETIME lpFileTime)
Definition: time.c:243
__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:319
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define _O_WRONLY
Definition: media.c:41
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:328
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
IStorage * storage
Definition: msipriv.h:182
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
Definition: path.c:728
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:289
struct list entry
Definition: msipriv.h:180
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:802
UINT msi_download_file(LPCWSTR szUrl, LPWSTR filename) DECLSPEC_HIDDEN
Definition: package.c:1107
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
#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:1946
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
#define S_FALSE
Definition: winerror.h:2357
smooth NULL
Definition: ftsmooth.c:416
char * psz1
Definition: fdi.h:228
#define MOVEFILE_DELAY_UNTIL_REBOOT
Definition: winbase.h:381
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:56
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:482
GLuint index
Definition: glext.h:6031
int options
Definition: main.c:106
#define OPEN_EXISTING
Definition: compat.h:426
UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, LPWSTR szSource, LPDWORD pcchSource)
Definition: source.c:411
static MSICABINETSTREAM * msi_get_cabinet_stream(MSIPACKAGE *package, UINT disk_id)
Definition: media.c:103
#define STGM_READ
Definition: objbase.h:916
#define _O_EXCL
Definition: media.c:51
static INT_PTR cabinet_close_file_info(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:506
#define _O_RDWR
Definition: media.c:42
#define TRACE(s)
Definition: solgame.cpp:4
#define MSICABEXTRACT_FILEEXTRACTED
Definition: msipriv.h:1055
GLsizeiptr size
Definition: glext.h:5919
char * psz3
Definition: fdi.h:230
if(!(yy_init))
Definition: macro.lex.yy.c:714
__wchar_t WCHAR
Definition: xmlstorage.h:180
MSIRECORD * MSI_QueryGetRecord(MSIDATABASE *db, LPCWSTR query,...) DECLSPEC_HIDDEN
Definition: msiquery.c:206
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
LONG HRESULT
Definition: typedefs.h:77
static INT_PTR CDECL cabinet_open(char *pszFile, int oflag, int pmode)
Definition: media.c:124
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
double __cdecl erf(double)
LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN
Definition: table.c:128
static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
Definition: media.c:183
#define ERROR_INSTALL_FAILURE
Definition: winerror.h:961
#define MAX_PATH
Definition: compat.h:26
static UINT CDECL cabinet_read_stream(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:238
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:299
UINT id
Definition: media.c:193
PVOID HANDLE
Definition: typedefs.h:71
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIDATABASE * db
Definition: msipriv.h:386
#define _O_CREAT
Definition: media.c:49
static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:748
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
static DWORD cb
Definition: integrity.c:41
static const WCHAR szMsi[]
Definition: msipriv.h:1119
#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:242
static const WCHAR szSourceDir[]
Definition: msipriv.h:1100
int ret
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:79
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
#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
static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:80
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:124
#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:2823
#define err(...)
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)
#define strcmpiW(s1, s2)
Definition: unicode.h:39
WINE_UNICODE_INLINE WCHAR * strrchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:254
struct list cabinet_streams
Definition: msipriv.h:399
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:245
#define ERR(fmt,...)
Definition: debug.h:109
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:59
#define CREATE_ALWAYS
Definition: disk.h:72
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
static ATOM item
Definition: dde.c:856
#define lstrcpyW
Definition: compat.h:406
#define CDECL
Definition: compat.h:21
GLsizei GLsizei GLchar * source
Definition: glext.h:6048
Definition: services.c:325
WINE_UNICODE_INLINE WCHAR * strcatW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:242
#define DRIVE_CDROM
Definition: winbase.h:251
#define MSICABEXTRACT_BEGINEXTRACT
Definition: msipriv.h:1054
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
unsigned int UINT
Definition: ndis.h:50
void * pv
Definition: fdi.h:231
#define _O_RDONLY
Definition: media.c:40
static LONG CDECL cabinet_seek_stream(INT_PTR hf, LONG dist, int seektype)
Definition: media.c:258
UINT Context
Definition: msipriv.h:437
#define CreateFileW
Definition: compat.h:400
static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:534
BOOL msi_cabextract(MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data)
Definition: media.c:653
static BOOL msi_free(void *mem)
Definition: msipriv.h:1227
LPWSTR BaseURL
Definition: msipriv.h:424
Definition: name.c:36
static UINT CDECL cabinet_read(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:155
GLuint res
Definition: glext.h:9613
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1204
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:912
#define MB_RETRYCANCEL
Definition: winuser.h:799
BOOL WINAPI MoveFileExW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName OPTIONAL, IN DWORD dwFlags)
Definition: move.c:1060
static UINT CDECL cabinet_write(INT_PTR hf, void *pv, UINT cb)
Definition: media.c:166
static INT_PTR cabinet_next_cabinet_stream(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
Definition: media.c:390
static UINT get_drive_type(const WCHAR *path)
Definition: media.c:670
#define CREATE_NEW
Definition: disk.h:69
IStorage * storage
Definition: msipriv.h:98
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
void msi_free_media_info(MSIMEDIAINFO *mi)
Definition: media.c:662
static void CDECL cabinet_free(void *pv)
Definition: media.c:119
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
Definition: media.c:275
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
#define _O_ACCMODE
Definition: media.c:43
#define MSIERR_CABNOTFOUND
Definition: resource.h:29
static WCHAR * strdupAtoW(const char *str)
Definition: main.c:67
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define SUCCEEDED(hr)
Definition: intsafe.h:57
LONGLONG QuadPart
Definition: typedefs.h:112
#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:2370