2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* 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
|
2006-08-01 23:12:11 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Actions dealing with files These are
|
|
|
|
*
|
|
|
|
* InstallFiles
|
|
|
|
* DuplicateFiles
|
2010-03-06 09:05:09 +00:00
|
|
|
* MoveFiles
|
2006-02-17 00:04:10 +00:00
|
|
|
* PatchFiles (TODO)
|
2010-03-06 09:05:09 +00:00
|
|
|
* RemoveDuplicateFiles
|
|
|
|
* RemoveFiles
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winerror.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
#include "fdi.h"
|
|
|
|
#include "msi.h"
|
|
|
|
#include "msidefs.h"
|
|
|
|
#include "msipriv.h"
|
|
|
|
#include "winuser.h"
|
2006-08-30 19:24:26 +00:00
|
|
|
#include "winreg.h"
|
|
|
|
#include "shlwapi.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
#include "wine/unicode.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, f->FileName );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 9, f->Component->Directory );
|
2006-02-17 00:04:10 +00:00
|
|
|
MSI_RecordSetInteger( uirow, 6, f->FileSize );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
ui_actiondata( package, action, uirow );
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
ui_progress( package, 2, f->FileSize, 0, 0 );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
static void schedule_install_files(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (file->Component->ActionRequest != INSTALLSTATE_LOCAL || !file->Component->Enabled)
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
|
|
|
TRACE("File %s is not scheduled for install\n", debugstr_w(file->File));
|
|
|
|
|
|
|
|
ui_progress(package,2,file->FileSize,0,0);
|
|
|
|
file->state = msifs_skipped;
|
|
|
|
}
|
2010-05-29 08:55:43 +00:00
|
|
|
else
|
|
|
|
file->Component->Action = INSTALLSTATE_LOCAL;
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static UINT copy_file(MSIFILE *file, LPWSTR source)
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
ret = CopyFileW(source, file->TargetPath, FALSE);
|
|
|
|
if (!ret)
|
|
|
|
return GetLastError();
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
|
|
|
|
file->state = msifs_installed;
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2009-10-17 21:16:57 +00:00
|
|
|
static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
UINT gle;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
TRACE("Copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
gle = copy_file(file, source);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (gle == ERROR_SUCCESS)
|
|
|
|
return gle;
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
if (gle == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
|
|
|
|
{
|
|
|
|
TRACE("overwriting existing file\n");
|
2009-10-17 21:16:57 +00:00
|
|
|
return ERROR_SUCCESS;
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
else if (gle == ERROR_ACCESS_DENIED)
|
|
|
|
{
|
|
|
|
SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
gle = copy_file(file, source);
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("Overwriting existing file: %d\n", gle);
|
|
|
|
}
|
2009-12-22 09:28:03 +00:00
|
|
|
if (gle == ERROR_SHARING_VIOLATION || gle == ERROR_USER_MAPPED_FILE)
|
2009-10-17 21:16:57 +00:00
|
|
|
{
|
|
|
|
WCHAR tmpfileW[MAX_PATH], *pathW, *p;
|
|
|
|
DWORD len;
|
|
|
|
|
|
|
|
TRACE("file in use, scheduling rename operation\n");
|
|
|
|
|
2009-10-25 11:06:09 +00:00
|
|
|
GetTempFileNameW(szBackSlash, szMsi, 0, tmpfileW);
|
2009-10-17 21:16:57 +00:00
|
|
|
len = strlenW(file->TargetPath) + strlenW(tmpfileW) + 1;
|
2010-05-29 08:55:43 +00:00
|
|
|
if (!(pathW = msi_alloc(len * sizeof(WCHAR))))
|
2009-10-17 21:16:57 +00:00
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
strcpyW(pathW, file->TargetPath);
|
|
|
|
if ((p = strrchrW(pathW, '\\'))) *p = 0;
|
|
|
|
strcatW(pathW, tmpfileW);
|
|
|
|
|
|
|
|
if (CopyFileW(source, pathW, FALSE) &&
|
|
|
|
MoveFileExW(file->TargetPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) &&
|
|
|
|
MoveFileExW(pathW, file->TargetPath, MOVEFILE_DELAY_UNTIL_REBOOT))
|
|
|
|
{
|
|
|
|
file->state = msifs_installed;
|
|
|
|
package->need_reboot = 1;
|
|
|
|
gle = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gle = GetLastError();
|
|
|
|
WARN("failed to schedule rename operation: %d)\n", gle);
|
|
|
|
}
|
2010-05-29 08:55:43 +00:00
|
|
|
msi_free(pathW);
|
2009-10-17 21:16:57 +00:00
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
|
|
|
|
return gle;
|
|
|
|
}
|
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
static UINT msi_create_directory( MSIPACKAGE *package, const WCHAR *dir )
|
|
|
|
{
|
|
|
|
MSIFOLDER *folder;
|
|
|
|
WCHAR *install_path;
|
|
|
|
|
|
|
|
install_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
|
|
|
|
if (!install_path)
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
if (folder->State == 0)
|
|
|
|
{
|
|
|
|
create_full_pathW( install_path );
|
|
|
|
folder->State = 2;
|
|
|
|
}
|
|
|
|
msi_free( install_path );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
|
|
|
|
LPWSTR *path, DWORD *attrs, PVOID user)
|
|
|
|
{
|
|
|
|
static MSIFILE *f = NULL;
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
UINT_PTR disk_id = (UINT_PTR)user;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
if (action == MSICABEXTRACT_BEGINEXTRACT)
|
|
|
|
{
|
|
|
|
f = get_loaded_file(package, file);
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
WARN("unknown file in cabinet (%s)\n", debugstr_w(file));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
if (f->disk_id != disk_id || (f->state != msifs_missing && f->state != msifs_overwrite))
|
2008-12-27 15:10:14 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
msi_file_update_ui(package, f, szInstallFiles);
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
msi_create_directory(package, f->Component->Directory);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
*path = strdupW(f->TargetPath);
|
|
|
|
*attrs = f->Attributes;
|
|
|
|
}
|
|
|
|
else if (action == MSICABEXTRACT_FILEEXTRACTED)
|
|
|
|
{
|
|
|
|
f->state = msifs_installed;
|
|
|
|
f = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* ACTION_InstallFiles()
|
2008-01-16 10:11:22 +00:00
|
|
|
*
|
2006-02-17 00:04:10 +00:00
|
|
|
* For efficiency, this is done in two passes:
|
|
|
|
* 1) Correct all the TargetPaths and determine what files are to be installed.
|
|
|
|
* 2) Extract Cabinets and copy files.
|
|
|
|
*/
|
|
|
|
UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
|
|
|
{
|
2008-05-17 19:46:01 +00:00
|
|
|
MSIMEDIAINFO *mi;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc = ERROR_SUCCESS;
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
/* increment progress bar each time action data is sent */
|
|
|
|
ui_progress(package,1,1,0,0);
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
schedule_install_files(package);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-05-17 19:46:01 +00:00
|
|
|
mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
if (file->state != msifs_missing && !mi->is_continuous && file->state != msifs_overwrite)
|
2006-02-17 00:04:10 +00:00
|
|
|
continue;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (file->Sequence > mi->last_sequence || mi->is_continuous ||
|
|
|
|
(file->IsCompressed && !mi->is_extracted))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
MSICABDATA data;
|
2008-05-17 19:46:01 +00:00
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
rc = ready_media(package, file, mi);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
ERR("Failed to ready media for %s\n", debugstr_w(file->File));
|
2006-11-28 11:21:39 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-17 19:46:01 +00:00
|
|
|
data.mi = mi;
|
|
|
|
data.package = package;
|
2008-12-27 15:10:14 +00:00
|
|
|
data.cb = installfiles_cb;
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
data.user = (PVOID)(UINT_PTR)mi->disk_id;
|
2008-05-17 19:46:01 +00:00
|
|
|
|
|
|
|
if (file->IsCompressed &&
|
2008-12-27 15:10:14 +00:00
|
|
|
!msi_cabextract(package, mi, &data))
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
|
|
|
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
|
2010-05-29 08:55:43 +00:00
|
|
|
rc = ERROR_INSTALL_FAILURE;
|
2006-11-28 11:21:39 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
if (!file->IsCompressed)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
LPWSTR source = resolve_file_source(package, file);
|
|
|
|
|
|
|
|
TRACE("file paths %s to %s\n", debugstr_w(source),
|
2008-07-08 20:52:29 +00:00
|
|
|
debugstr_w(file->TargetPath));
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_file_update_ui(package, file, szInstallFiles);
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
msi_create_directory(package, file->Component->Directory);
|
|
|
|
|
2009-10-17 21:16:57 +00:00
|
|
|
rc = copy_install_file(package, file, source);
|
2006-11-28 11:21:39 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source),
|
2006-11-28 11:21:39 +00:00
|
|
|
debugstr_w(file->TargetPath), rc);
|
|
|
|
rc = ERROR_INSTALL_FAILURE;
|
2008-12-27 15:10:14 +00:00
|
|
|
msi_free(source);
|
2006-11-28 11:21:39 +00:00
|
|
|
break;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
msi_free(source);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
else if (file->state != msifs_installed)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->TargetPath));
|
2006-11-28 11:21:39 +00:00
|
|
|
rc = ERROR_INSTALL_FAILURE;
|
|
|
|
break;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
msi_free_media_info(mi);
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
struct list entry;
|
|
|
|
LPWSTR sourcename;
|
|
|
|
LPWSTR destname;
|
|
|
|
LPWSTR source;
|
|
|
|
LPWSTR dest;
|
|
|
|
} FILE_LIST;
|
|
|
|
|
|
|
|
static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
|
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
|
|
|
|
GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
{
|
|
|
|
WARN("Source or dest is directory, not moving\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options == msidbMoveFileOptionsMove)
|
|
|
|
{
|
|
|
|
TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
|
|
|
|
ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
WARN("MoveFile failed: %d\n", GetLastError());
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
|
|
|
|
ret = CopyFileW(source, dest, FALSE);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
WARN("CopyFile failed: %d\n", GetLastError());
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
|
|
|
|
{
|
|
|
|
LPWSTR path, ptr;
|
|
|
|
DWORD dirlen, pathlen;
|
|
|
|
|
|
|
|
ptr = strrchrW(wildcard, '\\');
|
|
|
|
dirlen = ptr - wildcard + 1;
|
|
|
|
|
|
|
|
pathlen = dirlen + lstrlenW(filename) + 1;
|
|
|
|
path = msi_alloc(pathlen * sizeof(WCHAR));
|
|
|
|
|
|
|
|
lstrcpynW(path, wildcard, dirlen + 1);
|
|
|
|
lstrcatW(path, filename);
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_file_entry(FILE_LIST *file)
|
|
|
|
{
|
|
|
|
msi_free(file->source);
|
|
|
|
msi_free(file->dest);
|
|
|
|
msi_free(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_list(FILE_LIST *list)
|
|
|
|
{
|
|
|
|
while (!list_empty(&list->entry))
|
|
|
|
{
|
|
|
|
FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
|
|
|
|
|
|
|
|
list_remove(&file->entry);
|
|
|
|
free_file_entry(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
|
|
|
|
{
|
|
|
|
FILE_LIST *new, *file;
|
|
|
|
LPWSTR ptr, filename;
|
|
|
|
DWORD size;
|
|
|
|
|
|
|
|
new = msi_alloc_zero(sizeof(FILE_LIST));
|
|
|
|
if (!new)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
new->source = strdupW(source);
|
|
|
|
ptr = strrchrW(dest, '\\') + 1;
|
|
|
|
filename = strrchrW(new->source, '\\') + 1;
|
|
|
|
|
|
|
|
new->sourcename = filename;
|
|
|
|
|
|
|
|
if (*ptr)
|
|
|
|
new->destname = ptr;
|
|
|
|
else
|
|
|
|
new->destname = new->sourcename;
|
|
|
|
|
|
|
|
size = (ptr - dest) + lstrlenW(filename) + 1;
|
|
|
|
new->dest = msi_alloc(size * sizeof(WCHAR));
|
|
|
|
if (!new->dest)
|
|
|
|
{
|
|
|
|
free_file_entry(new);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
lstrcpynW(new->dest, dest, ptr - dest + 1);
|
|
|
|
lstrcatW(new->dest, filename);
|
|
|
|
|
|
|
|
if (list_empty(&files->entry))
|
|
|
|
{
|
|
|
|
list_add_head(&files->entry, &new->entry);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
|
|
|
|
{
|
|
|
|
if (lstrcmpW(source, file->source) < 0)
|
|
|
|
{
|
|
|
|
list_add_before(&file->entry, &new->entry);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_after(&file->entry, &new->entry);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATAW wfd;
|
|
|
|
HANDLE hfile;
|
|
|
|
LPWSTR path;
|
|
|
|
BOOL res;
|
|
|
|
FILE_LIST files, *file;
|
|
|
|
DWORD size;
|
|
|
|
|
|
|
|
hfile = FindFirstFileW(source, &wfd);
|
|
|
|
if (hfile == INVALID_HANDLE_VALUE) return FALSE;
|
|
|
|
|
|
|
|
list_init(&files.entry);
|
|
|
|
|
|
|
|
for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
|
|
|
|
{
|
|
|
|
if (is_dot_dir(wfd.cFileName)) continue;
|
|
|
|
|
|
|
|
path = wildcard_to_file(source, wfd.cFileName);
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
res = FALSE;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_wildcard(&files, path, dest);
|
|
|
|
msi_free(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no files match the wildcard */
|
|
|
|
if (list_empty(&files.entry))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* only the first wildcard match gets renamed to dest */
|
|
|
|
file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
|
|
|
|
size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
|
|
|
|
file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
|
|
|
|
if (!file->dest)
|
|
|
|
{
|
|
|
|
res = FALSE;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* file->dest may be shorter after the reallocation, so add a NULL
|
|
|
|
* terminator. This is needed for the call to strrchrW, as there will no
|
|
|
|
* longer be a NULL terminator within the bounds of the allocation in this case.
|
|
|
|
*/
|
|
|
|
file->dest[size - 1] = '\0';
|
|
|
|
lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
|
|
|
|
|
|
|
|
while (!list_empty(&files.entry))
|
|
|
|
{
|
|
|
|
file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
|
|
|
|
|
|
|
|
msi_move_file(file->source, file->dest, options);
|
|
|
|
|
|
|
|
list_remove(&file->entry);
|
|
|
|
free_file_entry(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
res = TRUE;
|
|
|
|
|
|
|
|
done:
|
|
|
|
free_list(&files);
|
|
|
|
FindClose(hfile);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR sourcename, component;
|
|
|
|
LPWSTR sourcedir, destname = NULL, destdir = NULL, source = NULL, dest = NULL;
|
|
|
|
int options;
|
|
|
|
DWORD size;
|
|
|
|
BOOL ret, wildcards;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
component = MSI_RecordGetString(rec, 2);
|
|
|
|
comp = get_loaded_component(package, component);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!comp->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (comp->ActionRequest != INSTALLSTATE_LOCAL && comp->ActionRequest != INSTALLSTATE_SOURCE)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
|
2010-03-01 12:01:30 +00:00
|
|
|
comp->Action = comp->Installed;
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-03-06 09:05:09 +00:00
|
|
|
comp->Action = comp->ActionRequest;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
sourcename = MSI_RecordGetString(rec, 3);
|
|
|
|
options = MSI_RecordGetInteger(rec, 7);
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
sourcedir = msi_dup_property(package->db, MSI_RecordGetString(rec, 5));
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!sourcedir)
|
|
|
|
goto done;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
destdir = msi_dup_property(package->db, MSI_RecordGetString(rec, 6));
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!destdir)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (!sourcename)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
source = strdupW(sourcedir);
|
|
|
|
if (!source)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
|
|
|
|
source = msi_alloc(size * sizeof(WCHAR));
|
|
|
|
if (!source)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
lstrcpyW(source, sourcedir);
|
|
|
|
if (source[lstrlenW(source) - 1] != '\\')
|
|
|
|
lstrcatW(source, szBackSlash);
|
|
|
|
lstrcatW(source, sourcename);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
wildcards = strchrW(source, '*') || strchrW(source, '?');
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (MSI_RecordIsNull(rec, 4))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!wildcards)
|
|
|
|
{
|
|
|
|
destname = strdupW(sourcename);
|
|
|
|
if (!destname)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
destname = strdupW(MSI_RecordGetString(rec, 4));
|
|
|
|
if (destname)
|
|
|
|
reduce_to_longfilename(destname);
|
|
|
|
}
|
|
|
|
|
|
|
|
size = 0;
|
|
|
|
if (destname)
|
|
|
|
size = lstrlenW(destname);
|
|
|
|
|
|
|
|
size += lstrlenW(destdir) + 2;
|
|
|
|
dest = msi_alloc(size * sizeof(WCHAR));
|
|
|
|
if (!dest)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
lstrcpyW(dest, destdir);
|
|
|
|
if (dest[lstrlenW(dest) - 1] != '\\')
|
|
|
|
lstrcatW(dest, szBackSlash);
|
|
|
|
|
|
|
|
if (destname)
|
|
|
|
lstrcatW(dest, destname);
|
|
|
|
|
|
|
|
if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
|
|
|
|
{
|
|
|
|
ret = CreateDirectoryW(destdir, NULL);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
WARN("CreateDirectory failed: %d\n", GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!wildcards)
|
|
|
|
msi_move_file(source, dest, options);
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
2010-03-06 09:05:09 +00:00
|
|
|
move_files_wildcard(source, dest, options);
|
|
|
|
|
|
|
|
done:
|
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(rec, 1) );
|
|
|
|
MSI_RecordSetInteger( uirow, 6, 1 ); /* FIXME */
|
|
|
|
MSI_RecordSetStringW( uirow, 9, destdir );
|
|
|
|
ui_actiondata( package, szMoveFiles, uirow );
|
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free(sourcedir);
|
|
|
|
msi_free(destdir);
|
|
|
|
msi_free(destname);
|
|
|
|
msi_free(source);
|
|
|
|
msi_free(dest);
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT ACTION_MoveFiles( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
MSIQUERY *view;
|
|
|
|
|
|
|
|
static const WCHAR ExecSeqQuery[] =
|
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','M','o','v','e','F','i','l','e','`',0};
|
|
|
|
|
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const WCHAR *file_key, const WCHAR *src )
|
|
|
|
{
|
|
|
|
DWORD len;
|
|
|
|
WCHAR *dst_name, *dst_path, *dst;
|
|
|
|
|
|
|
|
if (MSI_RecordIsNull( row, 4 ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
len = strlenW( src ) + 1;
|
|
|
|
if (!(dst_name = msi_alloc( len * sizeof(WCHAR)))) return NULL;
|
|
|
|
strcpyW( dst_name, strrchrW( src, '\\' ) + 1 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MSI_RecordGetStringW( row, 4, NULL, &len );
|
|
|
|
if (!(dst_name = msi_alloc( ++len * sizeof(WCHAR) ))) return NULL;
|
|
|
|
MSI_RecordGetStringW( row, 4, dst_name, &len );
|
|
|
|
reduce_to_longfilename( dst_name );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (MSI_RecordIsNull( row, 5 ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
WCHAR *p;
|
|
|
|
dst_path = strdupW( src );
|
|
|
|
p = strrchrW( dst_path, '\\' );
|
|
|
|
if (p) *p = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
const WCHAR *dst_key = MSI_RecordGetString( row, 5 );
|
|
|
|
|
|
|
|
dst_path = resolve_folder( package, dst_key, FALSE, FALSE, TRUE, NULL );
|
|
|
|
if (!dst_path)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
/* try a property */
|
2010-05-29 08:55:43 +00:00
|
|
|
dst_path = msi_dup_property( package->db, dst_key );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!dst_path)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
FIXME("Unable to get destination folder, try AppSearch properties\n");
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( dst_name );
|
|
|
|
return NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
dst = build_directory_name( 2, dst_path, dst_name );
|
|
|
|
create_full_pathW( dst_path );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( dst_name );
|
|
|
|
msi_free( dst_path );
|
|
|
|
return dst;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPWSTR dest;
|
|
|
|
LPCWSTR file_key, component;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
MSIFILE *file;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
component = MSI_RecordGetString(row,2);
|
|
|
|
comp = get_loaded_component(package,component);
|
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!comp->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (comp->ActionRequest != INSTALLSTATE_LOCAL)
|
|
|
|
{
|
|
|
|
TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
|
|
|
|
comp->Action = comp->Installed;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
comp->Action = INSTALLSTATE_LOCAL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
file_key = MSI_RecordGetString(row,3);
|
|
|
|
if (!file_key)
|
|
|
|
{
|
|
|
|
ERR("Unable to get file key\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = get_loaded_file( package, file_key );
|
|
|
|
if (!file)
|
|
|
|
{
|
|
|
|
ERR("Original file unknown %s\n", debugstr_w(file_key));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
dest = get_duplicate_filename( package, row, file_key, file->TargetPath );
|
|
|
|
if (!dest)
|
|
|
|
{
|
|
|
|
WARN("Unable to get duplicate filename\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Duplicating file %s to %s\n", debugstr_w(file->TargetPath), debugstr_w(dest));
|
|
|
|
|
|
|
|
if (!CopyFileW( file->TargetPath, dest, TRUE ))
|
|
|
|
{
|
|
|
|
WARN("Failed to copy file %s -> %s (%u)\n",
|
|
|
|
debugstr_w(file->TargetPath), debugstr_w(dest), GetLastError());
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
FIXME("We should track these duplicate files as well\n");
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) );
|
|
|
|
MSI_RecordSetInteger( uirow, 6, file->FileSize );
|
|
|
|
MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) );
|
|
|
|
ui_actiondata( package, szDuplicateFiles, uirow );
|
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free(dest);
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
MSIQUERY * view;
|
|
|
|
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};
|
|
|
|
|
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_RemoveDuplicateFiles( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPWSTR dest;
|
|
|
|
LPCWSTR file_key, component;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 2 );
|
|
|
|
comp = get_loaded_component( package, component );
|
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!comp->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (comp->ActionRequest != INSTALLSTATE_ABSENT)
|
|
|
|
{
|
|
|
|
TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
|
|
|
|
comp->Action = comp->Installed;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
comp->Action = INSTALLSTATE_ABSENT;
|
|
|
|
|
|
|
|
file_key = MSI_RecordGetString( row, 3 );
|
|
|
|
if (!file_key)
|
|
|
|
{
|
|
|
|
ERR("Unable to get file key\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = get_loaded_file( package, file_key );
|
|
|
|
if (!file)
|
|
|
|
{
|
|
|
|
ERR("Original file unknown %s\n", debugstr_w(file_key));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest = get_duplicate_filename( package, row, file_key, file->TargetPath );
|
|
|
|
if (!dest)
|
|
|
|
{
|
|
|
|
WARN("Unable to get duplicate filename\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Removing duplicate %s of %s\n", debugstr_w(dest), debugstr_w(file->TargetPath));
|
|
|
|
|
|
|
|
if (!DeleteFileW( dest ))
|
|
|
|
{
|
|
|
|
WARN("Failed to delete duplicate file %s (%u)\n", debugstr_w(dest), GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) );
|
|
|
|
MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) );
|
|
|
|
ui_actiondata( package, szRemoveDuplicateFiles, uirow );
|
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free(dest);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
MSIQUERY *view;
|
|
|
|
static const WCHAR query[] =
|
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
|
|
|
|
|
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveDuplicateFiles, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static BOOL verify_comp_for_removal(MSICOMPONENT *comp, UINT install_mode)
|
|
|
|
{
|
|
|
|
INSTALLSTATE request = comp->ActionRequest;
|
|
|
|
|
|
|
|
if (request == INSTALLSTATE_UNKNOWN)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (install_mode == msidbRemoveFileInstallModeOnInstall &&
|
|
|
|
(request == INSTALLSTATE_LOCAL || request == INSTALLSTATE_SOURCE))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (request == INSTALLSTATE_ABSENT)
|
|
|
|
{
|
|
|
|
if (!comp->ComponentId)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (install_mode == msidbRemoveFileInstallModeOnRemove)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (install_mode == msidbRemoveFileInstallModeOnBoth)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2008-12-27 15:10:14 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2008-12-27 15:10:14 +00:00
|
|
|
LPCWSTR component, filename, dirprop;
|
|
|
|
UINT install_mode;
|
|
|
|
LPWSTR dir = NULL, path = NULL;
|
|
|
|
DWORD size;
|
2010-05-29 08:55:43 +00:00
|
|
|
UINT ret = ERROR_SUCCESS;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
component = MSI_RecordGetString(row, 2);
|
|
|
|
filename = MSI_RecordGetString(row, 3);
|
|
|
|
dirprop = MSI_RecordGetString(row, 4);
|
|
|
|
install_mode = MSI_RecordGetInteger(row, 5);
|
|
|
|
|
|
|
|
comp = get_loaded_component(package, component);
|
|
|
|
if (!comp)
|
|
|
|
{
|
|
|
|
ERR("Invalid component: %s\n", debugstr_w(component));
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!comp->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!verify_comp_for_removal(comp, install_mode))
|
|
|
|
{
|
|
|
|
TRACE("Skipping removal due to missing conditions\n");
|
|
|
|
comp->Action = comp->Installed;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
dir = msi_dup_property(package->db, dirprop);
|
2008-12-27 15:10:14 +00:00
|
|
|
if (!dir)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
size = (filename != NULL) ? lstrlenW(filename) : 0;
|
|
|
|
size += lstrlenW(dir) + 2;
|
|
|
|
path = msi_alloc(size * sizeof(WCHAR));
|
|
|
|
if (!path)
|
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
ret = ERROR_OUTOFMEMORY;
|
2008-12-27 15:10:14 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename)
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
lstrcpyW(path, dir);
|
|
|
|
PathAddBackslashW(path);
|
2008-12-27 15:10:14 +00:00
|
|
|
lstrcatW(path, filename);
|
|
|
|
|
|
|
|
TRACE("Deleting misc file: %s\n", debugstr_w(path));
|
|
|
|
DeleteFileW(path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
TRACE("Removing misc directory: %s\n", debugstr_w(dir));
|
|
|
|
RemoveDirectoryW(dir);
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(row, 1) );
|
|
|
|
MSI_RecordSetStringW( uirow, 9, dir );
|
|
|
|
ui_actiondata( package, szRemoveFiles, uirow );
|
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
msi_free(path);
|
|
|
|
msi_free(dir);
|
2010-05-29 08:55:43 +00:00
|
|
|
return ret;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT ACTION_RemoveFiles( MSIPACKAGE *package )
|
|
|
|
{
|
2008-12-27 15:10:14 +00:00
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIFILE *file;
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT r;
|
|
|
|
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','m','o','v','e','F','i','l','e','`',0};
|
2010-03-06 09:05:09 +00:00
|
|
|
static const WCHAR folder_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW(package->db, query, &view);
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
MSI_IterateRecords(view, NULL, ITERATE_RemoveFiles, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
r = MSI_DatabaseOpenViewW(package->db, folder_query, &view);
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIRECORD *uirow;
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
LPWSTR dir, p;
|
|
|
|
VS_FIXEDFILEINFO *ver;
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
if ( file->state == msifs_installed )
|
|
|
|
ERR("removing installed file %s\n", debugstr_w(file->TargetPath));
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if ( file->Component->ActionRequest != INSTALLSTATE_ABSENT ||
|
|
|
|
file->Component->Installed == INSTALLSTATE_SOURCE )
|
2006-02-17 00:04:10 +00:00
|
|
|
continue;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!file->Component->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
if (file->Version)
|
|
|
|
{
|
|
|
|
ver = msi_get_disk_file_version( file->TargetPath );
|
|
|
|
if (ver && msi_compare_file_versions( ver, file->Version ) > 0)
|
|
|
|
{
|
|
|
|
TRACE("newer version detected, not removing file\n");
|
|
|
|
msi_free( ver );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
msi_free( ver );
|
|
|
|
}
|
2006-08-30 19:24:26 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
TRACE("removing %s\n", debugstr_w(file->File) );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!DeleteFileW( file->TargetPath ))
|
|
|
|
{
|
|
|
|
WARN("failed to delete %s\n", debugstr_w(file->TargetPath));
|
|
|
|
}
|
|
|
|
/* FIXME: check persistence for each directory */
|
|
|
|
else if (r && (dir = strdupW( file->TargetPath )))
|
|
|
|
{
|
|
|
|
if ((p = strrchrW( dir, '\\' ))) *p = 0;
|
|
|
|
RemoveDirectoryW( dir );
|
|
|
|
msi_free( dir );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
file->state = msifs_missing;
|
2006-08-01 23:12:11 +00:00
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 9 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, file->FileName );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 9, file->Component->Directory );
|
|
|
|
ui_actiondata( package, szRemoveFiles, uirow );
|
2006-08-01 23:12:11 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
/* FIXME: call ui_progress here? */
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|