1699 lines
54 KiB
C
1699 lines
54 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
opaque.c
|
|
|
|
Abstract:
|
|
|
|
Implements a basic secure server transport module
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 08-Mar-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "logmsg.h"
|
|
#include <compress.h>
|
|
|
|
#define DBG_OPAQUE "OpaqueUnc"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
#define S_TRANSPORT_DIR TEXT("USMT2.UNC")
|
|
#define S_TRANSPORT_DAT_FILE TEXT("TRANSDB.DAT")
|
|
#define S_TRANSPORT_IMG_FILE TEXT("IMG%05X.DAT")
|
|
#define S_TRANSPORT_STATUS_FILE TEXT("status")
|
|
#define S_FILEOBJECT_NAME TEXT("File")
|
|
#define S_REGOBJECT_NAME TEXT("Registry")
|
|
#define S_DATABASEOBJECT_NAME TEXT("Database")
|
|
#define S_DETAILS_PREFIX TEXT("details-")
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
#define TRFLAG_FILE 0x01
|
|
#define TRFLAG_MEMORY 0x02
|
|
#define COPY_BUFFER_SIZE 32768
|
|
#define OPAQUETR_OLDSIG1 0x55534D31 //USM1
|
|
#define OPAQUETR_OLDSIG2 0x55534D32 //USM1
|
|
#define OPAQUETR_SIG 0x55534D33 //USM2
|
|
|
|
#define TRSTATUS_DIRTY 0x00000001
|
|
#define TRSTATUS_READY 0x00000002
|
|
#define TRSTATUS_LOCKED 0x00000003
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct {
|
|
TCHAR TempFile [MAX_PATH];
|
|
PCVOID AllocPtr;
|
|
PCVOID DetailsPtr;
|
|
HANDLE FileHandle;
|
|
HANDLE MapHandle;
|
|
} ALLOCSTATE, *PALLOCSTATE;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
MIG_TRANSPORTSTORAGEID g_ReliableStorageId;
|
|
PCTSTR g_TransportPath = NULL;
|
|
PCTSTR g_TransportTempPath = NULL;
|
|
PCTSTR g_TransportStatus = NULL;
|
|
HANDLE g_TransportStatusHandle = NULL;
|
|
BOOL g_OtCompressData = FALSE;
|
|
BOOL g_OtOldFormat = FALSE;
|
|
UINT g_Platform;
|
|
MIG_PROGRESSSLICEID g_PersistentSlice;
|
|
MIG_PROGRESSSLICEID g_DatabaseSlice;
|
|
UINT g_CompressedTicks;
|
|
UINT g_CompressedTicked;
|
|
MIG_PROGRESSSLICEID g_CompressedSlice;
|
|
UINT g_UncompressTicks;
|
|
UINT g_UncompressTicked;
|
|
MIG_PROGRESSSLICEID g_UncompressSlice;
|
|
LONGLONG g_TotalFiles;
|
|
LONGLONG g_FilesRead;
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
BOOL
|
|
pOtSaveAllState (
|
|
IN BOOL Compressed
|
|
);
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
BOOL
|
|
pSetOpaqueTransportStatus (
|
|
IN HANDLE TrJournalHandle,
|
|
IN BOOL Compressed,
|
|
IN DWORD Status
|
|
)
|
|
{
|
|
DWORD signature = OPAQUETR_SIG;
|
|
BOOL result = FALSE;
|
|
|
|
if (BfSetFilePointer (TrJournalHandle, 0)) {
|
|
result = TRUE;
|
|
result = result && BfWriteFile (TrJournalHandle, (PBYTE)(&signature), sizeof (DWORD));
|
|
result = result && BfWriteFile (TrJournalHandle, (PBYTE)(&Compressed), sizeof (BOOL));
|
|
result = result && BfWriteFile (TrJournalHandle, (PBYTE)(&Status), sizeof (DWORD));
|
|
result = result && FlushFileBuffers (TrJournalHandle);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
pGetOpaqueTransportStatus (
|
|
IN PCTSTR TrJournal,
|
|
OUT PBOOL Compressed, OPTIONAL
|
|
OUT PBOOL OldStorage, OPTIONAL
|
|
IN BOOL OpenReadOnly
|
|
)
|
|
{
|
|
HANDLE trJrnHandle;
|
|
BOOL compressed = FALSE;
|
|
DWORD signature = 0;
|
|
DWORD fileSize = 0;
|
|
DWORD result = 0;
|
|
|
|
if (OldStorage) {
|
|
*OldStorage = FALSE;
|
|
}
|
|
|
|
if (TrJournal && TrJournal [0]) {
|
|
if (OpenReadOnly) {
|
|
trJrnHandle = BfOpenReadFile (TrJournal);
|
|
} else {
|
|
trJrnHandle = BfOpenFile (TrJournal);
|
|
}
|
|
if (trJrnHandle) {
|
|
if (BfSetFilePointer (trJrnHandle, 0)) {
|
|
fileSize = GetFileSize (trJrnHandle, NULL);
|
|
if (fileSize == (sizeof (BOOL) + sizeof (DWORD))) {
|
|
if (OldStorage) {
|
|
*OldStorage = TRUE;
|
|
}
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&compressed), sizeof (BOOL))) {
|
|
BfReadFile (trJrnHandle, (PBYTE)(&result), sizeof (DWORD));
|
|
}
|
|
}
|
|
if (fileSize == (sizeof (BOOL) + sizeof (DWORD) + sizeof (DWORD))) {
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&signature), sizeof (DWORD))) {
|
|
if (signature == OPAQUETR_SIG) {
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&compressed), sizeof (BOOL))) {
|
|
BfReadFile (trJrnHandle, (PBYTE)(&result), sizeof (DWORD));
|
|
}
|
|
}
|
|
if ((signature == OPAQUETR_OLDSIG1) ||
|
|
(signature == OPAQUETR_OLDSIG2)
|
|
) {
|
|
if (OldStorage) {
|
|
*OldStorage = TRUE;
|
|
}
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&compressed), sizeof (BOOL))) {
|
|
BfReadFile (trJrnHandle, (PBYTE)(&result), sizeof (DWORD));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CloseHandle (trJrnHandle);
|
|
} else {
|
|
if (GetLastError () == ERROR_ACCESS_DENIED) {
|
|
result = TRSTATUS_LOCKED;
|
|
}
|
|
}
|
|
}
|
|
if (Compressed) {
|
|
*Compressed = compressed;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PCTSTR
|
|
pGetOpaqueImageFile (
|
|
IN PCTSTR BasePath,
|
|
IN UINT ImageIdx
|
|
)
|
|
{
|
|
TCHAR imageFileName [13];
|
|
PCTSTR imageFile = NULL;
|
|
HANDLE imageFileHandle = NULL;
|
|
|
|
wsprintf (imageFileName, S_TRANSPORT_IMG_FILE, ImageIdx);
|
|
return JoinPaths (BasePath, imageFileName);
|
|
}
|
|
|
|
PCTSTR
|
|
pGetRealTransportPath (
|
|
VOID
|
|
)
|
|
{
|
|
return g_OtCompressData?g_TransportTempPath:g_TransportPath;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportInitialize (
|
|
IN PMIG_LOGCALLBACK LogCallback
|
|
)
|
|
{
|
|
//
|
|
// Initialize globals
|
|
//
|
|
|
|
LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
|
|
g_ReliableStorageId = IsmRegisterTransport (S_RELIABLE_STORAGE_TRANSPORT);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
OpaqueTransportEstimateProgressBar (
|
|
MIG_PLATFORMTYPEID PlatformTypeId
|
|
)
|
|
{
|
|
UINT ticks;
|
|
PMIG_OBJECTCOUNT objectCount;
|
|
|
|
if (PlatformTypeId == PLATFORM_SOURCE) {
|
|
|
|
//
|
|
// If saving, we know the number of ticks based on the count of the
|
|
// persistent attribute.
|
|
//
|
|
|
|
objectCount = IsmGetObjectsStatistics (PLATFORM_SOURCE);
|
|
|
|
if (objectCount) {
|
|
ticks = objectCount->PersistentObjects;
|
|
} else {
|
|
ticks = 0;
|
|
}
|
|
|
|
g_PersistentSlice = IsmRegisterProgressSlice (ticks, max (1, ticks / 5));
|
|
|
|
if (g_OtCompressData) {
|
|
g_DatabaseSlice = IsmRegisterProgressSlice (3, 1);
|
|
} else {
|
|
g_DatabaseSlice = IsmRegisterProgressSlice (1, 1);
|
|
}
|
|
|
|
} else {
|
|
if (g_OtCompressData) {
|
|
g_UncompressTicked = 0;
|
|
g_UncompressTicks = 1000;
|
|
g_UncompressSlice = IsmRegisterProgressSlice (g_UncompressTicks, 180);
|
|
} else {
|
|
//
|
|
// If restoring, we have almost no work to account for, since
|
|
// we download from the secure server file-by-file.
|
|
//
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "Assuming transport download has no progress impact"));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportQueryCapabilities (
|
|
IN MIG_TRANSPORTSTORAGEID TransportStorageId,
|
|
OUT PMIG_TRANSPORTTYPE TransportType,
|
|
OUT PMIG_TRANSPORTCAPABILITIES Capabilities,
|
|
OUT PCTSTR *FriendlyDescription
|
|
)
|
|
{
|
|
if (TransportStorageId != g_ReliableStorageId) {
|
|
return FALSE;
|
|
}
|
|
|
|
*TransportType = TRANSPORTTYPE_FULL;
|
|
*Capabilities = CAPABILITY_COMPRESSED;
|
|
*FriendlyDescription = TEXT("Local computer or another computer on the Network");
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
pOtCleanUpTempDir (
|
|
VOID
|
|
)
|
|
{
|
|
if (g_TransportTempPath) {
|
|
FiRemoveAllFilesInTree (g_TransportTempPath);
|
|
}
|
|
}
|
|
|
|
PCTSTR
|
|
pOtCreateTemporaryDir (
|
|
VOID
|
|
)
|
|
{
|
|
TCHAR tempFile[MAX_PATH];
|
|
|
|
if (!IsmGetTempDirectory (tempFile, ARRAYSIZE(tempFile))) {
|
|
return NULL;
|
|
}
|
|
return DuplicatePathString (tempFile, 0);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportSetStorage (
|
|
IN MIG_PLATFORMTYPEID Platform,
|
|
IN MIG_TRANSPORTSTORAGEID TransportStorageId,
|
|
IN MIG_TRANSPORTCAPABILITIES RequiredCapabilities,
|
|
IN PCTSTR StoragePath,
|
|
OUT PBOOL Valid,
|
|
OUT PBOOL ImageExists
|
|
)
|
|
{
|
|
PCTSTR lastDirPtr = NULL;
|
|
PCTSTR transportPath = NULL;
|
|
PCTSTR transportStatus = NULL;
|
|
HANDLE transportStatusHandle = INVALID_HANDLE_VALUE;
|
|
MIG_OBJECTSTRINGHANDLE encodedPath;
|
|
DWORD status;
|
|
BOOL result = FALSE;
|
|
|
|
if (Valid) {
|
|
*Valid = FALSE;
|
|
}
|
|
if (ImageExists) {
|
|
*ImageExists = FALSE;
|
|
}
|
|
|
|
if (TransportStorageId == g_ReliableStorageId) {
|
|
|
|
if ((!RequiredCapabilities) || (RequiredCapabilities == CAPABILITY_COMPRESSED)) {
|
|
|
|
if (RequiredCapabilities == CAPABILITY_COMPRESSED) {
|
|
g_OtCompressData = TRUE;
|
|
} else {
|
|
g_OtCompressData = FALSE;
|
|
}
|
|
|
|
// If this is the destination, let's check if the user included USMT2.UNC in
|
|
// the path by mistake. If he did (the StoragePath ends in USMT2.UNC and
|
|
// StoragePath has our transport status) we will accept it.
|
|
if (Platform == PLATFORM_DESTINATION) {
|
|
lastDirPtr = _tcsrchr (StoragePath, TEXT('\\'));
|
|
if (lastDirPtr) {
|
|
lastDirPtr = _tcsinc (lastDirPtr);
|
|
if (lastDirPtr) {
|
|
if (StringIMatch (lastDirPtr, S_TRANSPORT_DIR)) {
|
|
transportPath = DuplicatePathString (StoragePath, 0);
|
|
transportStatus = JoinPaths (transportPath, S_TRANSPORT_STATUS_FILE);
|
|
if ((!DoesFileExist (transportPath)) ||
|
|
(pGetOpaqueTransportStatus (transportStatus, NULL, NULL, TRUE) != TRSTATUS_READY)
|
|
) {
|
|
FreePathString (transportPath);
|
|
transportPath = NULL;
|
|
FreePathString (transportStatus);
|
|
transportStatus = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!transportPath) {
|
|
transportPath = JoinPaths (StoragePath, S_TRANSPORT_DIR);
|
|
}
|
|
if (!transportStatus) {
|
|
transportStatus = JoinPaths (transportPath, S_TRANSPORT_STATUS_FILE);
|
|
}
|
|
|
|
if (!DoesFileExist (transportPath)) {
|
|
|
|
// we require UNC path or a full path (like c:\...)
|
|
if (transportPath[0] == '\\' && transportPath[1] == '\\') {
|
|
// this is a UNC path
|
|
*Valid = TRUE;
|
|
} else if (transportPath[1] == ':') {
|
|
// this is a normal full path
|
|
*Valid = TRUE;
|
|
} else {
|
|
*Valid = FALSE;
|
|
}
|
|
|
|
if ((*Valid) && (Platform == PLATFORM_SOURCE)) {
|
|
// we need to actually try to create our transport directory and the status file
|
|
// After that we will remove them but this is just the way for us to validate the
|
|
// store
|
|
|
|
*Valid = FALSE;
|
|
if (BfCreateDirectory (transportPath)) {
|
|
transportStatusHandle = BfCreateFile (transportStatus);
|
|
if (transportStatusHandle) {
|
|
*Valid = TRUE;
|
|
CloseHandle (transportStatusHandle);
|
|
}
|
|
PushError ();
|
|
FiRemoveAllFilesInTree (transportPath);
|
|
PopError ();
|
|
}
|
|
}
|
|
|
|
*ImageExists = FALSE;
|
|
|
|
} else {
|
|
|
|
// we try to open this transport status file with Read/Write. If we
|
|
// fail this is either because somebody has it opened or we don't
|
|
// have access rights. In both cases we should get back TRSTATUS_LOCKED
|
|
|
|
status = pGetOpaqueTransportStatus (transportStatus, NULL, NULL, TRUE);
|
|
|
|
switch (status) {
|
|
case TRSTATUS_LOCKED:
|
|
*ImageExists = TRUE;
|
|
*Valid = FALSE;
|
|
break;
|
|
case TRSTATUS_READY:
|
|
*ImageExists = TRUE;
|
|
*Valid = TRUE;
|
|
break;
|
|
case TRSTATUS_DIRTY:
|
|
*ImageExists = FALSE;
|
|
*Valid = TRUE;
|
|
break;
|
|
default:
|
|
*ImageExists = FALSE;
|
|
*Valid = TRUE;
|
|
}
|
|
}
|
|
|
|
result = TRUE;
|
|
}
|
|
}
|
|
|
|
if (result && *Valid) {
|
|
|
|
if (g_TransportPath) {
|
|
FreePathString (g_TransportPath);
|
|
g_TransportPath = NULL;
|
|
}
|
|
|
|
if (g_TransportStatus) {
|
|
FreePathString (g_TransportStatus);
|
|
g_TransportStatus = NULL;
|
|
}
|
|
|
|
if (transportPath) {
|
|
g_TransportPath = transportPath;
|
|
} else {
|
|
g_TransportPath = JoinPaths (StoragePath, S_TRANSPORT_DIR);
|
|
}
|
|
if (transportStatus) {
|
|
g_TransportStatus = transportStatus;
|
|
} else {
|
|
g_TransportStatus = JoinPaths (g_TransportPath, S_TRANSPORT_STATUS_FILE);
|
|
}
|
|
|
|
encodedPath = IsmCreateSimpleObjectPattern (g_TransportPath, FALSE, NULL, FALSE);
|
|
if (encodedPath) {
|
|
IsmRegisterStaticExclusion (MIG_FILE_TYPE, encodedPath);
|
|
IsmDestroyObjectHandle (encodedPath);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportSaveState (
|
|
VOID
|
|
)
|
|
{
|
|
MIG_APPINFO appInfo;
|
|
ERRUSER_EXTRADATA extraData;
|
|
DWORD status;
|
|
BOOL result = FALSE;
|
|
BOOL allowDelete = FALSE;
|
|
|
|
ZeroMemory (&extraData, sizeof (ERRUSER_EXTRADATA));
|
|
extraData.Error = ERRUSER_ERROR_UNKNOWN;
|
|
|
|
__try {
|
|
|
|
ZeroMemory (&appInfo, sizeof (MIG_APPINFO));
|
|
appInfo.Phase = MIG_TRANSPORT_PHASE;
|
|
appInfo.SubPhase = SUBPHASE_PREPARING;
|
|
IsmSendMessageToApp (ISMMESSAGE_APP_INFO, (ULONG_PTR)(&appInfo));
|
|
|
|
if (!g_TransportPath) {
|
|
DEBUGMSG ((DBG_ERROR, "Transport Path is not selected"));
|
|
extraData.Error = ERRUSER_ERROR_NOTRANSPORTPATH;
|
|
__leave;
|
|
}
|
|
|
|
if (DoesFileExist (g_TransportPath)) {
|
|
|
|
status = pGetOpaqueTransportStatus (g_TransportStatus, NULL, NULL, FALSE);
|
|
|
|
switch (status) {
|
|
case TRSTATUS_LOCKED:
|
|
SetLastError (ERROR_ACCESS_DENIED);
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_TRANSPORT_DIR_BUSY, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_TRANSPORTPATHBUSY;
|
|
__leave;
|
|
case TRSTATUS_DIRTY:
|
|
result = FiRemoveAllFilesInTree (g_TransportPath);
|
|
if (!result) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_EMPTY_DIR, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_CANTEMPTYDIR;
|
|
__leave;
|
|
}
|
|
break;
|
|
case TRSTATUS_READY:
|
|
default:
|
|
if (IsmSendMessageToApp (TRANSPORTMESSAGE_IMAGE_EXISTS, 0)) {
|
|
if (!FiRemoveAllFilesInTree (g_TransportPath)) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_EMPTY_DIR, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_CANTEMPTYDIR;
|
|
__leave;
|
|
}
|
|
} else {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_NOT_EMPTY, g_TransportPath));
|
|
SetLastError (ERROR_ALREADY_EXISTS);
|
|
extraData.Error = ERRUSER_ERROR_ALREADYEXISTS;
|
|
__leave;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
allowDelete = TRUE;
|
|
|
|
if (!BfCreateDirectory (g_TransportPath)) {
|
|
PushError ();
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_CREATE_DIR, g_TransportPath));
|
|
PopError ();
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATEDIR;
|
|
__leave;
|
|
}
|
|
|
|
g_TransportStatusHandle = BfCreateFile (g_TransportStatus);
|
|
if (!g_TransportStatusHandle) {
|
|
PushError ();
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_CREATE_STATUS_FILE, g_TransportStatus));
|
|
PopError ();
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATESTATUS;
|
|
__leave;
|
|
}
|
|
|
|
result = pSetOpaqueTransportStatus (g_TransportStatusHandle, g_OtCompressData, TRSTATUS_DIRTY);
|
|
if (!result) {
|
|
PushError ();
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_CREATE_STATUS_FILE, g_TransportStatus));
|
|
PopError ();
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATESTATUS;
|
|
__leave;
|
|
}
|
|
|
|
g_Platform = PLATFORM_SOURCE;
|
|
result = pOtSaveAllState (g_OtCompressData);
|
|
|
|
if (result) {
|
|
result = result && pSetOpaqueTransportStatus (g_TransportStatusHandle, g_OtCompressData, TRSTATUS_READY);
|
|
}
|
|
|
|
result = result && FlushFileBuffers (g_TransportStatusHandle);
|
|
result = result && CloseHandle (g_TransportStatusHandle);
|
|
if (result) {
|
|
g_TransportStatusHandle = NULL;
|
|
}
|
|
}
|
|
__finally {
|
|
PushError ();
|
|
if (g_TransportStatusHandle) {
|
|
// if we got here there was some error. Let's just close the handle
|
|
CloseHandle (g_TransportStatusHandle);
|
|
}
|
|
if (allowDelete && (!result)) {
|
|
FiRemoveAllFilesInTree (g_TransportPath);
|
|
}
|
|
PopError ();
|
|
}
|
|
|
|
PushError ();
|
|
|
|
if (!result) {
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
}
|
|
|
|
PopError ();
|
|
|
|
return result;
|
|
}
|
|
|
|
PCTSTR
|
|
pOpaqueGetNewFileName (
|
|
IN PCTSTR FileName
|
|
)
|
|
{
|
|
PCTSTR newFileName = NULL;
|
|
PTSTR tempPtr1 = NULL;
|
|
PCTSTR endStr1 = NULL;
|
|
PCTSTR tempPtr2 = NULL;
|
|
PCTSTR endStr2 = NULL;
|
|
INT i;
|
|
|
|
// let's modify the file to extract. The file name will
|
|
// be split in 2 after the first 5 characters
|
|
newFileName = DuplicatePathString (FileName, 1);
|
|
if (!newFileName) {
|
|
return NULL;
|
|
}
|
|
tempPtr1 = (PTSTR) GetFileNameFromPath (newFileName);
|
|
if (!tempPtr1) {
|
|
FreePathString (newFileName);
|
|
return NULL;
|
|
}
|
|
endStr1 = GetEndOfString (newFileName);
|
|
if (!endStr1) {
|
|
FreePathString (newFileName);
|
|
return NULL;
|
|
}
|
|
tempPtr2 = GetFileNameFromPath (FileName);
|
|
if (!tempPtr2) {
|
|
FreePathString (newFileName);
|
|
return NULL;
|
|
}
|
|
endStr2 = GetEndOfString (FileName);
|
|
if (!endStr2) {
|
|
FreePathString (newFileName);
|
|
return NULL;
|
|
}
|
|
for (i = 0; i < 5; i ++) {
|
|
tempPtr1 = _tcsinc (tempPtr1);
|
|
tempPtr2 = _tcsinc (tempPtr2);
|
|
}
|
|
|
|
if ((tempPtr1 < endStr1) &&
|
|
(tempPtr2 < endStr2)
|
|
) {
|
|
StringCopy (tempPtr1, TEXT("\\"));
|
|
tempPtr1 = _tcsinc (tempPtr1);
|
|
StringCopy (tempPtr1, tempPtr2);
|
|
} else {
|
|
FreePathString (newFileName);
|
|
newFileName = NULL;
|
|
}
|
|
return newFileName;
|
|
}
|
|
|
|
BOOL
|
|
pOpaqueCallback (
|
|
IN PCTSTR FileToExtract,
|
|
IN LONGLONG FileSize,
|
|
OUT PBOOL ExtractFile,
|
|
IN OUT PCTSTR *NewFileName
|
|
)
|
|
{
|
|
LONGLONG numerator;
|
|
LONGLONG divisor;
|
|
LONGLONG tick;
|
|
UINT delta;
|
|
|
|
if (NewFileName) {
|
|
*NewFileName = pOpaqueGetNewFileName (FileToExtract);
|
|
}
|
|
|
|
g_FilesRead ++;
|
|
// now update the progress bar
|
|
numerator = (LONGLONG) g_FilesRead * (LONGLONG) g_UncompressTicks;
|
|
divisor = (LONGLONG) g_TotalFiles;
|
|
if (divisor) {
|
|
tick = numerator / divisor;
|
|
} else {
|
|
tick = 0;
|
|
}
|
|
delta = (UINT) tick - g_UncompressTicked;
|
|
if (delta) {
|
|
IsmTickProgressBar (g_UncompressSlice, delta);
|
|
g_UncompressTicked += delta;
|
|
}
|
|
|
|
if (ExtractFile) {
|
|
*ExtractFile = TRUE;
|
|
}
|
|
|
|
return (!IsmCheckCancel());
|
|
}
|
|
|
|
BOOL
|
|
pOtReadAllImages (
|
|
VOID
|
|
)
|
|
{
|
|
COMPRESS_HANDLE compressedHandle;
|
|
BOOL result = FALSE;
|
|
|
|
if (CompressOpenHandle (g_TransportPath, S_TRANSPORT_IMG_FILE, 1, &compressedHandle)) {
|
|
g_TotalFiles = compressedHandle.FilesStored;
|
|
if (CompressExtractAllFiles (g_TransportTempPath, &compressedHandle, pOpaqueCallback)) {
|
|
result = TRUE;
|
|
}
|
|
CompressCleanupHandle (&compressedHandle);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportBeginApply (
|
|
VOID
|
|
)
|
|
{
|
|
ERRUSER_EXTRADATA extraData;
|
|
DWORD status = 0;
|
|
PCTSTR memDbFile;
|
|
INT_PTR appReply;
|
|
PCTSTR newTransDbFile = NULL;
|
|
BOOL result = FALSE;
|
|
|
|
g_Platform = PLATFORM_DESTINATION;
|
|
|
|
ZeroMemory (&extraData, sizeof (ERRUSER_EXTRADATA));
|
|
extraData.Error = ERRUSER_ERROR_UNKNOWN;
|
|
|
|
__try {
|
|
if (!g_TransportPath) {
|
|
DEBUGMSG ((DBG_ERROR, "Transport Path is not selected"));
|
|
extraData.Error = ERRUSER_ERROR_NOTRANSPORTPATH;
|
|
__leave;
|
|
}
|
|
|
|
while (status != TRSTATUS_READY) {
|
|
|
|
status = pGetOpaqueTransportStatus (g_TransportStatus, &g_OtCompressData, &g_OtOldFormat, TRUE);
|
|
|
|
switch (status) {
|
|
case TRSTATUS_LOCKED:
|
|
if (!IsmSendMessageToApp (TRANSPORTMESSAGE_IMAGE_LOCKED, 0)) {
|
|
SetLastError (ERROR_ACCESS_DENIED);
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_TRANSPORT_DIR_BUSY, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_TRANSPORTPATHBUSY;
|
|
__leave;
|
|
}
|
|
break;
|
|
case TRSTATUS_DIRTY:
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INVALID_IMAGE, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_TRANSPORTINVALIDIMAGE;
|
|
__leave;
|
|
case TRSTATUS_READY:
|
|
break;
|
|
default:
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INVALID_IMAGE, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_TRANSPORTINVALIDIMAGE;
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
if (g_OtOldFormat) {
|
|
IsmSendMessageToApp (TRANSPORTMESSAGE_OLD_STORAGE, 0);
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INVALID_IMAGE, g_TransportPath));
|
|
extraData.Error = ERRUSER_ERROR_TRANSPORTINVALIDIMAGE;
|
|
__leave;
|
|
}
|
|
|
|
g_TransportStatusHandle = BfOpenReadFile (g_TransportStatus);
|
|
if (!g_TransportStatusHandle) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_OPEN_STATUS_FILE, g_TransportStatus));
|
|
extraData.Error = ERRUSER_ERROR_CANTOPENSTATUS;
|
|
__leave;
|
|
}
|
|
|
|
if (g_OtCompressData) {
|
|
g_TransportTempPath = pOtCreateTemporaryDir ();
|
|
|
|
if (!g_TransportTempPath) {
|
|
CloseHandle (g_TransportStatusHandle);
|
|
g_TransportStatusHandle = NULL;
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATETEMPDIR;
|
|
__leave;
|
|
}
|
|
|
|
if (!pOtReadAllImages ()) {
|
|
CloseHandle (g_TransportStatusHandle);
|
|
g_TransportStatusHandle = NULL;
|
|
extraData.Error = ERRUSER_ERROR_CANTUNPACKIMAGE;
|
|
__leave;
|
|
}
|
|
CloseHandle (g_TransportStatusHandle);
|
|
g_TransportStatusHandle = NULL;
|
|
}
|
|
|
|
newTransDbFile = pOpaqueGetNewFileName (S_TRANSPORT_DAT_FILE);
|
|
|
|
memDbFile = JoinPaths (pGetRealTransportPath (), newTransDbFile?newTransDbFile:S_TRANSPORT_DAT_FILE);
|
|
|
|
if (newTransDbFile) {
|
|
FreePathString (newTransDbFile);
|
|
newTransDbFile = NULL;
|
|
}
|
|
|
|
result = MemDbLoad (memDbFile);
|
|
if (!result) {
|
|
extraData.Error = ERRUSER_ERROR_CANTREADIMAGE;
|
|
}
|
|
FreePathString (memDbFile);
|
|
}
|
|
__finally {
|
|
}
|
|
|
|
if (!result) {
|
|
extraData.ErrorArea = ERRUSER_AREA_LOAD;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
OpaqueTransportEndApply (
|
|
VOID
|
|
)
|
|
{
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
|
|
if (g_OtCompressData) {
|
|
pOtCleanUpTempDir ();
|
|
} else {
|
|
CloseHandle (g_TransportStatusHandle);
|
|
g_TransportStatusHandle = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
OpaqueTransportTerminate (
|
|
VOID
|
|
)
|
|
{
|
|
pOtCleanUpTempDir();
|
|
|
|
if (g_TransportTempPath) {
|
|
FreePathString (g_TransportTempPath);
|
|
g_TransportTempPath = NULL;
|
|
}
|
|
if (g_TransportStatus) {
|
|
FreePathString (g_TransportStatus);
|
|
g_TransportStatus = NULL;
|
|
}
|
|
if (g_TransportPath) {
|
|
FreePathString (g_TransportPath);
|
|
g_TransportPath = NULL;
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
pGetTempFileName (
|
|
OUT PTSTR Buffer
|
|
)
|
|
{
|
|
static fileIndex = 0;
|
|
|
|
fileIndex ++;
|
|
wsprintf (Buffer, TEXT("%08X.DAT"), fileIndex);
|
|
}
|
|
|
|
PCTSTR
|
|
pOpaqueAllocStorageFileName (
|
|
IN PCTSTR FileName OPTIONAL
|
|
)
|
|
{
|
|
TCHAR buffer[32];
|
|
|
|
if (FileName) {
|
|
StringCopy (buffer, FileName);
|
|
} else {
|
|
pGetTempFileName (buffer);
|
|
}
|
|
|
|
return JoinPaths (g_TransportPath, buffer);
|
|
}
|
|
|
|
VOID
|
|
pFreeStorageFileName (
|
|
IN PCTSTR FileName
|
|
)
|
|
{
|
|
FreePathString (FileName);
|
|
}
|
|
|
|
BOOL
|
|
pOpaqueSaveDetails (
|
|
IN PCTSTR DecoratedObject,
|
|
IN PMIG_DETAILS Details
|
|
)
|
|
{
|
|
PCTSTR key;
|
|
BOOL b = FALSE;
|
|
|
|
if ((!Details) || (!Details->DetailsSize)) {
|
|
return TRUE;
|
|
}
|
|
|
|
key = JoinText (S_DETAILS_PREFIX, DecoratedObject);
|
|
|
|
if (key) {
|
|
|
|
b = (MemDbSetUnorderedBlob (key, 0, Details->DetailsData, Details->DetailsSize) != 0);
|
|
|
|
FreeText (key);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pOtAddFileToImage (
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR StoredName,
|
|
IN OUT PCOMPRESS_HANDLE CompressedHandle
|
|
)
|
|
{
|
|
return CompressAddFileToHandle (FileName, StoredName, CompressedHandle);
|
|
}
|
|
|
|
BOOL
|
|
pOtSaveContentInFile (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN PCTSTR EncodedFileName,
|
|
IN PCTSTR DecoratedObject,
|
|
IN PMIG_CONTENT Content,
|
|
IN OUT PCOMPRESS_HANDLE CompressedHandle OPTIONAL
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
PCTSTR destPath = NULL;
|
|
DWORD attributes = INVALID_ATTRIBUTES;
|
|
|
|
MYASSERT (Content->ContentInFile);
|
|
if (!Content->ContentInFile) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Use the CopyFile API to move the file from local to storage.
|
|
//
|
|
|
|
__try {
|
|
if (Content && (Content->Details.DetailsSize == sizeof (WIN32_FIND_DATAW)) && Content->Details.DetailsData) {
|
|
attributes = ((PWIN32_FIND_DATAW)Content->Details.DetailsData)->dwFileAttributes;
|
|
}
|
|
if ((attributes != INVALID_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
|
|
// this must be a directory, let's just write the key
|
|
|
|
if (!MemDbSetValue (DecoratedObject, TRFLAG_FILE)) {
|
|
__leave;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Get a temp file, assemble the src path, copy the file
|
|
//
|
|
|
|
destPath = pOpaqueAllocStorageFileName (NULL);
|
|
if (!destPath) {
|
|
__leave;
|
|
}
|
|
|
|
if (CompressedHandle) {
|
|
if (!pOtAddFileToImage (Content->FileContent.ContentPath, GetFileNameFromPath (destPath), CompressedHandle)) {
|
|
__leave;
|
|
}
|
|
} else {
|
|
if (!CopyFile (Content->FileContent.ContentPath, destPath, FALSE)) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Keep track of where the file went
|
|
//
|
|
|
|
if (!MemDbSetValue (DecoratedObject, TRFLAG_FILE)) {
|
|
__leave;
|
|
}
|
|
|
|
if (!MemDbAddSingleLinkage (DecoratedObject, GetFileNameFromPath (destPath), 0)) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save details
|
|
//
|
|
|
|
result = pOpaqueSaveDetails (DecoratedObject, &(Content->Details));
|
|
|
|
}
|
|
__finally {
|
|
pFreeStorageFileName (destPath);
|
|
INVALID_POINTER (destPath);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
pOtSaveContentInMemory (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN PCTSTR EncodedObjectName,
|
|
IN PCTSTR DecoratedObject,
|
|
IN PMIG_CONTENT Content
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
|
|
MYASSERT (!Content->ContentInFile);
|
|
if (Content->ContentInFile) {
|
|
return FALSE;
|
|
}
|
|
|
|
MemDbSetValue (DecoratedObject, TRFLAG_MEMORY);
|
|
|
|
if (Content->MemoryContent.ContentBytes && Content->MemoryContent.ContentSize) {
|
|
|
|
MemDbSetUnorderedBlob (
|
|
DecoratedObject,
|
|
0,
|
|
Content->MemoryContent.ContentBytes,
|
|
Content->MemoryContent.ContentSize
|
|
);
|
|
}
|
|
|
|
result = pOpaqueSaveDetails (DecoratedObject, &(Content->Details));
|
|
|
|
return result;
|
|
}
|
|
|
|
PCTSTR
|
|
pOpaqueBuildDecoratedObject (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN ENCODEDSTRHANDLE ObjectName
|
|
)
|
|
{
|
|
TCHAR prefix[32];
|
|
|
|
wsprintf (prefix, TEXT("%u"), ObjectTypeId);
|
|
|
|
return JoinPaths (prefix, ObjectName);
|
|
}
|
|
|
|
VOID
|
|
pOtDestroyDecoratedObject (
|
|
IN PCTSTR String
|
|
)
|
|
{
|
|
FreePathString (String);
|
|
}
|
|
|
|
BOOL
|
|
pOtSaveAllState (
|
|
IN BOOL Compressed
|
|
)
|
|
{
|
|
MIG_APPINFO appInfo;
|
|
MIG_CONTENT value;
|
|
PMIG_CONTENT convValue;
|
|
ULONGLONG size;
|
|
MIG_OBJECTWITHATTRIBUTE_ENUM objEnum;
|
|
PCTSTR ourDbFile = NULL;
|
|
PCTSTR decoratedObject = NULL;
|
|
ULONGLONG bytesSaved = 0;
|
|
UINT lastTick = GetTickCount();
|
|
TCHAR text[64];
|
|
UINT fraction;
|
|
COMPRESS_HANDLE compressedHandle;
|
|
INT_PTR appReply;
|
|
BOOL okSave = FALSE;
|
|
TRANSCOPY_ERROR transCopyError;
|
|
ERRUSER_EXTRADATA extraData;
|
|
BOOL result = FALSE;
|
|
|
|
__try {
|
|
|
|
ZeroMemory (&compressedHandle, sizeof (COMPRESS_HANDLE));
|
|
|
|
if (Compressed) {
|
|
g_TransportTempPath = pOtCreateTemporaryDir ();
|
|
|
|
if (!g_TransportTempPath) {
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATETEMPDIR;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
if (!CompressCreateHandle (g_TransportPath, S_TRANSPORT_IMG_FILE, 1, 0, &compressedHandle)) {
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATECABFILE;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate all objects with "save" attribute
|
|
//
|
|
|
|
if (IsmEnumFirstPersistentObject (&objEnum)) {
|
|
do {
|
|
//
|
|
// For each object to be saved, do the appropriate
|
|
// data copy action
|
|
//
|
|
|
|
okSave = FALSE;
|
|
while (!okSave) {
|
|
|
|
if (!IsmAcquireObjectEx (
|
|
objEnum.ObjectTypeId,
|
|
objEnum.ObjectName,
|
|
&value,
|
|
CONTENTTYPE_ANY,
|
|
0
|
|
)) {
|
|
|
|
transCopyError.ObjectType = IsmGetObjectTypeName (objEnum.ObjectTypeId);
|
|
transCopyError.ObjectName = IsmGetNativeObjectName (objEnum.ObjectTypeId, objEnum.ObjectName);
|
|
transCopyError.Error = GetLastError ();
|
|
|
|
if (IsmIsNonCriticalObject (objEnum.ObjectTypeId, objEnum.ObjectName)) {
|
|
appReply = APPRESPONSE_IGNORE;
|
|
} else {
|
|
appReply = IsmSendMessageToApp (TRANSPORTMESSAGE_SRC_COPY_ERROR, (ULONG_PTR)&transCopyError);
|
|
if ((appReply == APPRESPONSE_NONE) ||
|
|
(appReply == APPRESPONSE_FAIL)
|
|
) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
IsmAbortPersistentObjectEnum (&objEnum);
|
|
__leave;
|
|
}
|
|
}
|
|
if (appReply == APPRESPONSE_IGNORE) {
|
|
LOG ((LOG_WARNING, (PCSTR) MSG_IGNORE_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYWARNING, (ULONG_PTR)(&extraData));
|
|
break;
|
|
}
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
continue;
|
|
}
|
|
okSave = TRUE;
|
|
}
|
|
|
|
if (okSave) {
|
|
|
|
#ifdef UNICODE
|
|
convValue = &value;
|
|
#else
|
|
// now let's convert this object content to UNICODE
|
|
convValue = IsmConvertObjectContentToUnicode (objEnum.ObjectTypeId, objEnum.ObjectName, &value);
|
|
if (!convValue) {
|
|
convValue = &value;
|
|
}
|
|
#endif
|
|
decoratedObject = pOpaqueBuildDecoratedObject (objEnum.ObjectTypeId, objEnum.ObjectName);
|
|
|
|
ZeroMemory (&appInfo, sizeof (MIG_APPINFO));
|
|
appInfo.Phase = MIG_TRANSPORT_PHASE;
|
|
appInfo.SubPhase = SUBPHASE_COMPRESSING;
|
|
appInfo.ObjectTypeId = (objEnum.ObjectTypeId & (~PLATFORM_MASK));
|
|
appInfo.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (ISMMESSAGE_APP_INFO, (ULONG_PTR)(&appInfo));
|
|
|
|
if (convValue->ContentInFile) {
|
|
okSave = FALSE;
|
|
while (!okSave) {
|
|
if (!pOtSaveContentInFile (objEnum.ObjectTypeId, objEnum.ObjectName, decoratedObject, convValue, &compressedHandle)) {
|
|
if (GetLastError () == ERROR_DISK_FULL) {
|
|
// we just failed because we don't have enough space on the destination
|
|
// path. Let's tell that to the user
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATECABFILE;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
transCopyError.ObjectType = IsmGetObjectTypeName (objEnum.ObjectTypeId);
|
|
transCopyError.ObjectName = IsmGetNativeObjectName (objEnum.ObjectTypeId, objEnum.ObjectName);
|
|
transCopyError.Error = GetLastError ();
|
|
|
|
if (IsmIsNonCriticalObject (objEnum.ObjectTypeId, objEnum.ObjectName)) {
|
|
appReply = APPRESPONSE_IGNORE;
|
|
} else {
|
|
appReply = IsmSendMessageToApp (TRANSPORTMESSAGE_SRC_COPY_ERROR, (ULONG_PTR)&transCopyError);
|
|
if ((appReply == APPRESPONSE_NONE) ||
|
|
(appReply == APPRESPONSE_FAIL)
|
|
) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
IsmAbortPersistentObjectEnum (&objEnum);
|
|
__leave;
|
|
}
|
|
}
|
|
if (appReply == APPRESPONSE_IGNORE) {
|
|
LOG ((LOG_WARNING, (PCSTR) MSG_IGNORE_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYWARNING, (ULONG_PTR)(&extraData));
|
|
break;
|
|
}
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
continue;
|
|
}
|
|
okSave = TRUE;
|
|
}
|
|
size = convValue->FileContent.ContentSize;
|
|
} else {
|
|
okSave = FALSE;
|
|
while (!okSave) {
|
|
if (!pOtSaveContentInMemory (objEnum.ObjectTypeId, objEnum.ObjectName, decoratedObject, convValue)) {
|
|
if (GetLastError () == ERROR_DISK_FULL) {
|
|
// we just failed because we don't have enough space on the destination
|
|
// path. Let's tell that to the user
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATECABFILE;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
transCopyError.ObjectType = IsmGetObjectTypeName (objEnum.ObjectTypeId);
|
|
transCopyError.ObjectName = IsmGetNativeObjectName (objEnum.ObjectTypeId, objEnum.ObjectName);
|
|
transCopyError.Error = GetLastError ();
|
|
|
|
if (IsmIsNonCriticalObject (objEnum.ObjectTypeId, objEnum.ObjectName)) {
|
|
appReply = APPRESPONSE_IGNORE;
|
|
} else {
|
|
appReply = IsmSendMessageToApp (TRANSPORTMESSAGE_SRC_COPY_ERROR, (ULONG_PTR)&transCopyError);
|
|
if ((appReply == APPRESPONSE_NONE) ||
|
|
(appReply == APPRESPONSE_FAIL)
|
|
) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
IsmAbortPersistentObjectEnum (&objEnum);
|
|
__leave;
|
|
}
|
|
}
|
|
if (appReply == APPRESPONSE_IGNORE) {
|
|
LOG ((LOG_WARNING, (PCSTR) MSG_IGNORE_COPYSOURCE, transCopyError.ObjectName));
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEOBJECT;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = objEnum.ObjectTypeId;
|
|
extraData.ObjectName = objEnum.ObjectName;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYWARNING, (ULONG_PTR)(&extraData));
|
|
break;
|
|
}
|
|
IsmReleaseMemory (transCopyError.ObjectName);
|
|
continue;
|
|
}
|
|
okSave = TRUE;
|
|
}
|
|
size = convValue->MemoryContent.ContentSize;
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
if (convValue != (&value)) {
|
|
IsmFreeConvertedObjectContent (objEnum.ObjectTypeId, convValue);
|
|
}
|
|
#endif
|
|
IsmReleaseObject (&value);
|
|
|
|
pOtDestroyDecoratedObject (decoratedObject);
|
|
decoratedObject = NULL;
|
|
}
|
|
|
|
IsmTickProgressBar (g_PersistentSlice, 1);
|
|
|
|
if (IsmCheckCancel()) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Send bytes saved to app every 3 seconds
|
|
//
|
|
|
|
bytesSaved += size;
|
|
|
|
if (GetTickCount() - lastTick > 3000) {
|
|
|
|
if (bytesSaved < 1048576) {
|
|
wsprintf (text, TEXT("Saved: %u K"), (UINT) (bytesSaved / 1024));
|
|
} else if (bytesSaved < 8388608) {
|
|
fraction = (UINT) (bytesSaved / 10485);
|
|
wsprintf (text, TEXT("Saved: %u.%02u M"), fraction / 100, fraction % 100);
|
|
} else if (bytesSaved < 1073741824) {
|
|
wsprintf (text, TEXT("Saved: %u M"), (UINT) (bytesSaved / 1048576));
|
|
} else {
|
|
fraction = (UINT) (bytesSaved / 10737418);
|
|
wsprintf (text, TEXT("Saved: %u.%02u G"), fraction / 100, fraction % 100);
|
|
}
|
|
|
|
IsmSendMessageToApp (TRANSPORTMESSAGE_SIZE_SAVED, (ULONG_PTR) text);
|
|
|
|
lastTick = GetTickCount();
|
|
}
|
|
|
|
} while (IsmEnumNextPersistentObject (&objEnum));
|
|
}
|
|
|
|
if (IsmCheckCancel()) {
|
|
__leave;
|
|
}
|
|
|
|
ZeroMemory (&appInfo, sizeof (MIG_APPINFO));
|
|
appInfo.Phase = MIG_TRANSPORT_PHASE;
|
|
appInfo.SubPhase = SUBPHASE_FINISHING;
|
|
IsmSendMessageToApp (ISMMESSAGE_APP_INFO, (ULONG_PTR)(&appInfo));
|
|
|
|
if (Compressed) {
|
|
ourDbFile = JoinPaths (g_TransportTempPath, S_TRANSPORT_DAT_FILE);
|
|
} else {
|
|
ourDbFile = pOpaqueAllocStorageFileName (S_TRANSPORT_DAT_FILE);
|
|
if (!ourDbFile) {
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEINTERNALDATA;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
if (!MemDbSave (ourDbFile)) {
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEINTERNALDATA;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
IsmTickProgressBar (g_DatabaseSlice, 1);
|
|
|
|
if (Compressed) {
|
|
if (IsmCheckCancel()) {
|
|
__leave;
|
|
}
|
|
|
|
if (!pOtAddFileToImage (ourDbFile, S_TRANSPORT_DAT_FILE, &compressedHandle)) {
|
|
extraData.Error = ERRUSER_ERROR_CANTSAVEINTERNALDATA;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
IsmTickProgressBar (g_DatabaseSlice, 1);
|
|
|
|
if (IsmCheckCancel()) {
|
|
__leave;
|
|
}
|
|
|
|
if (!CompressFlushAndCloseHandle (&compressedHandle)) {
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATECABFILE;
|
|
extraData.ErrorArea = ERRUSER_AREA_SAVE;
|
|
extraData.ObjectTypeId = 0;
|
|
extraData.ObjectName = NULL;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
__leave;
|
|
}
|
|
|
|
IsmTickProgressBar (g_DatabaseSlice, 1);
|
|
|
|
if (IsmCheckCancel()) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
IsmSendMessageToApp (TRANSPORTMESSAGE_SIZE_SAVED, 0);
|
|
result = TRUE;
|
|
|
|
}
|
|
__finally {
|
|
PushError ();
|
|
CompressCleanupHandle (&compressedHandle);
|
|
|
|
pFreeStorageFileName (ourDbFile);
|
|
INVALID_POINTER (ourDbFile);
|
|
|
|
pOtDestroyDecoratedObject (decoratedObject);
|
|
INVALID_POINTER (decoratedObject);
|
|
|
|
if (g_OtCompressData && g_TransportTempPath) {
|
|
pOtCleanUpTempDir ();
|
|
}
|
|
PopError ();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportAcquireObject (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN MIG_OBJECTSTRINGHANDLE ObjectName,
|
|
OUT PMIG_CONTENT ObjectContent, CALLER_INITIALIZED
|
|
IN MIG_CONTENTTYPE ContentType,
|
|
IN UINT MemoryContentLimit
|
|
)
|
|
{
|
|
UINT value;
|
|
PCBYTE memValue;
|
|
UINT memValueSize;
|
|
PCTSTR fileValue = NULL;
|
|
PCTSTR newFileValue = NULL;
|
|
BOOL valueInFile;
|
|
KEYHANDLE keyHandle;
|
|
PALLOCSTATE allocState;
|
|
PCTSTR detailsKey = NULL;
|
|
PBYTE details;
|
|
UINT detailsSize;
|
|
PCTSTR sourceFile;
|
|
PCTSTR decoratedObject = NULL;
|
|
HANDLE fileHandle;
|
|
BOOL result = FALSE;
|
|
|
|
if (!ObjectContent) {
|
|
return FALSE;
|
|
}
|
|
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
MYASSERT ((ObjectTypeId & PLATFORM_MASK) == PLATFORM_SOURCE);
|
|
|
|
decoratedObject = pOpaqueBuildDecoratedObject (ObjectTypeId, ObjectName);
|
|
|
|
allocState = (PALLOCSTATE) MemAllocZeroed (sizeof (ALLOCSTATE));
|
|
|
|
if (MemDbGetValue (decoratedObject, &value)) {
|
|
if (value == TRFLAG_FILE) {
|
|
valueInFile = TRUE;
|
|
keyHandle = MemDbGetSingleLinkage (decoratedObject, 0, 0);
|
|
if (keyHandle) {
|
|
fileValue = MemDbGetKeyFromHandle (keyHandle, 0);
|
|
newFileValue = pOpaqueGetNewFileName (fileValue);
|
|
result = fileValue != NULL;
|
|
} else {
|
|
fileValue = NULL;
|
|
result = TRUE;
|
|
}
|
|
} else if (value == TRFLAG_MEMORY) {
|
|
valueInFile = FALSE;
|
|
memValueSize = 0;
|
|
memValue = MemDbGetUnorderedBlob (decoratedObject, 0, &memValueSize);
|
|
result = TRUE;
|
|
} else {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_UNSUPPORTED_DATA, value));
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
}
|
|
if (result) {
|
|
result = FALSE;
|
|
|
|
if (valueInFile) {
|
|
if ((ContentType == CONTENTTYPE_ANY) ||
|
|
(ContentType == CONTENTTYPE_FILE) ||
|
|
(ContentType == CONTENTTYPE_DETAILS_ONLY)
|
|
) {
|
|
// this is stored as a file and it's wanted as a file
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
if (fileValue) {
|
|
ObjectContent->FileContent.ContentPath = JoinPaths (pGetRealTransportPath (), newFileValue?newFileValue:fileValue);
|
|
ObjectContent->FileContent.ContentSize = BfGetFileSize (ObjectContent->FileContent.ContentPath);
|
|
} else {
|
|
ObjectContent->FileContent.ContentSize = 0;
|
|
ObjectContent->FileContent.ContentPath = NULL;
|
|
}
|
|
result = TRUE;
|
|
} else {
|
|
// this is stored as a file and it's wanted as memory
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = FALSE;
|
|
if (fileValue) {
|
|
sourceFile = JoinPaths (pGetRealTransportPath (), newFileValue?newFileValue:fileValue);
|
|
ObjectContent->MemoryContent.ContentSize = (UINT) BfGetFileSize (sourceFile);
|
|
ObjectContent->MemoryContent.ContentBytes = MapFileIntoMemory (
|
|
sourceFile,
|
|
&allocState->FileHandle,
|
|
&allocState->MapHandle
|
|
);
|
|
FreePathString (sourceFile);
|
|
result = (ObjectContent->MemoryContent.ContentBytes != NULL);
|
|
} else {
|
|
ObjectContent->MemoryContent.ContentSize = 0;
|
|
ObjectContent->MemoryContent.ContentBytes = NULL;
|
|
result = TRUE;
|
|
}
|
|
}
|
|
if (newFileValue) {
|
|
FreePathString (newFileValue);
|
|
newFileValue = NULL;
|
|
}
|
|
if (fileValue) {
|
|
MemDbReleaseMemory (fileValue);
|
|
fileValue = NULL;
|
|
}
|
|
} else {
|
|
if ((ContentType == CONTENTTYPE_ANY) ||
|
|
(ContentType == CONTENTTYPE_MEMORY) ||
|
|
(ContentType == CONTENTTYPE_DETAILS_ONLY)
|
|
) {
|
|
// this is stored as memory and it's wanted as memory
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = FALSE;
|
|
ObjectContent->MemoryContent.ContentSize = memValueSize;
|
|
ObjectContent->MemoryContent.ContentBytes = memValue;
|
|
result = TRUE;
|
|
} else {
|
|
// this is stored as memory and it's wanted as a file
|
|
if (memValue) {
|
|
if (IsmGetTempFile (allocState->TempFile, ARRAYSIZE(allocState->TempFile))) {
|
|
fileHandle = BfCreateFile (allocState->TempFile);
|
|
if (fileHandle) {
|
|
if (BfWriteFile (fileHandle, memValue, memValueSize)) {
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
ObjectContent->FileContent.ContentSize = memValueSize;
|
|
ObjectContent->FileContent.ContentPath = DuplicatePathString (allocState->TempFile, 0);
|
|
result = TRUE;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
}
|
|
}
|
|
MemDbReleaseMemory (memValue);
|
|
} else {
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
ObjectContent->FileContent.ContentSize = 0;
|
|
ObjectContent->FileContent.ContentPath = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
}
|
|
|
|
if (result) {
|
|
//
|
|
// Fill the details
|
|
//
|
|
|
|
detailsKey = JoinText (S_DETAILS_PREFIX, decoratedObject);
|
|
|
|
details = MemDbGetUnorderedBlob (detailsKey, 0, &detailsSize);
|
|
|
|
if (!details) {
|
|
detailsSize = 0;
|
|
}
|
|
|
|
allocState->DetailsPtr = details;
|
|
|
|
ObjectContent->Details.DetailsSize = detailsSize;
|
|
ObjectContent->Details.DetailsData = details;
|
|
|
|
FreeText (detailsKey);
|
|
|
|
ObjectContent->TransHandle = allocState;
|
|
}
|
|
|
|
if (!result) {
|
|
FreeAlloc (allocState);
|
|
}
|
|
|
|
FreePathString (decoratedObject);
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
OpaqueTransportReleaseObject (
|
|
IN OUT PMIG_CONTENT ObjectContent
|
|
)
|
|
{
|
|
PALLOCSTATE allocState;
|
|
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
|
|
allocState = (PALLOCSTATE) ObjectContent->TransHandle;
|
|
|
|
if (ObjectContent->ContentInFile) {
|
|
FreePathString (ObjectContent->FileContent.ContentPath);
|
|
if (allocState && allocState->TempFile[0]) {
|
|
DeleteFile (allocState->TempFile);
|
|
}
|
|
} else {
|
|
if (allocState && allocState->FileHandle && allocState->MapHandle) {
|
|
UnmapFile (
|
|
ObjectContent->MemoryContent.ContentBytes,
|
|
allocState->MapHandle,
|
|
allocState->FileHandle
|
|
);
|
|
} else {
|
|
MemDbReleaseMemory (ObjectContent->MemoryContent.ContentBytes);
|
|
}
|
|
}
|
|
|
|
if (allocState && allocState->DetailsPtr) {
|
|
MemDbReleaseMemory (allocState->DetailsPtr);
|
|
}
|
|
|
|
FreeAlloc (allocState);
|
|
|
|
return TRUE;
|
|
}
|
|
|