Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2718 lines
111 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
lnkmig.c
Abstract:
<abstract>
Author:
Calin Negreanu (calinn) 08 Mar 2000
Revision History:
<alias> <date> <comments>
--*/
//
// Includes
//
#include "pch.h"
#include "logmsg.h"
#include "lnkmig.h"
#define DBG_LINKS "Links"
//
// Strings
//
// None
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
// None
//
// Globals
//
PMHANDLE g_LinksPool = NULL;
MIG_ATTRIBUTEID g_LnkMigAttr_Shortcut = 0;
MIG_ATTRIBUTEID g_CopyIfRelevantAttr;
MIG_ATTRIBUTEID g_OsFileAttribute;
MIG_PROPERTYID g_LnkMigProp_Target = 0;
MIG_PROPERTYID g_LnkMigProp_Params = 0;
MIG_PROPERTYID g_LnkMigProp_WorkDir = 0;
MIG_PROPERTYID g_LnkMigProp_RawWorkDir = 0;
MIG_PROPERTYID g_LnkMigProp_IconPath = 0;
MIG_PROPERTYID g_LnkMigProp_IconNumber = 0;
MIG_PROPERTYID g_LnkMigProp_IconData = 0;
MIG_PROPERTYID g_LnkMigProp_HotKey = 0;
MIG_PROPERTYID g_LnkMigProp_DosApp = 0;
MIG_PROPERTYID g_LnkMigProp_MsDosMode = 0;
MIG_PROPERTYID g_LnkMigProp_ExtraData = 0;
MIG_OPERATIONID g_LnkMigOp_FixContent;
IShellLink *g_ShellLink = NULL;
IPersistFile *g_PersistFile = NULL;
BOOL g_VcmMode = FALSE;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Private prototypes
//
MIG_OBJECTENUMCALLBACK LinksCallback;
MIG_PREENUMCALLBACK LnkMigPreEnumeration;
MIG_POSTENUMCALLBACK LnkMigPostEnumeration;
OPMAPPLYCALLBACK DoLnkContentFix;
MIG_RESTORECALLBACK LinkRestoreCallback;
BOOL
LinkDoesContentMatch (
IN BOOL AlreadyProcessed,
IN MIG_OBJECTTYPEID SrcObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
IN PMIG_CONTENT SrcContent,
IN MIG_OBJECTTYPEID DestObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE DestObjectName,
IN PMIG_CONTENT DestContent,
OUT PBOOL Identical,
OUT PBOOL DifferentDetailsOnly
);
//
// Code
//
BOOL
pIsUncPath (
IN PCTSTR Path
)
{
return (Path && (Path[0] == TEXT('\\')) && (Path[1] == TEXT('\\')));
}
BOOL
LinksInitialize (
VOID
)
{
g_LinksPool = PmCreateNamedPool ("Links");
return (g_LinksPool != NULL);
}
VOID
LinksTerminate (
VOID
)
{
if (g_LinksPool) {
PmDestroyPool (g_LinksPool);
g_LinksPool = NULL;
}
}
BOOL
pCommonInitialize (
IN PMIG_LOGCALLBACK LogCallback
)
{
LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
g_LnkMigProp_RawWorkDir = IsmRegisterProperty (S_LNKMIGPROP_RAWWORKDIR, FALSE);
g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
return TRUE;
}
BOOL
WINAPI
LnkMigVcmInitialize (
IN PMIG_LOGCALLBACK LogCallback,
IN PVOID Reserved
)
{
g_VcmMode = TRUE;
return pCommonInitialize (LogCallback);
}
BOOL
WINAPI
LnkMigSgmInitialize (
IN PMIG_LOGCALLBACK LogCallback,
IN PVOID Reserved
)
{
return pCommonInitialize (LogCallback);
}
BOOL
LnkMigPreEnumeration (
VOID
)
{
if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
}
return TRUE;
}
BOOL
LnkMigPostEnumeration (
VOID
)
{
FreeCOMLink (&g_ShellLink, &g_PersistFile);
g_ShellLink = NULL;
g_PersistFile = NULL;
return TRUE;
}
MIG_OBJECTSTRINGHANDLE
pBuildEncodedNameFromNativeName (
IN PCTSTR NativeName
)
{
PCTSTR nodeName;
PTSTR leafName;
MIG_OBJECTSTRINGHANDLE result = NULL;
MIG_OBJECT_ENUM objEnum;
result = IsmCreateObjectHandle (NativeName, NULL);
if (result) {
if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) {
IsmAbortObjectEnum (&objEnum);
return result;
}
IsmDestroyObjectHandle (result);
result = NULL;
}
// we have to split this path because it could be a file
nodeName = DuplicatePathString (NativeName, 0);
leafName = _tcsrchr (nodeName, TEXT('\\'));
if (leafName) {
*leafName = 0;
leafName ++;
result = IsmCreateObjectHandle (nodeName, leafName);
} else {
// we have no \ in the name. This can only mean that the
// file specification has only a leaf
result = IsmCreateObjectHandle (NULL, NativeName);
}
FreePathString (nodeName);
return result;
}
PCTSTR
pSpecialExpandEnvironmentString (
IN PCTSTR SrcString,
IN PCTSTR Context
)
{
PCTSTR result = NULL;
PCTSTR srcWinDir = NULL;
PCTSTR destWinDir = NULL;
PTSTR newSrcString = NULL;
PCTSTR copyPtr = NULL;
if (IsmGetRealPlatform () == PLATFORM_DESTINATION) {
// Special case where this is actually the destination machine and
// first part of SrcString matches %windir%. In this case, it is likely that
// the shell replaced the source windows directory with the destination one.
// We need to change it back
destWinDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
if (destWinDir) {
if (StringIPrefix (SrcString, destWinDir)) {
srcWinDir = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
if (srcWinDir) {
newSrcString = IsmGetMemory (SizeOfString (srcWinDir) + SizeOfString (SrcString));
if (newSrcString) {
copyPtr = SrcString + TcharCount (destWinDir);
StringCopy (newSrcString, srcWinDir);
StringCat (newSrcString, copyPtr);
}
IsmReleaseMemory (srcWinDir);
srcWinDir = NULL;
}
}
IsmReleaseMemory (destWinDir);
destWinDir = NULL;
}
}
result = IsmExpandEnvironmentString (
PLATFORM_SOURCE,
S_SYSENVVAR_GROUP,
newSrcString?newSrcString:SrcString,
Context
);
if (newSrcString) {
IsmReleaseMemory (newSrcString);
}
return result;
}
MIG_OBJECTSTRINGHANDLE
pTryObject (
IN PCTSTR LeafName,
IN PCTSTR EnvName
)
{
MIG_OBJECT_ENUM objEnum;
PTSTR envData = NULL;
DWORD envSize = 0;
PATH_ENUM pathEnum;
MIG_OBJECTSTRINGHANDLE result = NULL;
if (IsmGetEnvironmentString (
PLATFORM_SOURCE,
S_SYSENVVAR_GROUP,
EnvName,
NULL,
0,
&envSize
)) {
envData = IsmGetMemory (envSize);
if (envData) {
if (IsmGetEnvironmentString (
PLATFORM_SOURCE,
S_SYSENVVAR_GROUP,
EnvName,
envData,
envSize,
&envSize
)) {
// let's enumerate the paths from this env variable (should be separated by ;)
if (EnumFirstPathEx (&pathEnum, envData, NULL, NULL, FALSE)) {
do {
result = IsmCreateObjectHandle (pathEnum.PtrCurrPath, LeafName);
if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) {
IsmAbortObjectEnum (&objEnum);
} else {
IsmDestroyObjectHandle (result);
result = NULL;
}
if (result) {
AbortPathEnum (&pathEnum);
break;
}
} while (EnumNextPath (&pathEnum));
}
}
IsmReleaseMemory (envData);
envData = NULL;
}
}
return result;
}
MIG_OBJECTSTRINGHANDLE
pGetFullEncodedName (
IN MIG_OBJECTSTRINGHANDLE ObjectName
)
{
PCTSTR node = NULL, leaf = NULL;
MIG_OBJECTSTRINGHANDLE result = NULL;
// let's split the ObjectName into node and leaf.
// If it's leaf only we are going to try to find
// that leaf in %path%, %windir% and %system% and
// reconstruct the object name.
if (IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf)) {
if (!node) {
// this is leaf only. We need to find out where this leaf
// is located. We are going to look for the leaf in the
// following directories (in this order)
// 1. %system%
// 2. %system16%
// 3. %windir%
// 4. All directories in %path% env. variable
result = pTryObject (leaf, TEXT("system"));
if (!result) {
result = pTryObject (leaf, TEXT("system16"));
}
if (!result) {
result = pTryObject (leaf, TEXT("windir"));
}
if (!result) {
result = pTryObject (leaf, TEXT("path"));
}
}
IsmDestroyObjectString (node);
IsmDestroyObjectString (leaf);
}
return result;
}
BOOL
pIsLnkExcluded (
IN MIG_OBJECTID ObjectId,
IN PCTSTR Target,
IN PCTSTR Params,
IN PCTSTR WorkDir
)
{
PTSTR multiSz = NULL;
MULTISZ_ENUM e;
UINT sizeNeeded;
HINF infHandle = INVALID_HANDLE_VALUE;
ENVENTRY_TYPE dataType;
INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
PCTSTR targetPattern = NULL;
PCTSTR targetPatternExp = NULL;
PCTSTR paramsPattern = NULL;
PCTSTR paramsPatternExp = NULL;
PCTSTR workDirPattern = NULL;
PCTSTR workDirPatternExp = NULL;
BOOL result = FALSE;
if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) {
// let's look in the INFs in section [ExcludedLinks] and see if our LNK matches
// one of the lines. If it does and it has the CopyIfRelevand attribute then
// it's excluded
if (IsmGetEnvironmentValue (
IsmGetRealPlatform (),
NULL,
S_GLOBAL_INF_HANDLE,
(PBYTE)(&infHandle),
sizeof (HINF),
&sizeNeeded,
&dataType
) &&
(sizeNeeded == sizeof (HINF)) &&
(dataType == ENVENTRY_BINARY)
) {
if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
do {
targetPattern = InfGetStringField (&is, 1);
targetPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, targetPattern, NULL);
if (!targetPatternExp) {
targetPatternExp = targetPattern;
}
paramsPattern = InfGetStringField (&is, 2);
paramsPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, paramsPattern, NULL);
if (!paramsPatternExp) {
paramsPatternExp = paramsPattern;
}
workDirPattern = InfGetStringField (&is, 3);
workDirPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, workDirPattern, NULL);
if (!workDirPatternExp) {
workDirPatternExp = workDirPattern;
}
if (IsPatternMatch (targetPatternExp?targetPatternExp:TEXT("*"), Target?Target:TEXT("")) &&
IsPatternMatch (paramsPatternExp?paramsPatternExp:TEXT("*"), Params?Params:TEXT("")) &&
IsPatternMatch (workDirPatternExp?workDirPatternExp:TEXT("*"), WorkDir?WorkDir:TEXT(""))
) {
result = TRUE;
if (workDirPatternExp && (workDirPatternExp != workDirPattern)) {
IsmReleaseMemory (workDirPatternExp);
workDirPatternExp = NULL;
}
if (paramsPatternExp && (paramsPatternExp != paramsPattern)) {
IsmReleaseMemory (paramsPatternExp);
paramsPatternExp = NULL;
}
if (targetPatternExp && (targetPatternExp != targetPattern)) {
IsmReleaseMemory (targetPatternExp);
targetPatternExp = NULL;
}
break;
}
if (workDirPatternExp && (workDirPatternExp != workDirPattern)) {
IsmReleaseMemory (workDirPatternExp);
workDirPatternExp = NULL;
}
if (paramsPatternExp && (paramsPatternExp != paramsPattern)) {
IsmReleaseMemory (paramsPatternExp);
paramsPatternExp = NULL;
}
if (targetPatternExp && (targetPatternExp != targetPattern)) {
IsmReleaseMemory (targetPatternExp);
targetPatternExp = NULL;
}
} while (InfFindNextLine (&is));
}
InfNameHandle (infHandle, NULL, FALSE);
} else {
if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) {
__try {
multiSz = AllocText (sizeNeeded);
if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) {
__leave;
}
if (EnumFirstMultiSz (&e, multiSz)) {
do {
infHandle = InfOpenInfFile (e.CurrentString);
if (infHandle != INVALID_HANDLE_VALUE) {
if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
do {
targetPattern = InfGetStringField (&is, 1);
paramsPattern = InfGetStringField (&is, 2);
workDirPattern = InfGetStringField (&is, 3);
if (IsPatternMatch (targetPattern?targetPattern:TEXT("*"), Target?Target:TEXT("")) &&
IsPatternMatch (paramsPattern?paramsPattern:TEXT("*"), Params?Params:TEXT("")) &&
IsPatternMatch (workDirPattern?workDirPattern:TEXT("*"), WorkDir?WorkDir:TEXT(""))
) {
result = TRUE;
break;
}
} while (InfFindNextLine (&is));
}
}
InfCloseInfFile (infHandle);
infHandle = INVALID_HANDLE_VALUE;
if (result) {
break;
}
} while (EnumNextMultiSz (&e));
}
}
__finally {
FreeText (multiSz);
}
}
}
InfResetInfStruct (&is);
}
return result;
}
UINT
LinksCallback (
IN PCMIG_OBJECTENUMDATA Data,
IN ULONG_PTR CallerArg
)
{
MIG_OBJECTID objectId;
BOOL extractResult = FALSE;
PCTSTR lnkTarget = NULL;
PCTSTR newLnkTarget = NULL;
PCTSTR expLnkTarget = NULL;
PCTSTR lnkParams = NULL;
PCTSTR lnkWorkDir = NULL;
PCTSTR lnkIconPath = NULL;
INT lnkIconNumber;
WORD lnkHotKey;
BOOL lnkDosApp;
BOOL lnkMsDosMode;
LNK_EXTRA_DATA lnkExtraData;
MIG_OBJECTSTRINGHANDLE encodedName;
MIG_OBJECTSTRINGHANDLE longEncodedName;
MIG_OBJECTSTRINGHANDLE fullEncodedName;
MIG_BLOB migBlob;
PCTSTR expTmpStr;
MIG_CONTENT lnkContent;
MIG_CONTENT lnkIconContent;
PICON_GROUP iconGroup = NULL;
ICON_SGROUP iconSGroup;
PCTSTR lnkIconResId = NULL;
PCTSTR extPtr = NULL;
BOOL exeDefaultIcon = FALSE;
if (Data->IsLeaf) {
objectId = IsmGetObjectIdFromName (MIG_FILE_TYPE, Data->ObjectName, TRUE);
if (IsmIsPersistentObjectId (objectId)) {
IsmSetAttributeOnObjectId (objectId, g_LnkMigAttr_Shortcut);
if (IsmAcquireObjectEx (
Data->ObjectTypeId,
Data->ObjectName,
&lnkContent,
CONTENTTYPE_FILE,
0
)) {
if (lnkContent.ContentInFile && lnkContent.FileContent.ContentPath) {
if (ExtractShortcutInfo (
lnkContent.FileContent.ContentPath,
&lnkTarget,
&lnkParams,
&lnkWorkDir,
&lnkIconPath,
&lnkIconNumber,
&lnkHotKey,
&lnkDosApp,
&lnkMsDosMode,
&lnkExtraData,
g_ShellLink,
g_PersistFile
)) {
// let's check if the LNK is excluded
if (pIsLnkExcluded (
objectId,
lnkTarget,
lnkParams,
lnkWorkDir
)) {
IsmClearPersistenceOnObjectId (objectId);
} else {
// let's get all the paths through the hooks and add everything as properties of this shortcut
if (lnkTarget) {
if (*lnkTarget) {
// If we are on the destination system, we are going to have major problems here.
// If the LNK had IDLISTs, we are going to get back a path that's local to the
// destination machine. For example if the target was c:\Windows\Favorites on the
// source system and that was the CSIDL_FAVORITES we are going to get back:
// c:\Documents and Settings\username\Favorites.
// Because of this problem we need to compress the path and then expand it back
// using env. variables from the source system.
if (IsmGetRealPlatform () == PLATFORM_DESTINATION) {
newLnkTarget = IsmCompressEnvironmentString (
PLATFORM_DESTINATION,
S_SYSENVVAR_GROUP,
lnkTarget,
Data->NativeObjectName,
TRUE
);
}
// let's look if this is a valid file specification. If it is not, it might be
// an URL or something else, so we will just migrate the thing
expTmpStr = pSpecialExpandEnvironmentString (newLnkTarget?newLnkTarget:lnkTarget, Data->NativeObjectName);
if (IsValidFileSpec (expTmpStr)) {
// we are going to need this (maybe) later, if the icon path is NULL and this is an EXE
expLnkTarget = DuplicatePathString (expTmpStr, 0);
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
if (!longEncodedName) {
longEncodedName = encodedName;
}
IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = longEncodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob);
} else {
// persist the target so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
}
}
if (longEncodedName != encodedName) {
IsmDestroyObjectHandle (longEncodedName);
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
}
} else {
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = encodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob);
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
}
}
if (newLnkTarget) {
IsmReleaseMemory (newLnkTarget);
newLnkTarget = NULL;
}
IsmReleaseMemory (expTmpStr);
expTmpStr = NULL;
} else {
if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
IsmClearPersistenceOnObjectId (objectId);
}
}
FreePathString (lnkTarget);
} else {
if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
IsmClearPersistenceOnObjectId (objectId);
}
}
if (lnkParams) {
if (*lnkParams) {
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = lnkParams;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Params, &migBlob);
}
}
FreePathString (lnkParams);
}
if (lnkWorkDir) {
if (*lnkWorkDir) {
// let's save the raw working directory
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = lnkWorkDir;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_RawWorkDir, &migBlob);
}
expTmpStr = pSpecialExpandEnvironmentString (lnkWorkDir, Data->NativeObjectName);
if (IsValidFileSpec (expTmpStr)) {
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
if (!longEncodedName) {
longEncodedName = encodedName;
}
IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = longEncodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob);
} else {
// persist the working directory (it has almost no space impact)
// so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
}
}
if (longEncodedName != encodedName) {
IsmDestroyObjectHandle (longEncodedName);
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
}
} else {
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = encodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob);
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
}
}
IsmReleaseMemory (expTmpStr);
expTmpStr = NULL;
}
FreePathString (lnkWorkDir);
}
if (((!lnkIconPath) || (!(*lnkIconPath))) && expLnkTarget) {
extPtr = GetFileExtensionFromPath (expLnkTarget);
if (extPtr) {
exeDefaultIcon = StringIMatch (extPtr, TEXT("EXE"));
if (exeDefaultIcon) {
if (lnkIconPath) {
FreePathString (lnkIconPath);
}
lnkIconPath = expLnkTarget;
}
}
}
if (lnkIconPath) {
if (*lnkIconPath) {
// let's look if this is a valid file specification. If it is not, it might be
// an URL or something else, so we will just migrate the thing
expTmpStr = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, lnkIconPath, Data->NativeObjectName);
if (IsValidFileSpec (expTmpStr)) {
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
if (!longEncodedName) {
longEncodedName = encodedName;
}
// Sometimes the icon is specified without full path (like foo.dll instead
// of c:\windows\system\foo.dll). When this is the case we are going to
// walk the %path% and %windir% and %system% and try to find the file there.
fullEncodedName = pGetFullEncodedName (longEncodedName);
if (fullEncodedName) {
if (longEncodedName != encodedName) {
IsmDestroyObjectHandle (longEncodedName);
}
longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, fullEncodedName);
if (!longEncodedName) {
longEncodedName = fullEncodedName;
} else {
IsmDestroyObjectHandle (fullEncodedName);
fullEncodedName = NULL;
}
}
IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
if (!g_VcmMode) {
if (!exeDefaultIcon) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = longEncodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob);
}
// one last thing: let's extract the icon and preserve it just in case.
if (IsmAcquireObjectEx (
MIG_FILE_TYPE,
longEncodedName,
&lnkIconContent,
CONTENTTYPE_FILE,
0
)) {
if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) {
if (lnkIconNumber >= 0) {
iconGroup = IcoExtractIconGroupByIndexFromFile (
lnkIconContent.FileContent.ContentPath,
lnkIconNumber,
NULL
);
} else {
lnkIconResId = (PCTSTR) (LONG_PTR) (-lnkIconNumber);
iconGroup = IcoExtractIconGroupFromFile (
lnkIconContent.FileContent.ContentPath,
lnkIconResId,
NULL
);
}
if (iconGroup) {
if (IcoSerializeIconGroup (iconGroup, &iconSGroup)) {
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(iconSGroup.Data);
migBlob.BinarySize = iconSGroup.DataSize;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconData, &migBlob);
IcoReleaseIconSGroup (&iconSGroup);
}
IcoReleaseIconGroup (iconGroup);
}
}
IsmReleaseObject (&lnkIconContent);
}
} else {
// persist the icon file so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
}
}
if (longEncodedName != encodedName) {
IsmDestroyObjectHandle (longEncodedName);
longEncodedName = NULL;
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
encodedName = NULL;
}
} else {
encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
if (!g_VcmMode) {
if (!exeDefaultIcon) {
migBlob.Type = BLOBTYPE_STRING;
migBlob.String = encodedName;
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob);
}
}
if (encodedName) {
IsmDestroyObjectHandle (encodedName);
}
}
IsmReleaseMemory (expTmpStr);
expTmpStr = NULL;
}
if (lnkIconPath != expLnkTarget) {
FreePathString (lnkIconPath);
}
}
if (!g_VcmMode) {
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(&lnkIconNumber);
migBlob.BinarySize = sizeof (INT);
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconNumber, &migBlob);
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(&lnkDosApp);
migBlob.BinarySize = sizeof (BOOL);
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_DosApp, &migBlob);
if (lnkDosApp) {
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(&lnkMsDosMode);
migBlob.BinarySize = sizeof (BOOL);
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_MsDosMode, &migBlob);
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(&lnkExtraData);
migBlob.BinarySize = sizeof (LNK_EXTRA_DATA);
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_ExtraData, &migBlob);
} else {
migBlob.Type = BLOBTYPE_BINARY;
migBlob.BinaryData = (PCBYTE)(&lnkHotKey);
migBlob.BinarySize = sizeof (WORD);
IsmAddPropertyToObjectId (objectId, g_LnkMigProp_HotKey, &migBlob);
}
IsmSetOperationOnObjectId (
objectId,
g_LnkMigOp_FixContent,
NULL,
NULL
);
}
if (expLnkTarget) {
FreePathString (expLnkTarget);
expLnkTarget = NULL;
}
}
} else {
if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
IsmClearPersistenceOnObjectId (objectId);
}
}
} else {
if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
IsmClearPersistenceOnObjectId (objectId);
}
}
IsmReleaseObject (&lnkContent);
} else {
if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
IsmClearPersistenceOnObjectId (objectId);
}
}
}
}
return CALLBACK_ENUM_CONTINUE;
}
BOOL
pCommonLnkMigQueueEnumeration (
VOID
)
{
ENCODEDSTRHANDLE pattern;
// hook all LNK files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.lnk"), TRUE);
if (pattern) {
IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
IsmDestroyObjectHandle (pattern);
}
// hook all PIF files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.pif"), TRUE);
if (pattern) {
IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
IsmDestroyObjectHandle (pattern);
}
// hook all URL files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.url"), TRUE);
if (pattern) {
IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
IsmDestroyObjectHandle (pattern);
}
IsmRegisterPreEnumerationCallback (LnkMigPreEnumeration, NULL);
IsmRegisterPostEnumerationCallback (LnkMigPostEnumeration, NULL);
return TRUE;
}
BOOL
WINAPI
LnkMigVcmQueueEnumeration (
IN PVOID Reserved
)
{
return pCommonLnkMigQueueEnumeration ();
}
BOOL
WINAPI
LnkMigSgmQueueEnumeration (
IN PVOID Reserved
)
{
return pCommonLnkMigQueueEnumeration ();
}
BOOL
pLnkFindFile (
IN PCTSTR FileName
)
{
MIG_OBJECTSTRINGHANDLE objectName;
PTSTR node, leaf, leafPtr;
BOOL result = FALSE;
objectName = IsmCreateObjectHandle (FileName, NULL);
if (objectName) {
if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) {
result = TRUE;
}
IsmDestroyObjectHandle (objectName);
}
if (!result) {
node = DuplicateText (FileName);
leaf = _tcsrchr (node, TEXT('\\'));
if (leaf) {
leafPtr = (PTSTR) leaf;
leaf = _tcsinc (leaf);
*leafPtr = 0;
objectName = IsmCreateObjectHandle (node, leaf);
if (objectName) {
if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) {
result = TRUE;
}
IsmDestroyObjectHandle (objectName);
}
*leafPtr = TEXT('\\');
}
FreeText (node);
}
return result;
}
BOOL
pLnkSearchPath (
IN PCTSTR FileName,
IN DWORD BufferLength,
OUT PTSTR Buffer
)
{
return FALSE;
}
MIG_OBJECTSTRINGHANDLE
pLnkSimpleTryHandle (
IN PCTSTR FullPath
)
{
PCTSTR buffer;
PTSTR leafPtr, leaf;
MIG_OBJECTSTRINGHANDLE source = NULL;
MIG_OBJECTSTRINGHANDLE result = NULL;
PTSTR workingPath;
PCTSTR sanitizedPath;
BOOL orgDeleted = FALSE;
BOOL orgReplaced = FALSE;
PCTSTR saved = NULL;
sanitizedPath = SanitizePath (FullPath);
if (!sanitizedPath) {
return NULL;
}
source = IsmCreateObjectHandle (sanitizedPath, NULL);
if (source) {
result = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
source,
NULL,
&orgDeleted,
&orgReplaced
);
// we do not want replaced directories
// since they can be false hits
if (orgDeleted) {
if (result) {
saved = result;
result = NULL;
}
}
if (!result && !orgDeleted) {
result = source;
} else {
IsmDestroyObjectHandle (source);
source = NULL;
}
}
if (result) {
goto exit;
}
buffer = DuplicatePathString (sanitizedPath, 0);
leaf = _tcsrchr (buffer, TEXT('\\'));
if (leaf) {
leafPtr = leaf;
leaf = _tcsinc (leaf);
*leafPtr = 0;
source = IsmCreateObjectHandle (buffer, leaf);
*leafPtr = TEXT('\\');
}
FreePathString (buffer);
if (source) {
result = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
source,
NULL,
&orgDeleted,
&orgReplaced
);
if (!result && !orgDeleted) {
result = source;
} else {
if (!result) {
result = saved;
}
IsmDestroyObjectHandle (source);
source = NULL;
}
}
if (result != saved) {
IsmDestroyObjectHandle (saved);
saved = NULL;
}
exit:
FreePathString (sanitizedPath);
return result;
}
MIG_OBJECTSTRINGHANDLE
pLnkTryHandle (
IN PCTSTR FullPath,
IN PCTSTR Hint,
OUT PCTSTR *TrimmedResult
)
{
PATH_ENUM pathEnum;
PCTSTR newPath;
MIG_OBJECTSTRINGHANDLE result = NULL;
PCTSTR nativeName = NULL;
PCTSTR lastSegPtr;
if (TrimmedResult) {
*TrimmedResult = NULL;
}
result = pLnkSimpleTryHandle (FullPath);
if (result || (!Hint)) {
return result;
}
if (EnumFirstPathEx (&pathEnum, Hint, NULL, NULL, FALSE)) {
do {
newPath = JoinPaths (pathEnum.PtrCurrPath, FullPath);
result = pLnkSimpleTryHandle (newPath);
if (result) {
AbortPathEnum (&pathEnum);
FreePathString (newPath);
// now, if the initial FullPath did not have any wack in it
// we will take the last segment of the result and put it
// in TrimmedResult
if (TrimmedResult && (!_tcschr (FullPath, TEXT('\\')))) {
nativeName = IsmGetNativeObjectName (MIG_FILE_TYPE, result);
if (nativeName) {
lastSegPtr = _tcsrchr (nativeName, TEXT('\\'));
if (lastSegPtr) {
lastSegPtr = _tcsinc (lastSegPtr);
if (lastSegPtr) {
*TrimmedResult = DuplicatePathString (lastSegPtr, 0);
}
}
}
}
return result;
}
FreePathString (newPath);
} while (EnumNextPath (&pathEnum));
}
AbortPathEnum (&pathEnum);
return NULL;
}
PCTSTR
pFilterBuffer (
IN PCTSTR SourceBuffer,
IN PCTSTR HintBuffer
)
{
PCTSTR result = NULL;
PCTSTR expBuffer = NULL;
MIG_OBJECTSTRINGHANDLE destination;
PCTSTR trimmedResult = NULL;
BOOL replaced = FALSE;
BOOL orgDeleted = FALSE;
BOOL orgReplaced = FALSE;
GROWBUFFER resultBuffer = INIT_GROWBUFFER;
PCTSTR nativeDest;
BOOL newContent = TRUE;
PCTSTR destResult = NULL;
PCTSTR newData, oldData;
PCMDLINE cmdLine;
GROWBUFFER cmdLineBuffer = INIT_GROWBUFFER;
UINT u;
PCTSTR p;
expBuffer = IsmExpandEnvironmentString (
PLATFORM_SOURCE,
S_SYSENVVAR_GROUP,
SourceBuffer,
NULL
);
if (expBuffer) {
destination = pLnkTryHandle (expBuffer, HintBuffer, &trimmedResult);
if (destination) {
replaced = TRUE;
if (trimmedResult) {
GbAppendString (&resultBuffer, trimmedResult);
FreePathString (trimmedResult);
} else {
nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination);
GbAppendString (&resultBuffer, nativeDest);
IsmReleaseMemory (nativeDest);
}
}
// finally, if we failed we are going to assume it's a command line
if (!replaced) {
newData = DuplicatePathString (expBuffer, 0);
cmdLine = ParseCmdLineEx (expBuffer, NULL, &pLnkFindFile, &pLnkSearchPath, &cmdLineBuffer);
if (cmdLine) {
//
// Find the file referenced in the list or command line
//
for (u = 0 ; u < cmdLine->ArgCount ; u++) {
p = cmdLine->Args[u].CleanedUpArg;
// first we try it as is
destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
// maybe we have something like /m:c:\foo.txt
// we need to go forward until we find a sequence of
// <alpha>:\<something>
if (!destination && p[0] && p[1]) {
while (p[2]) {
if (_istalpha ((CHARTYPE) _tcsnextc (p)) &&
p[1] == TEXT(':') &&
p[2] == TEXT('\\')
) {
destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
if (destination) {
break;
}
}
p ++;
}
}
if (destination) {
replaced = TRUE;
if (trimmedResult) {
oldData = StringSearchAndReplace (newData, p, trimmedResult);
if (oldData) {
FreePathString (newData);
newData = oldData;
}
FreePathString (trimmedResult);
} else {
nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination);
oldData = StringSearchAndReplace (newData, p, nativeDest);
if (oldData) {
FreePathString (newData);
newData = oldData;
}
IsmReleaseMemory (nativeDest);
}
IsmDestroyObjectHandle (destination);
destination = NULL;
}
}
}
GbFree (&cmdLineBuffer);
if (!replaced) {
if (newData) {
FreePathString (newData);
}
} else {
if (newData) {
GbAppendString (&resultBuffer, newData);
FreePathString (newData);
}
}
}
if (destination) {
IsmDestroyObjectHandle (destination);
destination = NULL;
}
if (replaced && resultBuffer.Buf) {
// looks like we have new content
// Let's do one more check. If this is a REG_EXPAND_SZ we will do our best to
// keep the stuff unexpanded. So if the source string expanded on the destination
// machine is the same as the destination string we won't do anything.
newContent = TRUE;
destResult = IsmExpandEnvironmentString (
PLATFORM_DESTINATION,
S_SYSENVVAR_GROUP,
SourceBuffer,
NULL
);
if (destResult && StringIMatch (destResult, (PCTSTR)resultBuffer.Buf)) {
newContent = FALSE;
}
if (destResult) {
IsmReleaseMemory (destResult);
destResult = NULL;
}
if (newContent) {
result = DuplicatePathString ((PCTSTR)resultBuffer.Buf, 0);
}
}
GbFree (&resultBuffer);
}
return result;
}
BOOL
WINAPI
DoLnkContentFix (
IN MIG_OBJECTTYPEID SrcObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
IN PCMIG_CONTENT OriginalContent,
IN PCMIG_CONTENT CurrentContent,
OUT PMIG_CONTENT NewContent,
IN PCMIG_BLOB SourceOperationData, OPTIONAL
IN PCMIG_BLOB DestinationOperationData OPTIONAL
)
{
MIG_PROPERTYDATAID propDataId;
MIG_BLOBTYPE propDataType;
UINT requiredSize;
BOOL lnkTargetPresent = FALSE;
PCTSTR lnkTargetNode = NULL;
PCTSTR lnkTargetLeaf = NULL;
PCTSTR objectNode = NULL;
PCTSTR objectLeaf = NULL;
MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
MIG_OBJECTTYPEID lnkTargetDestType = 0;
MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
BOOL lnkTargetDestDel = FALSE;
BOOL lnkTargetDestRepl = FALSE;
PCTSTR lnkTargetDestNative = NULL;
PCTSTR lnkParams = NULL;
PCTSTR lnkParamsNew = NULL;
MIG_OBJECTSTRINGHANDLE lnkWorkDir = NULL;
MIG_OBJECTTYPEID lnkWorkDirDestType = 0;
MIG_OBJECTSTRINGHANDLE lnkWorkDirDest = NULL;
BOOL lnkWorkDirDestDel = FALSE;
BOOL lnkWorkDirDestRepl = FALSE;
PCTSTR lnkWorkDirDestNative = NULL;
PCTSTR lnkRawWorkDir = NULL;
PCTSTR lnkRawWorkDirExp = NULL;
MIG_OBJECTSTRINGHANDLE lnkIconPath = NULL;
MIG_OBJECTTYPEID lnkIconPathDestType = 0;
MIG_OBJECTSTRINGHANDLE lnkIconPathDest = NULL;
BOOL lnkIconPathDestDel = FALSE;
BOOL lnkIconPathDestRepl = FALSE;
PCTSTR lnkIconPathDestNative = NULL;
INT lnkIconNumber = 0;
PICON_GROUP lnkIconGroup = NULL;
ICON_SGROUP lnkIconSGroup = {0, NULL};
WORD lnkHotKey = 0;
BOOL lnkDosApp = FALSE;
BOOL lnkMsDosMode = FALSE;
PLNK_EXTRA_DATA lnkExtraData = NULL;
BOOL comInit = FALSE;
BOOL modifyFile = FALSE;
PTSTR iconLibPath = NULL;
PTSTR newShortcutPath = NULL;
MIG_CONTENT lnkIconContent;
// now it's finally time to fix the LNK file content
if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) {
comInit = TRUE;
if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
return TRUE;
}
}
// first, retrieve the properties
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Target);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Params);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkParams = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkParams, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_WorkDir);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkWorkDir = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkWorkDir, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkRawWorkDir = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkRawWorkDir, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconPath);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkIconPath = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkIconPath, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconNumber);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
if (requiredSize == sizeof (INT)) {
IsmGetPropertyData (propDataId, (PBYTE)(&lnkIconNumber), requiredSize, NULL, &propDataType);
}
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconData);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkIconSGroup.DataSize = requiredSize;
lnkIconSGroup.Data = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkIconSGroup.Data, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_HotKey);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
if (requiredSize == sizeof (WORD)) {
IsmGetPropertyData (propDataId, (PBYTE)(&lnkHotKey), requiredSize, NULL, &propDataType);
}
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_DosApp);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
if (requiredSize == sizeof (BOOL)) {
IsmGetPropertyData (propDataId, (PBYTE)(&lnkDosApp), requiredSize, NULL, &propDataType);
}
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_MsDosMode);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
if (requiredSize == sizeof (BOOL)) {
IsmGetPropertyData (propDataId, (PBYTE)(&lnkMsDosMode), requiredSize, NULL, &propDataType);
}
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_ExtraData);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkExtraData = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkExtraData, requiredSize, NULL, &propDataType);
}
}
// let's examine the target, see if it was migrated
if (lnkTarget) {
lnkTargetDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
lnkTarget,
&lnkTargetDestType,
&lnkTargetDestDel,
&lnkTargetDestRepl
);
if (((lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE)) &&
((lnkTargetDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
) {
if (lnkTargetDest) {
// the target changed location, we need to adjust the link
modifyFile = TRUE;
lnkTargetDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTargetDest);
}
}
lnkTargetPresent = !lnkTargetDestDel;
}
// let's examine the parameters
if (lnkParams) {
lnkParamsNew = pFilterBuffer (lnkParams, NULL);
if (lnkParamsNew) {
modifyFile = TRUE;
}
}
// let's examine the working directory
if (lnkWorkDir) {
lnkWorkDirDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
lnkWorkDir,
&lnkWorkDirDestType,
&lnkWorkDirDestDel,
&lnkWorkDirDestRepl
);
if (((lnkWorkDirDestDel == FALSE) || (lnkWorkDirDestRepl == TRUE)) &&
((lnkWorkDirDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
) {
if (lnkWorkDirDest) {
// the working directory changed location
// Normally we would want to adjust the link's working directory
// to point to the new location. However, let's take the raw working directory,
// expand it and see if it matches the lnkWorkDirDest. If it does we won't touch
// it since the raw working directory is working great. If it doesn't we will
// modify the link
lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
lnkRawWorkDirExp = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, lnkRawWorkDir, NULL);
if ((!lnkWorkDirDestNative) ||
(!lnkRawWorkDirExp) ||
(!StringIMatch (lnkRawWorkDirExp, lnkWorkDirDestNative))) {
modifyFile = TRUE;
} else {
IsmReleaseMemory (lnkWorkDirDestNative);
lnkWorkDirDestNative = NULL;
}
if (lnkRawWorkDirExp) {
IsmReleaseMemory (lnkRawWorkDirExp);
lnkRawWorkDirExp = NULL;
}
}
} else {
// seems like the working directory is gone. If the target is still present, we will adjust
// the working directory to point where the target is located
if (lnkTargetPresent) {
if (IsmCreateObjectStringsFromHandle (lnkTargetDest?lnkTargetDest:lnkTarget, &lnkTargetNode, &lnkTargetLeaf)) {
lnkWorkDirDest = IsmCreateObjectHandle (lnkTargetNode, NULL);
if (lnkWorkDirDest) {
modifyFile = TRUE;
lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
}
IsmDestroyObjectString (lnkTargetNode);
IsmDestroyObjectString (lnkTargetLeaf);
}
}
}
}
// let's examine the icon path
if (lnkIconPath) {
lnkIconPathDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
lnkIconPath,
&lnkIconPathDestType,
&lnkIconPathDestDel,
&lnkIconPathDestRepl
);
// if the icon holder is deleted we will extract the icon and put it in our lib.
// The point is, even if the icon holder is replaced (that is, exists on the destination
// machine), we cannot guarantee that the icon indexes will be the same. Typically, shell32.dll
// icon indexes changed from version to version, and if a user picked an shell32.dll icon on Win9x,
// he will have a surprise on Win XP. If we wanted to keep the icon from the replacement file, we just
// need to check for lnkIconPathDestRepl.
if ((lnkIconPathDestDel == FALSE) &&
((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
) {
if (lnkIconPathDest) {
// the icon path changed location, we need to adjust the link
modifyFile = TRUE;
lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest);
}
} else {
// seems like the icon path is gone. If the we have the icon extracted we will try to add it to the
// icon library and adjust this link to point there.
if (lnkIconSGroup.DataSize) {
lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup);
if (lnkIconGroup) {
if (IsmGetEnvironmentString (
PLATFORM_DESTINATION,
NULL,
S_ENV_ICONLIB,
NULL,
0,
&requiredSize
)) {
iconLibPath = PmGetMemory (g_LinksPool, requiredSize);
if (IsmGetEnvironmentString (
PLATFORM_DESTINATION,
NULL,
S_ENV_ICONLIB,
iconLibPath,
requiredSize,
NULL
)) {
if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) {
modifyFile = TRUE;
lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath));
StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath);
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB);
}
}
PmReleaseMemory (g_LinksPool, iconLibPath);
}
IcoReleaseIconGroup (lnkIconGroup);
}
} else {
// we don't have the icon extracted. Let's just do our best and update the
// icon path to point to the destination replacement.
if (((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) &&
(lnkIconPathDest)
) {
// the icon path changed location, we need to adjust the link
modifyFile = TRUE;
lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest);
}
}
}
} else {
// If we have an icon extracted, but the icon path is NULL, it
// means that the original LNK had no icon associated with it
// but it's target was an EXE. In this case the icon that was
// displayed was the first icon from the EXE. Now we want to
// make sure that the destination target has at least one icon
// in it. If it doesn't we will just hook the source extracted icon.
if (lnkIconSGroup.DataSize) {
// let's see if the destination target has at least one icon
if (IsmAcquireObjectEx (
MIG_FILE_TYPE | PLATFORM_DESTINATION,
lnkTargetDest?lnkTargetDest:lnkTarget,
&lnkIconContent,
CONTENTTYPE_FILE,
0
)) {
if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) {
lnkIconGroup = IcoExtractIconGroupByIndexFromFile (
lnkIconContent.FileContent.ContentPath,
0,
NULL
);
if (lnkIconGroup) {
// Yes, it has at least one icon, we're safe
IcoReleaseIconGroup (lnkIconGroup);
lnkIconGroup = NULL;
} else {
// Nope, it does not have any icons
lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup);
if (lnkIconGroup) {
if (IsmGetEnvironmentString (
PLATFORM_DESTINATION,
NULL,
S_ENV_ICONLIB,
NULL,
0,
&requiredSize
)) {
iconLibPath = PmGetMemory (g_LinksPool, requiredSize);
if (IsmGetEnvironmentString (
PLATFORM_DESTINATION,
NULL,
S_ENV_ICONLIB,
iconLibPath,
requiredSize,
NULL
)) {
if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) {
modifyFile = TRUE;
lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath));
StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath);
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB);
}
}
PmReleaseMemory (g_LinksPool, iconLibPath);
}
IcoReleaseIconGroup (lnkIconGroup);
}
}
}
IsmReleaseObject (&lnkIconContent);
}
}
}
if (modifyFile) {
if (CurrentContent->ContentInFile) {
if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) {
// We need to modify the shortcut. Unfortunately, if this is the command
// line tool, the shortcut we are going to modify is not some temporary file,
// it is the actual shortcut from the store. As a result, if you try to
// apply a second time, the shortcut would be already modified and problems
// may appear. For this, we will get a temporary directory from ISM,
// copy the current shortcut (CurrentContent->FileContent.ContentPath) and
// modify it and generate a new content.
newShortcutPath = IsmGetMemory (MAX_PATH);
if (newShortcutPath) {
if (IsmGetTempFile (newShortcutPath, MAX_PATH)) {
if (CopyFile (
(PCTSTR) CurrentContent->FileContent.ContentPath,
newShortcutPath,
FALSE
)) {
if (ModifyShortcutFileEx (
newShortcutPath,
GetFileExtensionFromPath (objectLeaf),
lnkTargetDestNative,
lnkParamsNew,
lnkWorkDirDestNative,
lnkIconPathDestNative,
lnkIconNumber,
lnkHotKey,
NULL,
g_ShellLink,
g_PersistFile
)) {
NewContent->FileContent.ContentPath = newShortcutPath;
}
}
}
}
IsmDestroyObjectString (objectNode);
IsmDestroyObjectString (objectLeaf);
}
} else {
// something is wrong, the content of this shortcut should be in a file
MYASSERT (FALSE);
}
}
if (lnkIconPathDestNative) {
IsmReleaseMemory (lnkIconPathDestNative);
lnkIconPathDestNative = NULL;
}
if (lnkWorkDirDestNative) {
IsmReleaseMemory (lnkWorkDirDestNative);
lnkWorkDirDestNative = NULL;
}
if (lnkTargetDestNative) {
IsmReleaseMemory (lnkTargetDestNative);
lnkTargetDestNative = NULL;
}
if (lnkIconPathDest) {
IsmDestroyObjectHandle (lnkIconPathDest);
lnkIconPathDest = NULL;
}
if (lnkWorkDirDest) {
IsmDestroyObjectHandle (lnkWorkDirDest);
lnkWorkDirDest = NULL;
}
if (lnkTargetDest) {
IsmDestroyObjectHandle (lnkTargetDest);
lnkTargetDest = NULL;
}
if (lnkExtraData) {
PmReleaseMemory (g_LinksPool, lnkExtraData);
lnkExtraData = NULL;
}
if (lnkIconSGroup.DataSize && lnkIconSGroup.Data) {
PmReleaseMemory (g_LinksPool, lnkIconSGroup.Data);
lnkIconSGroup.DataSize = 0;
lnkIconSGroup.Data = NULL;
}
if (lnkIconPath) {
PmReleaseMemory (g_LinksPool, lnkIconPath);
lnkIconPath = NULL;
}
if (lnkWorkDir) {
PmReleaseMemory (g_LinksPool, lnkWorkDir);
lnkWorkDir = NULL;
}
if (lnkParams) {
PmReleaseMemory (g_LinksPool, lnkParams);
lnkParams = NULL;
}
if (lnkTarget) {
PmReleaseMemory (g_LinksPool, lnkTarget);
lnkTarget = NULL;
}
if (comInit) {
FreeCOMLink (&g_ShellLink, &g_PersistFile);
g_ShellLink = NULL;
g_PersistFile = NULL;
}
return TRUE;
}
BOOL
LinkRestoreCallback (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTID ObjectId,
IN MIG_OBJECTSTRINGHANDLE ObjectName
)
{
MIG_PROPERTYDATAID propDataId;
MIG_BLOBTYPE propDataType;
UINT requiredSize;
MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
MIG_OBJECTTYPEID lnkTargetDestType = 0;
MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
BOOL lnkTargetDestDel = FALSE;
BOOL lnkTargetDestRepl = FALSE;
PCTSTR lnkTargetNative = NULL;
PCTSTR objectNode = NULL;
PCTSTR objectLeaf = NULL;
PCTSTR extPtr = NULL;
PCTSTR userProfile = NULL;
PCTSTR allUsersProfile = NULL;
PCTSTR newObjectNode = NULL;
MIG_OBJECTSTRINGHANDLE newObjectName = NULL;
MIG_CONTENT oldContent;
MIG_CONTENT newContent;
BOOL identical = FALSE;
BOOL diffDetailsOnly = FALSE;
BOOL result = TRUE;
if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) {
if (IsmCreateObjectStringsFromHandle (ObjectName, &objectNode, &objectLeaf)) {
if (objectLeaf) {
extPtr = GetFileExtensionFromPath (objectLeaf);
if (extPtr &&
(StringIMatch (extPtr, TEXT("LNK")) ||
StringIMatch (extPtr, TEXT("PIF"))
)
) {
propDataId = IsmGetPropertyFromObject (ObjectTypeId, ObjectName, g_LnkMigProp_Target);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
lnkTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTarget);
if (lnkTargetNative) {
if (pIsUncPath (lnkTargetNative)) {
result = TRUE;
} else {
lnkTargetDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
lnkTarget,
&lnkTargetDestType,
&lnkTargetDestDel,
&lnkTargetDestRepl
);
result = (lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE);
if (lnkTargetDest) {
IsmDestroyObjectHandle (lnkTargetDest);
}
}
IsmReleaseMemory (lnkTargetNative);
} else {
result = FALSE;
}
PmReleaseMemory (g_LinksPool, lnkTarget);
}
}
if (result) {
// one more thing. If this LNK is in %USERPROFILE% and an equivalent LNK
// (same name, same target, same arguments, same working dir) can be found
// in %ALLUSERSPROFILE% then we won't restore this LNK. Similarly, if the
// LNK is in %ALLUSERSPROFILE% and an equivalent LNK exists in %USERPROFILE%
// we won't restore the LNK.
userProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL);
allUsersProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL);
if (userProfile && allUsersProfile && objectNode) {
if (StringIPrefix (objectNode, userProfile)) {
newObjectNode = StringSearchAndReplace (objectNode, userProfile, allUsersProfile);
if (newObjectNode) {
newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf);
if (newObjectName) {
if (IsmAcquireObjectEx (
(ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
newObjectName,
&newContent,
CONTENTTYPE_FILE,
0
)) {
if (IsmAcquireObjectEx (
ObjectTypeId,
ObjectName,
&oldContent,
CONTENTTYPE_FILE,
0
)) {
if (LinkDoesContentMatch (
FALSE,
ObjectTypeId,
ObjectName,
&oldContent,
(ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
newObjectName,
&newContent,
&identical,
&diffDetailsOnly
)) {
result = (!identical) && (!diffDetailsOnly);
}
IsmReleaseObject (&oldContent);
}
IsmReleaseObject (&newContent);
}
IsmDestroyObjectHandle (newObjectName);
newObjectName = NULL;
}
FreePathString (newObjectNode);
newObjectNode = NULL;
}
}
}
if (userProfile) {
IsmReleaseMemory (userProfile);
userProfile = NULL;
}
if (allUsersProfile) {
IsmReleaseMemory (allUsersProfile);
allUsersProfile = NULL;
}
allUsersProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL);
userProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL);
if (userProfile && allUsersProfile && objectNode) {
if (StringIPrefix (objectNode, allUsersProfile)) {
newObjectNode = StringSearchAndReplace (objectNode, allUsersProfile, userProfile);
if (newObjectNode) {
newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf);
if (newObjectName) {
if (IsmAcquireObjectEx (
(ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
newObjectName,
&newContent,
CONTENTTYPE_FILE,
0
)) {
if (IsmAcquireObjectEx (
ObjectTypeId,
ObjectName,
&oldContent,
CONTENTTYPE_FILE,
0
)) {
if (LinkDoesContentMatch (
FALSE,
ObjectTypeId,
ObjectName,
&oldContent,
(ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
newObjectName,
&newContent,
&identical,
&diffDetailsOnly
)) {
result = (!identical) || (!diffDetailsOnly);
}
IsmReleaseObject (&oldContent);
}
IsmReleaseObject (&newContent);
}
IsmDestroyObjectHandle (newObjectName);
newObjectName = NULL;
}
FreePathString (newObjectNode);
newObjectNode = NULL;
}
}
}
if (userProfile) {
IsmReleaseMemory (userProfile);
userProfile = NULL;
}
if (allUsersProfile) {
IsmReleaseMemory (allUsersProfile);
allUsersProfile = NULL;
}
}
}
}
IsmDestroyObjectString (objectNode);
IsmDestroyObjectString (objectLeaf);
}
}
return result;
}
BOOL
pMatchWinSysFiles (
IN PCTSTR Source,
IN PCTSTR Destination
)
{
PCTSTR srcLeaf;
PCTSTR destLeaf;
PCTSTR winDir = NULL;
PCTSTR sysDir = NULL;
BOOL result = FALSE;
__try {
if ((!Source) || (!Destination)) {
__leave;
}
srcLeaf = _tcsrchr (Source, TEXT('\\'));
destLeaf = _tcsrchr (Destination, TEXT('\\'));
if ((!srcLeaf) || (!destLeaf)) {
__leave;
}
if (!StringIMatch (srcLeaf, destLeaf)) {
__leave;
}
// now let's see if the directory for each is either
// %windir% or %system%
// Source is already modified to what it would look like on the destination machine,
// let's just expand the PLATFORM_DESTINATION env. variables.
winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL);
sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL);
if ((!winDir) || (!sysDir)) {
__leave;
}
if (!StringIPrefix (Source, winDir) && !StringIPrefix (Source, sysDir)) {
__leave;
}
IsmReleaseMemory (winDir);
winDir = NULL;
IsmReleaseMemory (sysDir);
sysDir = NULL;
winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL);
sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL);
if ((!winDir) || (!sysDir)) {
__leave;
}
if (!StringIPrefix (Destination, winDir) && !StringIPrefix (Destination, sysDir)) {
__leave;
}
IsmReleaseMemory (winDir);
winDir = NULL;
IsmReleaseMemory (sysDir);
sysDir = NULL;
result = TRUE;
}
__finally {
if (winDir) {
IsmReleaseMemory (winDir);
winDir = NULL;
}
if (sysDir) {
IsmReleaseMemory (sysDir);
sysDir = NULL;
}
}
return result;
}
BOOL
pForcedLnkMatch (
IN PCTSTR SrcTarget,
IN PCTSTR SrcParams,
IN PCTSTR SrcWorkDir,
IN PCTSTR DestTarget,
IN PCTSTR DestParams,
IN PCTSTR DestWorkDir
)
{
PTSTR multiSz = NULL;
MULTISZ_ENUM e;
UINT sizeNeeded;
HINF infHandle = INVALID_HANDLE_VALUE;
ENVENTRY_TYPE dataType;
INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
PCTSTR srcTargetPat = NULL;
PCTSTR srcParamsPat = NULL;
PCTSTR srcWorkDirPat = NULL;
PCTSTR destTargetPat = NULL;
PCTSTR destParamsPat = NULL;
PCTSTR destWorkDirPat = NULL;
BOOL result = FALSE;
// let's look in the INFs in section [EquivalentLinks] and see if our LNKs match
// one of the lines. If they do then they are equivalent
if (IsmGetEnvironmentValue (
IsmGetRealPlatform (),
NULL,
S_GLOBAL_INF_HANDLE,
(PBYTE)(&infHandle),
sizeof (HINF),
&sizeNeeded,
&dataType
) &&
(sizeNeeded == sizeof (HINF)) &&
(dataType == ENVENTRY_BINARY)
) {
if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
do {
srcTargetPat = InfGetStringField (&is, 1);
srcParamsPat = InfGetStringField (&is, 2);
srcWorkDirPat = InfGetStringField (&is, 3);
destTargetPat = InfGetStringField (&is, 4);
destParamsPat = InfGetStringField (&is, 5);
destWorkDirPat = InfGetStringField (&is, 6);
if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) &&
IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT(""))
) {
result = TRUE;
break;
}
if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) &&
IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT(""))
) {
result = TRUE;
break;
}
} while (InfFindNextLine (&is));
}
InfNameHandle (infHandle, NULL, FALSE);
} else {
if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) {
__try {
multiSz = AllocText (sizeNeeded);
if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) {
__leave;
}
if (EnumFirstMultiSz (&e, multiSz)) {
do {
infHandle = InfOpenInfFile (e.CurrentString);
if (infHandle != INVALID_HANDLE_VALUE) {
if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
do {
srcTargetPat = InfGetStringField (&is, 1);
srcParamsPat = InfGetStringField (&is, 2);
srcWorkDirPat = InfGetStringField (&is, 3);
destTargetPat = InfGetStringField (&is, 4);
destParamsPat = InfGetStringField (&is, 5);
destWorkDirPat = InfGetStringField (&is, 6);
if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) &&
IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT(""))
) {
result = TRUE;
break;
}
if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) &&
IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT(""))
) {
result = TRUE;
break;
}
} while (InfFindNextLine (&is));
}
}
InfCloseInfFile (infHandle);
infHandle = INVALID_HANDLE_VALUE;
if (result) {
break;
}
} while (EnumNextMultiSz (&e));
}
}
__finally {
FreeText (multiSz);
}
}
}
InfResetInfStruct (&is);
return result;
}
BOOL
LinkDoesContentMatch (
IN BOOL AlreadyProcessed,
IN MIG_OBJECTTYPEID SrcObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
IN PMIG_CONTENT SrcContent,
IN MIG_OBJECTTYPEID DestObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE DestObjectName,
IN PMIG_CONTENT DestContent,
OUT PBOOL Identical,
OUT PBOOL DifferentDetailsOnly
)
{
PCTSTR objectNode = NULL;
PCTSTR objectLeaf = NULL;
PCTSTR extPtr = NULL;
MIG_PROPERTYDATAID propDataId;
MIG_BLOBTYPE propDataType;
UINT requiredSize;
MIG_OBJECTSTRINGHANDLE srcTarget = NULL;
PCTSTR srcTargetNative = NULL;
PCTSTR srcParams = NULL;
PCTSTR srcParamsNew = NULL;
MIG_OBJECTSTRINGHANDLE srcWorkDir = NULL;
PCTSTR srcWorkDirNative = NULL;
PCTSTR srcRawWorkDir = NULL;
BOOL lnkWorkDirDestDel = FALSE;
BOOL lnkWorkDirDestRepl = FALSE;
PCTSTR destTarget = NULL;
PCTSTR destParams = NULL;
PCTSTR destWorkDir = NULL;
PCTSTR destIconPath = NULL;
PCTSTR expTmpStr;
PCTSTR longExpTmpStr;
INT destIconNumber;
WORD destHotKey;
BOOL destDosApp;
BOOL destMsDosMode;
BOOL comInit = FALSE;
MIG_OBJECTSTRINGHANDLE lnkDest = NULL;
PCTSTR lnkNative = NULL;
BOOL targetOsFile = FALSE;
BOOL match = FALSE;
BOOL result = FALSE;
if ((SrcObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) {
return FALSE;
}
if ((DestObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) {
return FALSE;
}
// let's check that the source is a shortcut
if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) {
if (objectLeaf) {
extPtr = GetFileExtensionFromPath (objectLeaf);
if (extPtr &&
(StringIMatch (extPtr, TEXT("LNK")) ||
StringIMatch (extPtr, TEXT("PIF")) ||
StringIMatch (extPtr, TEXT("URL"))
)
) {
result = TRUE;
}
}
IsmDestroyObjectString (objectNode);
IsmDestroyObjectString (objectLeaf);
}
if (!result) {
return FALSE;
}
result = FALSE;
// let's check that the destination is a shortcut
if (IsmCreateObjectStringsFromHandle (DestObjectName, &objectNode, &objectLeaf)) {
if (objectLeaf) {
extPtr = GetFileExtensionFromPath (objectLeaf);
if (extPtr &&
(StringIMatch (extPtr, TEXT("LNK")) ||
StringIMatch (extPtr, TEXT("PIF")) ||
StringIMatch (extPtr, TEXT("URL"))
)
) {
result = TRUE;
}
}
IsmDestroyObjectString (objectNode);
IsmDestroyObjectString (objectLeaf);
}
if (!result) {
return FALSE;
}
// some safety checks
if (!SrcContent->ContentInFile) {
return FALSE;
}
if (!SrcContent->FileContent.ContentPath) {
return FALSE;
}
if (!DestContent->ContentInFile) {
return FALSE;
}
if (!DestContent->FileContent.ContentPath) {
return FALSE;
}
result = FALSE;
__try {
// let's get info from the source. We will not look inside the LNK file, we will
// just get it's properties. If there are no properties, we'll just exit, leaving
// the default compare to solve the problem.
// first, retrieve the properties
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Target);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
srcTarget = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)srcTarget, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Params);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
srcParams = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)srcParams, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
srcRawWorkDir = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)srcRawWorkDir, requiredSize, NULL, &propDataType);
}
}
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_WorkDir);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
srcWorkDir = PmGetMemory (g_LinksPool, requiredSize);
IsmGetPropertyData (propDataId, (PBYTE)srcWorkDir, requiredSize, NULL, &propDataType);
}
}
// now, let's get the info from the destination shortcut
if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) {
comInit = TRUE;
if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
return TRUE;
}
}
if (!ExtractShortcutInfo (
DestContent->FileContent.ContentPath,
&destTarget,
&destParams,
&destWorkDir,
&destIconPath,
&destIconNumber,
&destHotKey,
&destDosApp,
&destMsDosMode,
NULL,
g_ShellLink,
g_PersistFile
)) {
__leave;
}
srcTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcTarget);
srcWorkDirNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcWorkDir);
if (pForcedLnkMatch (
srcTargetNative,
srcParams,
srcWorkDirNative,
destTarget,
destParams,
destWorkDir
)) {
if (srcTargetNative) {
IsmReleaseMemory (srcTargetNative);
srcTargetNative = NULL;
}
if (srcWorkDirNative) {
IsmReleaseMemory (srcWorkDirNative);
srcWorkDirNative = NULL;
}
result = TRUE;
if (Identical) {
*Identical = TRUE;
}
if (DifferentDetailsOnly) {
*DifferentDetailsOnly = FALSE;
}
__leave;
}
if (srcTargetNative) {
IsmReleaseMemory (srcTargetNative);
srcTargetNative = NULL;
}
if (srcWorkDirNative) {
IsmReleaseMemory (srcWorkDirNative);
srcWorkDirNative = NULL;
}
// let's filter the source target and see if it matches the dest target
match = TRUE;
if (srcTarget && *srcTarget && destTarget && *destTarget) {
// let's see if the source target is an OS file
targetOsFile = IsmIsAttributeSetOnObject (MIG_FILE_TYPE|PLATFORM_SOURCE, srcTarget, g_OsFileAttribute);
lnkDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
srcTarget,
NULL,
NULL,
NULL
);
if (!lnkDest) {
lnkDest = srcTarget;
}
lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest);
if (lnkNative) {
expTmpStr = IsmExpandEnvironmentString (
PLATFORM_DESTINATION,
S_SYSENVVAR_GROUP,
destTarget,
NULL
);
if (!expTmpStr) {
expTmpStr = destTarget;
}
longExpTmpStr = BfGetLongFileName (expTmpStr);
if (!longExpTmpStr) {
longExpTmpStr = expTmpStr;
}
if (!StringIMatch (lnkNative, longExpTmpStr)) {
// different targets
// Let's try another trick to catch some OS files getting moved.
// For example, in Win9x systems, notepad.exe is in %windir%.
// In XP, it was moved to %system%. We'll try to match the target
// if the last segment is the same and the rest is either %windir%
// or %system%
if (!pMatchWinSysFiles (lnkNative, longExpTmpStr)) {
match = FALSE;
}
}
if (longExpTmpStr != expTmpStr) {
FreePathString (longExpTmpStr);
}
if (expTmpStr != destTarget) {
IsmReleaseMemory (expTmpStr);
}
IsmReleaseMemory (lnkNative);
lnkNative = NULL;
} else {
match = FALSE;
}
if (lnkDest != srcTarget) {
IsmDestroyObjectHandle (lnkDest);
}
lnkDest = NULL;
} else {
if (srcTarget && *srcTarget) {
match = FALSE;
}
if (destTarget && *destTarget) {
match = FALSE;
}
}
// the target did not match
if (!match) {
__leave;
}
// let's match the src and dest parameters
match = TRUE;
if (srcParams && *srcParams && destParams && *destParams) {
// srcParams might have source paths embedded in them.
// Let's try to filter them and get the parameters as
// they would look on the destination machine
srcParamsNew = pFilterBuffer (srcParams, NULL);
if (!StringIMatch (srcParamsNew?srcParamsNew:srcParams, destParams)) {
// different parameters
match = FALSE;
}
if (srcParamsNew) {
FreePathString (srcParamsNew);
srcParamsNew = NULL;
}
} else {
if (srcParams && *srcParams) {
match = FALSE;
}
if (destParams && *destParams) {
match = FALSE;
}
}
// the parameters did not match
if (!match) {
__leave;
}
// let's filter the source work dir and see if it matches the dest work dir.
match = TRUE;
// if the source target was an OS file we will ignore the working directory match
if (!targetOsFile) {
if (srcWorkDir && *srcWorkDir && destWorkDir && *destWorkDir) {
lnkDest = IsmFilterObject (
MIG_FILE_TYPE | PLATFORM_SOURCE,
srcWorkDir,
NULL,
&lnkWorkDirDestDel,
&lnkWorkDirDestRepl
);
if (!lnkDest) {
// if the working directory is deleted and not
// replaced it means it will go away. In that case
// we don't really care about working directory
// matching the destination one.
if ((!lnkWorkDirDestDel) || lnkWorkDirDestRepl) {
lnkDest = srcWorkDir;
}
}
if (lnkDest) {
lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest);
if (lnkNative) {
expTmpStr = IsmExpandEnvironmentString (
PLATFORM_DESTINATION,
S_SYSENVVAR_GROUP,
destWorkDir,
NULL
);
if (!expTmpStr) {
expTmpStr = destWorkDir;
}
longExpTmpStr = BfGetLongFileName (expTmpStr);
if (!longExpTmpStr) {
longExpTmpStr = expTmpStr;
}
if (!StringIMatch (lnkNative, longExpTmpStr)) {
// different working directories
// let's test the raw versions just in case
if (!srcRawWorkDir || !StringIMatch (srcRawWorkDir, destWorkDir)) {
match = FALSE;
}
}
if (longExpTmpStr != expTmpStr) {
FreePathString (longExpTmpStr);
}
if (expTmpStr != destWorkDir) {
IsmReleaseMemory (expTmpStr);
}
IsmReleaseMemory (lnkNative);
lnkNative = NULL;
} else {
match = FALSE;
}
if (lnkDest != srcWorkDir) {
IsmDestroyObjectHandle (lnkDest);
}
lnkDest = NULL;
}
} else {
if (srcWorkDir && *srcWorkDir) {
match = FALSE;
}
if (destWorkDir && *destWorkDir) {
match = FALSE;
}
}
}
// the working directory did not match
if (!match) {
__leave;
}
result = TRUE;
if (Identical) {
*Identical = TRUE;
}
if (DifferentDetailsOnly) {
*DifferentDetailsOnly = FALSE;
}
}
__finally {
if (srcTarget) {
PmReleaseMemory (g_LinksPool, srcTarget);
srcTarget = NULL;
}
if (srcParams) {
PmReleaseMemory (g_LinksPool, srcParams);
srcParams = NULL;
}
if (srcRawWorkDir) {
PmReleaseMemory (g_LinksPool, srcRawWorkDir);
srcRawWorkDir = NULL;
}
if (srcWorkDir) {
PmReleaseMemory (g_LinksPool, srcWorkDir);
srcWorkDir = NULL;
}
if (destTarget) {
FreePathString (destTarget);
destTarget = NULL;
}
if (destParams) {
FreePathString (destParams);
destParams = NULL;
}
if (destWorkDir) {
FreePathString (destWorkDir);
destWorkDir = NULL;
}
if (destIconPath) {
FreePathString (destIconPath);
destIconPath = NULL;
}
if (comInit) {
FreeCOMLink (&g_ShellLink, &g_PersistFile);
g_ShellLink = NULL;
g_PersistFile = NULL;
}
if (lnkNative) {
IsmReleaseMemory (lnkNative);
lnkNative = NULL;
}
}
return result;
}
BOOL
WINAPI
LnkMigOpmInitialize (
IN PMIG_LOGCALLBACK LogCallback,
IN PVOID Reserved
)
{
LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
g_OsFileAttribute = IsmRegisterAttribute (S_ATTRIBUTE_OSFILE, FALSE);
g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
IsmRegisterRestoreCallback (LinkRestoreCallback);
IsmRegisterCompareCallback (MIG_FILE_TYPE, LinkDoesContentMatch);
IsmRegisterOperationApplyCallback (g_LnkMigOp_FixContent, DoLnkContentFix, TRUE);
return TRUE;
}