msi: breakup part 4
Aric Stewart
aric at codeweavers.com
Fri Jun 17 07:39:49 CDT 2005
Break out all the file related actions and helper functions into files.c
-------------- next part --------------
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.31
diff -u -r1.31 Makefile.in
--- dlls/msi/Makefile.in 16 Jun 2005 20:40:34 -0000 1.31
+++ dlls/msi/Makefile.in 17 Jun 2005 12:37:29 -0000
@@ -18,6 +18,7 @@
dialog.c \
distinct.c \
events.c \
+ files.c \
format.c \
handle.c \
helpers.c \
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.148
diff -u -r1.148 action.c
--- dlls/msi/action.c 16 Jun 2005 20:40:34 -0000 1.148
+++ dlls/msi/action.c 17 Jun 2005 12:37:31 -0000
@@ -1,7 +1,7 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
- * Copyright 2004 Aric Stewart for CodeWeavers
+ * Copyright 2004,2005 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,6 @@
*/
#include <stdarg.h>
-#include <stdio.h>
#define COBJMACROS
@@ -36,15 +35,8 @@
#include "winerror.h"
#include "winreg.h"
#include "wine/debug.h"
-#include "fdi.h"
-#include "msi.h"
-#include "msiquery.h"
#include "msidefs.h"
-#include "msvcrt/fcntl.h"
-#include "objbase.h"
-#include "objidl.h"
#include "msipriv.h"
-#include "winnls.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
@@ -73,8 +65,6 @@
static UINT ACTION_CreateFolders(MSIPACKAGE *package);
static UINT ACTION_CostFinalize(MSIPACKAGE *package);
static UINT ACTION_FileCost(MSIPACKAGE *package);
-static UINT ACTION_InstallFiles(MSIPACKAGE *package);
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
static UINT ACTION_InstallValidate(MSIPACKAGE *package);
@@ -99,16 +89,15 @@
/*
* consts and values used
*/
-static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
static const WCHAR c_colon[] = {'C',':','\\',0};
-static const WCHAR cszbs[]={'\\',0};
+
const static WCHAR szCreateFolders[] =
{'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
const static WCHAR szCostFinalize[] =
{'C','o','s','t','F','i','n','a','l','i','z','e',0};
-const static WCHAR szInstallFiles[] =
+const WCHAR szInstallFiles[] =
{'I','n','s','t','a','l','l','F','i','l','e','s',0};
-const static WCHAR szDuplicateFiles[] =
+const WCHAR szDuplicateFiles[] =
{'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
const static WCHAR szWriteRegistryValues[] =
{'W','r','i','t','e','R','e','g','i','s','t','r','y',
@@ -125,7 +114,7 @@
{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
const static WCHAR szProcessComponents[] =
{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
-const WCHAR szRegisterTypeLibraries[] =
+const static WCHAR szRegisterTypeLibraries[] =
{'R','e','g','i','s','t','e','r','T','y','p','e',
'L','i','b','r','a','r','i','e','s',0};
const WCHAR szRegisterClassInfo[] =
@@ -181,10 +170,10 @@
'F','i','l','e',0};
const static WCHAR szIsolateComponents[] =
{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szMigrateFeatureStates[] =
+const WCHAR szMigrateFeatureStates[] =
{'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
'S','t','a','t','e','s',0};
-const static WCHAR szMoveFiles[] =
+const WCHAR szMoveFiles[] =
{'M','o','v','e','F','i','l','e','s',0};
const static WCHAR szMsiPublishAssemblies[] =
{'M','s','i','P','u','b','l','i','s','h',
@@ -196,7 +185,7 @@
{'I','n','s','t','a','l','l','O','D','B','C',0};
const static WCHAR szInstallServices[] =
{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
-const static WCHAR szPatchFiles[] =
+const WCHAR szPatchFiles[] =
{'P','a','t','c','h','F','i','l','e','s',0};
const static WCHAR szPublishComponents[] =
{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
@@ -211,16 +200,16 @@
{'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
const static WCHAR szRegisterUser[] =
{'R','e','g','i','s','t','e','r','U','s','e','r',0};
-const static WCHAR szRemoveDuplicateFiles[] =
+const WCHAR szRemoveDuplicateFiles[] =
{'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
'F','i','l','e','s',0};
const static WCHAR szRemoveEnvironmentStrings[] =
{'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
'S','t','r','i','n','g','s',0};
-const static WCHAR szRemoveExistingProducts[] =
+const WCHAR szRemoveExistingProducts[] =
{'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
'P','r','o','d','u','c','t','s',0};
-const static WCHAR szRemoveFiles[] =
+const WCHAR szRemoveFiles[] =
{'R','e','m','o','v','e','F','i','l','e','s',0};
const static WCHAR szRemoveFolders[] =
{'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
@@ -250,19 +239,19 @@
'C','o','m','p','o','n','e','n','t','s',0};
const static WCHAR szUnpublishFeatures[] =
{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-const static WCHAR szUnregisterClassInfo[] =
+const WCHAR szUnregisterClassInfo[] =
{'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
'I','n','f','o',0};
const static WCHAR szUnregisterComPlus[] =
{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-const static WCHAR szUnregisterExtensionInfo[] =
+const WCHAR szUnregisterExtensionInfo[] =
{'U','n','r','e','g','i','s','t','e','r',
'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
const static WCHAR szUnregisterFonts[] =
{'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
-const static WCHAR szUnregisterMIMEInfo[] =
+const WCHAR szUnregisterMIMEInfo[] =
{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-const static WCHAR szUnregisterProgIdInfo[] =
+const WCHAR szUnregisterProgIdInfo[] =
{'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
'I','n','f','o',0};
const static WCHAR szUnregisterTypeLibraries[] =
@@ -2028,648 +2017,6 @@
return SetFeatureStates(package);
}
-/*
- * This is a helper function for handling embedded cabinet media
- */
-static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
- WCHAR* source)
-{
- UINT rc;
- USHORT* data;
- UINT size;
- DWORD write;
- HANDLE the_file;
- WCHAR tmp[MAX_PATH];
-
- rc = read_raw_stream_data(package->db,stream_name,&data,&size);
- if (rc != ERROR_SUCCESS)
- return rc;
-
- write = MAX_PATH;
- if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
- GetTempPathW(MAX_PATH,tmp);
-
- GetTempFileNameW(tmp,stream_name,0,source);
-
- track_tempfile(package,strrchrW(source,'\\'), source);
- the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (the_file == INVALID_HANDLE_VALUE)
- {
- ERR("Unable to create file %s\n",debugstr_w(source));
- rc = ERROR_FUNCTION_FAILED;
- goto end;
- }
-
- WriteFile(the_file,data,size,&write,NULL);
- CloseHandle(the_file);
- TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
-end:
- HeapFree(GetProcessHeap(),0,data);
- return rc;
-}
-
-
-/* Support functions for FDI functions */
-typedef struct
-{
- MSIPACKAGE* package;
- LPCSTR cab_path;
- LPCSTR file_name;
-} CabData;
-
-static void * cabinet_alloc(ULONG cb)
-{
- return HeapAlloc(GetProcessHeap(), 0, cb);
-}
-
-static void cabinet_free(void *pv)
-{
- HeapFree(GetProcessHeap(), 0, pv);
-}
-
-static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
-{
- DWORD dwAccess = 0;
- DWORD dwShareMode = 0;
- DWORD dwCreateDisposition = OPEN_EXISTING;
- switch (oflag & _O_ACCMODE)
- {
- case _O_RDONLY:
- dwAccess = GENERIC_READ;
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
- break;
- case _O_WRONLY:
- dwAccess = GENERIC_WRITE;
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- break;
- case _O_RDWR:
- dwAccess = GENERIC_READ | GENERIC_WRITE;
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- break;
- }
- if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
- dwCreateDisposition = CREATE_NEW;
- else if (oflag & _O_CREAT)
- dwCreateDisposition = CREATE_ALWAYS;
- return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
- dwCreateDisposition, 0, NULL);
-}
-
-static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
-{
- DWORD dwRead;
- if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
- return dwRead;
- return 0;
-}
-
-static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
-{
- DWORD dwWritten;
- if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
- return dwWritten;
- return 0;
-}
-
-static int cabinet_close(INT_PTR hf)
-{
- return CloseHandle((HANDLE)hf) ? 0 : -1;
-}
-
-static long cabinet_seek(INT_PTR hf, long dist, int seektype)
-{
- /* flags are compatible and so are passed straight through */
- return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
-}
-
-static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
-{
- /* FIXME: try to do more processing in this function */
- switch (fdint)
- {
- case fdintCOPY_FILE:
- {
- CabData *data = (CabData*) pfdin->pv;
- ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
- char *file;
-
- LPWSTR trackname;
- LPWSTR trackpath;
- LPWSTR tracknametmp;
- static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
-
- if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
- return 0;
-
- file = cabinet_alloc((len+1)*sizeof(char));
- strcpy(file, data->cab_path);
- strcat(file, pfdin->psz1);
-
- TRACE("file: %s\n", debugstr_a(file));
-
- /* track this file so it can be deleted if not installed */
- trackpath=strdupAtoW(file);
- tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
- trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
- strlenW(tmpprefix)+1) * sizeof(WCHAR));
-
- strcpyW(trackname,tmpprefix);
- strcatW(trackname,tracknametmp);
-
- track_tempfile(data->package, trackname, trackpath);
-
- HeapFree(GetProcessHeap(),0,trackpath);
- HeapFree(GetProcessHeap(),0,trackname);
- HeapFree(GetProcessHeap(),0,tracknametmp);
-
- return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
- }
- case fdintCLOSE_FILE_INFO:
- {
- FILETIME ft;
- FILETIME ftLocal;
- if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
- return -1;
- if (!LocalFileTimeToFileTime(&ft, &ftLocal))
- return -1;
- if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
- return -1;
-
- cabinet_close(pfdin->hf);
- return 1;
- }
- default:
- return 0;
- }
-}
-
-/***********************************************************************
- * extract_cabinet_file
- *
- * Extract files from a cab file.
- */
-static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
- const WCHAR* path, const WCHAR* file)
-{
- HFDI hfdi;
- ERF erf;
- BOOL ret;
- char *cabinet;
- char *cab_path;
- char *file_name;
- CabData data;
-
- TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
- debugstr_w(file), debugstr_w(path));
-
- hfdi = FDICreate(cabinet_alloc,
- cabinet_free,
- cabinet_open,
- cabinet_read,
- cabinet_write,
- cabinet_close,
- cabinet_seek,
- 0,
- &erf);
- if (!hfdi)
- {
- ERR("FDICreate failed\n");
- return FALSE;
- }
-
- if (!(cabinet = strdupWtoA( source )))
- {
- FDIDestroy(hfdi);
- return FALSE;
- }
- if (!(cab_path = strdupWtoA( path )))
- {
- FDIDestroy(hfdi);
- HeapFree(GetProcessHeap(), 0, cabinet);
- return FALSE;
- }
-
- data.package = package;
- data.cab_path = cab_path;
- if (file)
- file_name = strdupWtoA(file);
- else
- file_name = NULL;
- data.file_name = file_name;
-
- ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
-
- if (!ret)
- ERR("FDICopy failed\n");
-
- FDIDestroy(hfdi);
-
- HeapFree(GetProcessHeap(), 0, cabinet);
- HeapFree(GetProcessHeap(), 0, cab_path);
- HeapFree(GetProcessHeap(), 0, file_name);
-
- return ret;
-}
-
-static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
- MSIFILE* file)
-{
- UINT rc = ERROR_SUCCESS;
- MSIRECORD * row = 0;
- static WCHAR source[MAX_PATH];
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
- ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
- LPCWSTR cab;
- DWORD sz;
- INT seq;
- static UINT last_sequence = 0;
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- {
- TRACE("Uncompressed File, no media to ready.\n");
- return ERROR_SUCCESS;
- }
-
- if (file->Sequence <= last_sequence)
- {
- TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
- /*extract_a_cabinet_file(package, source,path,file->File); */
- return ERROR_SUCCESS;
- }
-
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
- if (!row)
- return ERROR_FUNCTION_FAILED;
-
- seq = MSI_RecordGetInteger(row,2);
- last_sequence = seq;
-
- cab = MSI_RecordGetString(row,4);
- if (cab)
- {
- TRACE("Source is CAB %s\n",debugstr_w(cab));
- /* the stream does not contain the # character */
- if (cab[0]=='#')
- {
- writeout_cabinet_stream(package,&cab[1],source);
- strcpyW(path,source);
- *(strrchrW(path,'\\')+1)=0;
- }
- else
- {
- sz = MAX_PATH;
- if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
- {
- ERR("No Source dir defined \n");
- rc = ERROR_FUNCTION_FAILED;
- }
- else
- {
- strcpyW(path,source);
- strcatW(source,cab);
- /* extract the cab file into a folder in the temp folder */
- sz = MAX_PATH;
- if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
- != ERROR_SUCCESS)
- GetTempPathW(MAX_PATH,path);
- }
- }
- rc = !extract_a_cabinet_file(package, source,path,NULL);
- }
- else
- {
- sz = MAX_PATH;
- MSI_GetPropertyW(package,cszSourceDir,source,&sz);
- strcpyW(path,source);
- }
- msiobj_release(&row->hdr);
- return rc;
-}
-
-inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
-{
- UINT rc = ERROR_SUCCESS;
- MSIFOLDER *folder;
- LPWSTR install_path;
-
- install_path = resolve_folder(package, package->components[component].Directory,
- FALSE, FALSE, &folder);
- if (!install_path)
- return ERROR_FUNCTION_FAILED;
-
- /* create the path */
- if (folder->State == 0)
- {
- create_full_pathW(install_path);
- folder->State = 2;
- }
- HeapFree(GetProcessHeap(), 0, install_path);
-
- return rc;
-}
-
-static UINT ACTION_InstallFiles(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- DWORD index;
- MSIRECORD * uirow;
- WCHAR uipath[MAX_PATH];
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- /* increment progress bar each time action data is sent */
- ui_progress(package,1,1,0,0);
-
- for (index = 0; index < package->loaded_files; index++)
- {
- WCHAR path_to_source[MAX_PATH];
- MSIFILE *file;
-
- file = &package->files[index];
-
- if (file->Temporary)
- continue;
-
-
- if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
- INSTALLSTATE_LOCAL))
- {
- ui_progress(package,2,file->FileSize,0,0);
- TRACE("File %s is not scheduled for install\n",
- debugstr_w(file->File));
-
- continue;
- }
-
- if ((file->State == 1) || (file->State == 2))
- {
- LPWSTR p;
- MSICOMPONENT* comp = NULL;
-
- TRACE("Installing %s\n",debugstr_w(file->File));
- rc = ready_media_for_file(package, path_to_source, file);
- /*
- * WARNING!
- * our file table could change here because a new temp file
- * may have been created
- */
- file = &package->files[index];
- if (rc != ERROR_SUCCESS)
- {
- ERR("Unable to ready media\n");
- rc = ERROR_FUNCTION_FAILED;
- break;
- }
-
- create_component_directory( package, file->ComponentIndex);
-
- /* recalculate file paths because things may have changed */
-
- if (file->ComponentIndex >= 0)
- comp = &package->components[file->ComponentIndex];
-
- p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
- HeapFree(GetProcessHeap(),0,file->TargetPath);
-
- file->TargetPath = build_directory_name(2, p, file->FileName);
- HeapFree(GetProcessHeap(),0,p);
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- {
- p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
- file->SourcePath = build_directory_name(2, p, file->ShortName);
- HeapFree(GetProcessHeap(),0,p);
- }
- else
- file->SourcePath = build_directory_name(2, path_to_source,
- file->File);
-
-
- TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath));
-
- /* the UI chunk */
- uirow=MSI_CreateRecord(9);
- MSI_RecordSetStringW(uirow,1,file->File);
- strcpyW(uipath,file->TargetPath);
- *(strrchrW(uipath,'\\')+1)=0;
- MSI_RecordSetStringW(uirow,9,uipath);
- MSI_RecordSetInteger(uirow,6,file->FileSize);
- ui_actiondata(package,szInstallFiles,uirow);
- msiobj_release( &uirow->hdr );
- ui_progress(package,2,file->FileSize,0,0);
-
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
- else
- rc = MoveFileW(file->SourcePath, file->TargetPath);
-
- if (!rc)
- {
- rc = GetLastError();
- ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
- debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
- rc);
- if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
- {
- if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
- ERR("Unable to copy file (%s -> %s) (error %ld)\n",
- debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath), GetLastError());
- if (!(file->Attributes & msidbFileAttributesNoncompressed))
- DeleteFileW(file->SourcePath);
- rc = 0;
- }
- else if (rc == ERROR_FILE_NOT_FOUND)
- {
- ERR("Source File Not Found! Continuing\n");
- rc = 0;
- }
- else if (file->Attributes & msidbFileAttributesVital)
- {
- ERR("Ignoring Error and continuing (nonvital file)...\n");
- rc = 0;
- }
- }
- else
- {
- file->State = 4;
- rc = ERROR_SUCCESS;
- }
- }
- }
-
- return rc;
-}
-
-inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
- LPWSTR* file_source)
-{
- DWORD index;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- for (index = 0; index < package->loaded_files; index ++)
- {
- if (strcmpW(file_key,package->files[index].File)==0)
- {
- if (package->files[index].State >= 2)
- {
- *file_source = strdupW(package->files[index].TargetPath);
- return ERROR_SUCCESS;
- }
- else
- return ERROR_FILE_NOT_FOUND;
- }
- }
-
- return ERROR_FUNCTION_FAILED;
-}
-
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- WCHAR *file_source = NULL;
- WCHAR dest_name[0x100];
- LPWSTR dest_path, dest;
- LPCWSTR file_key, component;
- INT component_index;
-
- DWORD sz;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- component = MSI_RecordGetString(row,2);
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping copy due to disabled component %s\n",
- debugstr_w(component));
-
- /* the action taken was the same as the current install state */
- package->components[component_index].Action =
- package->components[component_index].Installed;
-
- msiobj_release(&row->hdr);
- continue;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
-
- file_key = MSI_RecordGetString(row,3);
- if (!file_key)
- {
- ERR("Unable to get file key\n");
- msiobj_release(&row->hdr);
- break;
- }
-
- rc = get_file_target(package,file_key,&file_source);
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Original file unknown %s\n",debugstr_w(file_key));
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- continue;
- }
-
- if (MSI_RecordIsNull(row,4))
- {
- strcpyW(dest_name,strrchrW(file_source,'\\')+1);
- }
- else
- {
- sz=0x100;
- MSI_RecordGetStringW(row,4,dest_name,&sz);
- reduce_to_longfilename(dest_name);
- }
-
- if (MSI_RecordIsNull(row,5))
- {
- LPWSTR p;
- dest_path = strdupW(file_source);
- p = strrchrW(dest_path,'\\');
- if (p)
- *p=0;
- }
- else
- {
- LPCWSTR destkey;
- destkey = MSI_RecordGetString(row,5);
- dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
- if (!dest_path)
- {
- ERR("Unable to get destination folder\n");
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- break;
- }
- }
-
- dest = build_directory_name(2, dest_path, dest_name);
-
- TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
- debugstr_w(dest));
-
- if (strcmpW(file_source,dest))
- rc = !CopyFileW(file_source,dest,TRUE);
- else
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
-
- FIXME("We should track these duplicate files as well\n");
-
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,dest_path);
- HeapFree(GetProcessHeap(),0,dest);
- HeapFree(GetProcessHeap(),0,file_source);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
/* OK this value is "interpreted" and then formatted based on the
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.19
diff -u -r1.19 action.h
--- dlls/msi/action.h 17 Jun 2005 09:52:13 -0000 1.19
+++ dlls/msi/action.h 17 Jun 2005 12:37:32 -0000
@@ -205,6 +205,8 @@
/* actions in other modules */
UINT ACTION_AppSearch(MSIPACKAGE *package);
UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
+UINT ACTION_InstallFiles(MSIPACKAGE *package);
+UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
@@ -252,3 +254,4 @@
extern const WCHAR cszSourceDir[];
extern const WCHAR szProductCode[];
extern const WCHAR cszRootDrive[];
+extern const WCHAR cszbs[];
--- /dev//null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/files.c 2005-06-17 07:31:01.000000000 -0500
@@ -0,0 +1,699 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Actions dealing with files These are
+ *
+ * InstallFiles
+ * DuplicateFiles
+ * MoveFiles (TODO)
+ * PatchFiles (TODO)
+ * RemoveDuplicateFiles(TODO)
+ * RemoveFiles(TODO)
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "fdi.h"
+#include "msidefs.h"
+#include "msvcrt/fcntl.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+extern const WCHAR szInstallFiles[];
+extern const WCHAR szDuplicateFiles[];
+extern const WCHAR szMoveFiles[];
+extern const WCHAR szPatchFiles[];
+extern const WCHAR szRemoveDuplicateFiles[];
+extern const WCHAR szRemoveFiles[];
+
+static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
+
+inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIFOLDER *folder;
+ LPWSTR install_path;
+
+ install_path = resolve_folder(package, package->components[component].Directory,
+ FALSE, FALSE, &folder);
+ if (!install_path)
+ return ERROR_FUNCTION_FAILED;
+
+ /* create the path */
+ if (folder->State == 0)
+ {
+ create_full_pathW(install_path);
+ folder->State = 2;
+ }
+ HeapFree(GetProcessHeap(), 0, install_path);
+
+ return rc;
+}
+
+/*
+ * This is a helper function for handling embedded cabinet media
+ */
+static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
+ WCHAR* source)
+{
+ UINT rc;
+ USHORT* data;
+ UINT size;
+ DWORD write;
+ HANDLE the_file;
+ WCHAR tmp[MAX_PATH];
+
+ rc = read_raw_stream_data(package->db,stream_name,&data,&size);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ write = MAX_PATH;
+ if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
+ GetTempPathW(MAX_PATH,tmp);
+
+ GetTempFileNameW(tmp,stream_name,0,source);
+
+ track_tempfile(package,strrchrW(source,'\\'), source);
+ the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (the_file == INVALID_HANDLE_VALUE)
+ {
+ ERR("Unable to create file %s\n",debugstr_w(source));
+ rc = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ WriteFile(the_file,data,size,&write,NULL);
+ CloseHandle(the_file);
+ TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
+end:
+ HeapFree(GetProcessHeap(),0,data);
+ return rc;
+}
+
+
+/* Support functions for FDI functions */
+typedef struct
+{
+ MSIPACKAGE* package;
+ LPCSTR cab_path;
+ LPCSTR file_name;
+} CabData;
+
+static void * cabinet_alloc(ULONG cb)
+{
+ return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void cabinet_free(void *pv)
+{
+ HeapFree(GetProcessHeap(), 0, pv);
+}
+
+static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
+{
+ DWORD dwAccess = 0;
+ DWORD dwShareMode = 0;
+ DWORD dwCreateDisposition = OPEN_EXISTING;
+ switch (oflag & _O_ACCMODE)
+ {
+ case _O_RDONLY:
+ dwAccess = GENERIC_READ;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
+ break;
+ case _O_WRONLY:
+ dwAccess = GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ case _O_RDWR:
+ dwAccess = GENERIC_READ | GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ }
+ if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
+ dwCreateDisposition = CREATE_NEW;
+ else if (oflag & _O_CREAT)
+ dwCreateDisposition = CREATE_ALWAYS;
+ return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+ dwCreateDisposition, 0, NULL);
+}
+
+static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwRead;
+ if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
+ return dwRead;
+ return 0;
+}
+
+static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwWritten;
+ if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
+ return dwWritten;
+ return 0;
+}
+
+static int cabinet_close(INT_PTR hf)
+{
+ return CloseHandle((HANDLE)hf) ? 0 : -1;
+}
+
+static long cabinet_seek(INT_PTR hf, long dist, int seektype)
+{
+ /* flags are compatible and so are passed straight through */
+ return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
+}
+
+static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
+{
+ /* FIXME: try to do more processing in this function */
+ switch (fdint)
+ {
+ case fdintCOPY_FILE:
+ {
+ CabData *data = (CabData*) pfdin->pv;
+ ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
+ char *file;
+
+ LPWSTR trackname;
+ LPWSTR trackpath;
+ LPWSTR tracknametmp;
+ static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
+
+ if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
+ return 0;
+
+ file = cabinet_alloc((len+1)*sizeof(char));
+ strcpy(file, data->cab_path);
+ strcat(file, pfdin->psz1);
+
+ TRACE("file: %s\n", debugstr_a(file));
+
+ /* track this file so it can be deleted if not installed */
+ trackpath=strdupAtoW(file);
+ tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
+ trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
+ strlenW(tmpprefix)+1) * sizeof(WCHAR));
+
+ strcpyW(trackname,tmpprefix);
+ strcatW(trackname,tracknametmp);
+
+ track_tempfile(data->package, trackname, trackpath);
+
+ HeapFree(GetProcessHeap(),0,trackpath);
+ HeapFree(GetProcessHeap(),0,trackname);
+ HeapFree(GetProcessHeap(),0,tracknametmp);
+
+ return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
+ }
+ case fdintCLOSE_FILE_INFO:
+ {
+ FILETIME ft;
+ FILETIME ftLocal;
+ if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
+ return -1;
+ if (!LocalFileTimeToFileTime(&ft, &ftLocal))
+ return -1;
+ if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
+ return -1;
+
+ cabinet_close(pfdin->hf);
+ return 1;
+ }
+ default:
+ return 0;
+ }
+}
+
+/***********************************************************************
+ * extract_cabinet_file
+ *
+ * Extract files from a cab file.
+ */
+static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
+ const WCHAR* path, const WCHAR* file)
+{
+ HFDI hfdi;
+ ERF erf;
+ BOOL ret;
+ char *cabinet;
+ char *cab_path;
+ char *file_name;
+ CabData data;
+
+ TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
+ debugstr_w(file), debugstr_w(path));
+
+ hfdi = FDICreate(cabinet_alloc,
+ cabinet_free,
+ cabinet_open,
+ cabinet_read,
+ cabinet_write,
+ cabinet_close,
+ cabinet_seek,
+ 0,
+ &erf);
+ if (!hfdi)
+ {
+ ERR("FDICreate failed\n");
+ return FALSE;
+ }
+
+ if (!(cabinet = strdupWtoA( source )))
+ {
+ FDIDestroy(hfdi);
+ return FALSE;
+ }
+ if (!(cab_path = strdupWtoA( path )))
+ {
+ FDIDestroy(hfdi);
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ return FALSE;
+ }
+
+ data.package = package;
+ data.cab_path = cab_path;
+ if (file)
+ file_name = strdupWtoA(file);
+ else
+ file_name = NULL;
+ data.file_name = file_name;
+
+ ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
+
+ if (!ret)
+ ERR("FDICopy failed\n");
+
+ FDIDestroy(hfdi);
+
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ HeapFree(GetProcessHeap(), 0, cab_path);
+ HeapFree(GetProcessHeap(), 0, file_name);
+
+ return ret;
+}
+
+static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
+ MSIFILE* file)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIRECORD * row = 0;
+ static WCHAR source[MAX_PATH];
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+ '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
+ ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
+ LPCWSTR cab;
+ DWORD sz;
+ INT seq;
+ static UINT last_sequence = 0;
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ TRACE("Uncompressed File, no media to ready.\n");
+ return ERROR_SUCCESS;
+ }
+
+ if (file->Sequence <= last_sequence)
+ {
+ TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
+ /*extract_a_cabinet_file(package, source,path,file->File); */
+ return ERROR_SUCCESS;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
+ if (!row)
+ return ERROR_FUNCTION_FAILED;
+
+ seq = MSI_RecordGetInteger(row,2);
+ last_sequence = seq;
+
+ cab = MSI_RecordGetString(row,4);
+ if (cab)
+ {
+ TRACE("Source is CAB %s\n",debugstr_w(cab));
+ /* the stream does not contain the # character */
+ if (cab[0]=='#')
+ {
+ writeout_cabinet_stream(package,&cab[1],source);
+ strcpyW(path,source);
+ *(strrchrW(path,'\\')+1)=0;
+ }
+ else
+ {
+ sz = MAX_PATH;
+ if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
+ {
+ ERR("No Source dir defined \n");
+ rc = ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ strcpyW(path,source);
+ strcatW(source,cab);
+ /* extract the cab file into a folder in the temp folder */
+ sz = MAX_PATH;
+ if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
+ != ERROR_SUCCESS)
+ GetTempPathW(MAX_PATH,path);
+ }
+ }
+ rc = !extract_a_cabinet_file(package, source,path,NULL);
+ }
+ else
+ {
+ sz = MAX_PATH;
+ MSI_GetPropertyW(package,cszSourceDir,source,&sz);
+ strcpyW(path,source);
+ }
+ msiobj_release(&row->hdr);
+ return rc;
+}
+
+inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
+ LPWSTR* file_source)
+{
+ DWORD index;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ for (index = 0; index < package->loaded_files; index ++)
+ {
+ if (strcmpW(file_key,package->files[index].File)==0)
+ {
+ if (package->files[index].State >= 2)
+ {
+ *file_source = strdupW(package->files[index].TargetPath);
+ return ERROR_SUCCESS;
+ }
+ else
+ return ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+UINT ACTION_InstallFiles(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ DWORD index;
+ MSIRECORD * uirow;
+ WCHAR uipath[MAX_PATH];
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ /* increment progress bar each time action data is sent */
+ ui_progress(package,1,1,0,0);
+
+ for (index = 0; index < package->loaded_files; index++)
+ {
+ WCHAR path_to_source[MAX_PATH];
+ MSIFILE *file;
+
+ file = &package->files[index];
+
+ if (file->Temporary)
+ continue;
+
+
+ if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
+ INSTALLSTATE_LOCAL))
+ {
+ ui_progress(package,2,file->FileSize,0,0);
+ TRACE("File %s is not scheduled for install\n",
+ debugstr_w(file->File));
+
+ continue;
+ }
+
+ if ((file->State == 1) || (file->State == 2))
+ {
+ LPWSTR p;
+ MSICOMPONENT* comp = NULL;
+
+ TRACE("Installing %s\n",debugstr_w(file->File));
+ rc = ready_media_for_file(package, path_to_source, file);
+ /*
+ * WARNING!
+ * our file table could change here because a new temp file
+ * may have been created
+ */
+ file = &package->files[index];
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to ready media\n");
+ rc = ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ create_component_directory( package, file->ComponentIndex);
+
+ /* recalculate file paths because things may have changed */
+
+ if (file->ComponentIndex >= 0)
+ comp = &package->components[file->ComponentIndex];
+
+ p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
+ HeapFree(GetProcessHeap(),0,file->TargetPath);
+
+ file->TargetPath = build_directory_name(2, p, file->FileName);
+ HeapFree(GetProcessHeap(),0,p);
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
+ file->SourcePath = build_directory_name(2, p, file->ShortName);
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ else
+ file->SourcePath = build_directory_name(2, path_to_source,
+ file->File);
+
+
+ TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath));
+
+ /* the UI chunk */
+ uirow=MSI_CreateRecord(9);
+ MSI_RecordSetStringW(uirow,1,file->File);
+ strcpyW(uipath,file->TargetPath);
+ *(strrchrW(uipath,'\\')+1)=0;
+ MSI_RecordSetStringW(uirow,9,uipath);
+ MSI_RecordSetInteger(uirow,6,file->FileSize);
+ ui_actiondata(package,szInstallFiles,uirow);
+ msiobj_release( &uirow->hdr );
+ ui_progress(package,2,file->FileSize,0,0);
+
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
+ else
+ rc = MoveFileW(file->SourcePath, file->TargetPath);
+
+ if (!rc)
+ {
+ rc = GetLastError();
+ ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
+ debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
+ rc);
+ if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
+ {
+ if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
+ ERR("Unable to copy file (%s -> %s) (error %ld)\n",
+ debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath), GetLastError());
+ if (!(file->Attributes & msidbFileAttributesNoncompressed))
+ DeleteFileW(file->SourcePath);
+ rc = 0;
+ }
+ else if (rc == ERROR_FILE_NOT_FOUND)
+ {
+ ERR("Source File Not Found! Continuing\n");
+ rc = 0;
+ }
+ else if (file->Attributes & msidbFileAttributesVital)
+ {
+ ERR("Ignoring Error and continuing (nonvital file)...\n");
+ rc = 0;
+ }
+ }
+ else
+ {
+ file->State = 4;
+ rc = ERROR_SUCCESS;
+ }
+ }
+ }
+
+ return rc;
+}
+
+UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
+{
+ UINT rc;
+ MSIQUERY * view;
+ MSIRECORD * row = 0;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR *file_source = NULL;
+ WCHAR dest_name[0x100];
+ LPWSTR dest_path, dest;
+ LPCWSTR file_key, component;
+ INT component_index;
+
+ DWORD sz;
+
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ component = MSI_RecordGetString(row,2);
+ component_index = get_loaded_component(package,component);
+
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping copy due to disabled component %s\n",
+ debugstr_w(component));
+
+ /* the action taken was the same as the current install state */
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
+
+ msiobj_release(&row->hdr);
+ continue;
+ }
+
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
+
+ file_key = MSI_RecordGetString(row,3);
+ if (!file_key)
+ {
+ ERR("Unable to get file key\n");
+ msiobj_release(&row->hdr);
+ break;
+ }
+
+ rc = get_file_target(package,file_key,&file_source);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Original file unknown %s\n",debugstr_w(file_key));
+ msiobj_release(&row->hdr);
+ HeapFree(GetProcessHeap(),0,file_source);
+ continue;
+ }
+
+ if (MSI_RecordIsNull(row,4))
+ {
+ strcpyW(dest_name,strrchrW(file_source,'\\')+1);
+ }
+ else
+ {
+ sz=0x100;
+ MSI_RecordGetStringW(row,4,dest_name,&sz);
+ reduce_to_longfilename(dest_name);
+ }
+
+ if (MSI_RecordIsNull(row,5))
+ {
+ LPWSTR p;
+ dest_path = strdupW(file_source);
+ p = strrchrW(dest_path,'\\');
+ if (p)
+ *p=0;
+ }
+ else
+ {
+ LPCWSTR destkey;
+ destkey = MSI_RecordGetString(row,5);
+ dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
+ if (!dest_path)
+ {
+ ERR("Unable to get destination folder\n");
+ msiobj_release(&row->hdr);
+ HeapFree(GetProcessHeap(),0,file_source);
+ break;
+ }
+ }
+
+ dest = build_directory_name(2, dest_path, dest_name);
+
+ TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
+ debugstr_w(dest));
+
+ if (strcmpW(file_source,dest))
+ rc = !CopyFileW(file_source,dest,TRUE);
+ else
+ rc = ERROR_SUCCESS;
+
+ if (rc != ERROR_SUCCESS)
+ ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
+
+ FIXME("We should track these duplicate files as well\n");
+
+ msiobj_release(&row->hdr);
+ HeapFree(GetProcessHeap(),0,dest_path);
+ HeapFree(GetProcessHeap(),0,dest);
+ HeapFree(GetProcessHeap(),0,file_source);
+ }
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+}
More information about the wine-patches
mailing list