Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1127 lines
26 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
decomp.c
Abstract:
File decompression support routines.
Author:
Ted Miller (tedm) 1-Feb-1995
Revision History:
--*/
#include "setupntp.h"
#pragma hdrstop
#include <pshpack1.h>
struct LZINFO;
typedef struct LZINFO *PLZINFO;
#include "..\..\shell\lz\libs\header.h"
#include <poppack.h>
typedef struct _SFD_INFO {
unsigned FileCount;
PCTSTR TargetFile;
BOOL GotTimestamp;
FILETIME FileTime;
} SFD_INFO, *PSFD_INFO;
UINT
pGetCompressInfoCB(
IN PVOID Context,
IN UINT Notification,
IN UINT Param1,
IN UINT Param2
);
UINT
pSingleFileDecompCB(
IN PVOID Context,
IN UINT Notification,
IN UINT Param1,
IN UINT Param2
);
PTSTR
SetupGenerateCompressedName(
IN PCTSTR Filename
)
/*++
Routine Description:
Given a filename, generate the compressed form of the name.
The compressed form is generated as follows:
Look backwards for a dot. If there is no dot, append "._" to the name.
If there is a dot followed by 0, 1, or 2 charcaters, append "_".
Otherwise there is a 3-character or greater extension and we replace
the last character with "_".
Arguments:
Filename - supplies filename whose compressed form is desired.
Return Value:
Pointer to buffer containing nul-terminated compressed-form filename.
The caller must free this buffer via MyFree().
--*/
{
PTSTR CompressedName,p,q;
UINT u;
//
// The maximum length of the compressed filename is the length of the
// original name plus 2 (for ._).
//
if(CompressedName = MyMalloc((lstrlen(Filename)+3)*sizeof(TCHAR))) {
lstrcpy(CompressedName,Filename);
p = _tcsrchr(CompressedName,TEXT('.'));
q = _tcsrchr(CompressedName,TEXT('\\'));
if(q < p) {
//
// If there are 0, 1, or 2 characters after the dot, just append
// the underscore. p points to the dot so include that in the length.
//
u = lstrlen(p);
if(u < 4) {
lstrcat(CompressedName,TEXT("_"));
} else {
//
// There are at least 3 characters in the extension.
// Replace the final one with an underscore.
//
p[u-1] = TEXT('_');
}
} else {
//
// No dot, just add ._.
//
lstrcat(CompressedName,TEXT("._"));
}
}
return(CompressedName);
}
DWORD
pSetupAttemptLocate(
IN PCTSTR FileName,
OUT PBOOL Found,
OUT PWIN32_FIND_DATA FindData
)
/*++
Routine Description:
Attempt to locate a source file via FindFirstFile().
Errors of the 'file not found' type are not considered errors
and result in NO_ERROR. Any non-NO_ERROR return indicates that
we could not determine whether the file is present or not
because of some hardware or system problem, etc.
Arguments:
FileName - supplies filename of the file to be located.
Found - receives a value indicating whether the file was found.
This value is only valid when the function returns NO_ERROR.
FindData - if found, returns win32 find data for the file.
Return Value:
Win32 error code indicating the outcome. If NO_ERROR, check
the Found return value to see whether the file was found.
--*/
{
DWORD d;
if(*Found = FileExists(FileName,FindData)) {
d = NO_ERROR;
} else {
//
// We didn't find the file. See whether that was because
// the file wasn't there or because some other error occured.
//
d = GetLastError();
if((d == ERROR_NO_MORE_FILES)
|| (d == ERROR_FILE_NOT_FOUND)
|| (d == ERROR_PATH_NOT_FOUND)
|| (d == ERROR_BAD_NETPATH))
{
d = NO_ERROR;
}
}
return(d);
}
DWORD
SetupDetermineSourceFileName(
IN PCTSTR FileName,
OUT PBOOL UsedCompressedName,
OUT PTSTR *FileNameLocated,
OUT PWIN32_FIND_DATA FindData
)
/*++
Routine Description:
Attempt to locate a source file whose name can be compressed
or uncompressed.
The order of attempt is
- the name as given (should be the uncompressed name)
- the compressed form, using _ as the compression char
- the compressed form, using $ as the compression char
Arguments:
FileName - supplies filename of the file to be located.
UsedCompressedName - receives a boolean indicating whether
the filename we located seems to indicate that the file
is compressed.
FileNameLocated - receives a pointer to the filename actually
located. The caller must free with MyFree().
FindData - if found, returns win32 find data for the file.
Return Value:
Win32 error code indicating the outcome.
ERROR_FILE_NOT_FOUND - normal code indicating everything is ok
but we can't find the file
NO_ERROR - file was located; check UsedCompressedName and FileNameOpened.
Others - something is wrong with the hardware or system.
--*/
{
DWORD d;
PTSTR TryName;
BOOL Found;
TryName = DuplicateString(FileName);
if(!TryName) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
*UsedCompressedName = FALSE;
*FileNameLocated = TryName;
d = pSetupAttemptLocate(TryName,&Found,FindData);
if(d != NO_ERROR) {
MyFree(TryName);
return(d);
}
if(Found) {
return(NO_ERROR);
}
MyFree(TryName);
*UsedCompressedName = TRUE;
TryName = SetupGenerateCompressedName(FileName);
if(!TryName) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
*FileNameLocated = TryName;
d = pSetupAttemptLocate(TryName,&Found,FindData);
if(d != NO_ERROR) {
MyFree(TryName);
return(d);
}
if(Found) {
return(NO_ERROR);
}
MYASSERT(TryName[lstrlen(TryName)-1] == TEXT('_'));
TryName[lstrlen(TryName)-1] = TEXT('$');
d = pSetupAttemptLocate(TryName,&Found,FindData);
if((d != NO_ERROR) || !Found) {
*FileNameLocated = NULL;
MyFree(TryName);
}
return(Found ? NO_ERROR : ERROR_FILE_NOT_FOUND);
}
DWORD
pSetupDecompressWinLzFile(
IN PTSTR SourceFileName,
IN PTSTR TargetFileName
)
/*++
Routine Description:
Determine whether a file is compressed, and retreive additional
information about it.
Arguments:
SourceFileName - supplies filename of the file to be checked.
This filename is used as a base; if not found then we look
for the 2 compressed forms (ie, foo.ex_, foo.ex$) as well.
ActualSourceFileName - receives a pointer to the filename
that was actually located. Caller can free with MyFree().
Valid only if the return code from this routine is NO_ERROR.
SourceFileSize - receives the size of the located file in its
current (ie, compressed) form. Valid only if this routine
returns NO_ERROR.
TargetFileSize - receives the uncompressed size of the file.
If the file is not compressed this will be the same as
SourceFileSize. Valid only if this routine returns NO_ERROR.
CompressionType - receives a value indicating the compression type.
Valid only if this routine returns NO_ERROR.
Return Value:
Win32 error code indicating the outcome.
ERROR_FILE_NOT_FOUND - normal code indicating everything is ok
but we can't find the file
NO_ERROR - file was located and output params are filled in.
Others - something is wrong with the hardware or system.
--*/
{
INT hSrc,hDst;
OFSTRUCT ofSrc,ofDst;
LONG l;
DWORD d;
FILETIME CreateTime,AccessTime,WriteTime;
//
// Get the timestamp of the source.
//
d = GetSetFileTimestamp(
SourceFileName,
&CreateTime,
&AccessTime,
&WriteTime,
FALSE
);
if(d != NO_ERROR) {
return(d);
}
hSrc = LZOpenFile(SourceFileName,&ofSrc,OF_READ|OF_SHARE_DENY_WRITE);
if(hSrc >= 0) {
hDst = LZOpenFile(TargetFileName,&ofSrc,OF_CREATE|OF_WRITE|OF_SHARE_EXCLUSIVE);
if(hDst >= 0) {
l = LZCopy(hSrc,hDst);
if(l >= 0) {
l = 0;
//
// Set the timestamp of the target. The file is already there
// so just ignore errors.
//
GetSetFileTimestamp(
TargetFileName,
&CreateTime,
&AccessTime,
&WriteTime,
TRUE
);
}
LZClose(hDst);
} else {
l = hDst;
}
LZClose(hSrc);
} else {
l = hSrc;
}
//
// lz error to win32 error
//
switch(l) {
case 0:
return(NO_ERROR);
case LZERROR_BADINHANDLE:
case LZERROR_READ:
return(ERROR_READ_FAULT);
case LZERROR_BADOUTHANDLE:
case LZERROR_WRITE:
return(ERROR_WRITE_FAULT);
case LZERROR_GLOBALLOC:
case LZERROR_GLOBLOCK:
return(ERROR_NOT_ENOUGH_MEMORY);
case LZERROR_BADVALUE:
case LZERROR_UNKNOWNALG:
return(ERROR_INVALID_DATA);
default:
return(ERROR_INVALID_FUNCTION);
}
}
DWORD
SetupInternalGetFileCompressionInfo(
IN PCTSTR SourceFileName,
OUT PTSTR *ActualSourceFileName,
OUT PWIN32_FIND_DATA SourceFindData,
OUT PDWORD TargetFileSize,
OUT PUINT CompressionType
)
/*++
Routine Description:
Determine whether a file is compressed, and retreive additional
information about it.
Arguments:
SourceFileName - supplies filename of the file to be checked.
This filename is used as a base; if not found then we look
for the 2 compressed forms (ie, foo.ex_, foo.ex$) as well.
ActualSourceFileName - receives a pointer to the filename
that was actually located. Caller can free with MyFree().
Valid only if the return code from this routine is NO_ERROR.
SourceFindData - receives win32 find data for the located file in its
current (ie, compressed) form. Valid only if this routine
returns NO_ERROR.
TargetFileSize - receives the uncompressed size of the file.
If the file is not compressed this will be the same as
SourceFileSize. Valid only if this routine returns NO_ERROR.
CompressionType - receives a value indicating the compression type.
Valid only if this routine returns NO_ERROR.
Return Value:
Win32 error code indicating the outcome.
ERROR_FILE_NOT_FOUND - normal code indicating everything is ok
but we can't find the file
NO_ERROR - file was located and output params are filled in.
Others - something is wrong with the hardware or system.
--*/
{
DWORD d;
BOOL b;
HANDLE hFile,hMapping;
DWORD size;
FH UNALIGNED *LZHeader;
d = SetupDetermineSourceFileName(
SourceFileName,
&b,
ActualSourceFileName,
SourceFindData
);
if(d != NO_ERROR) {
return(d);
}
//
// If the file is 0-length it isn't compressed;
// trying to map it in below will fail in this case.
//
if(SourceFindData->nFileSizeLow) {
//
// See if it's a diamond file.
//
d = DiamondProcessCabinet(
*ActualSourceFileName,
0,
pGetCompressInfoCB,
&size,
TRUE
);
if(d == NO_ERROR) {
*TargetFileSize = size;
*CompressionType = FILE_COMPRESSION_MSZIP;
return(NO_ERROR);
}
//
// See if it's a WINLZ file.
//
d = OpenAndMapFileForRead(
*ActualSourceFileName,
&SourceFindData->nFileSizeLow,
&hFile,
&hMapping,
(PVOID *)&LZHeader
);
if(d != NO_ERROR) {
MyFree(*ActualSourceFileName);
return(d);
}
b = FALSE;
try {
if((SourceFindData->nFileSizeLow >= HEADER_LEN)
&& !memcmp(LZHeader->rgbyteMagic,COMP_SIG,COMP_SIG_LEN)
&& RecognizeCompAlg(LZHeader->byteAlgorithm))
{
*TargetFileSize = LZHeader->cbulUncompSize;
b = TRUE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
;
}
UnmapAndCloseFile(hFile,hMapping,LZHeader);
if(b) {
*CompressionType = FILE_COMPRESSION_WINLZA;
return(NO_ERROR);
}
}
//
// File is not compressed.
//
*CompressionType = FILE_COMPRESSION_NONE;
*TargetFileSize = SourceFindData->nFileSizeLow;
return(NO_ERROR);
}
UINT
pGetCompressInfoCB(
IN PVOID Context,
IN UINT Notification,
IN UINT Param1,
IN UINT Param2
)
{
PFILE_IN_CABINET_INFO FileInfo;
DWORD rc;
switch(Notification) {
case SPFILENOTIFY_CABINETINFO:
//
// We don't do anything with this.
//
rc = NO_ERROR;
break;
case SPFILENOTIFY_FILEINCABINET:
//
// New file within a cabinet.
//
// We don't ever want to copy the file. Save size info
// and abort.
//
FileInfo = (PFILE_IN_CABINET_INFO)Param1;
*((PDWORD)Context) = FileInfo->FileSize;
FileInfo->Win32Error = NO_ERROR;
rc = FILEOP_ABORT;
break;
//case SPFILENOTIFY_FILEEXTRACTED:
//case SPFILENOTIFY_NEEDNEWCABINET:
default:
//
// We should never get these.
//
MYASSERT(0);
rc = ERROR_INVALID_FUNCTION;
break;
}
return(rc);
}
#ifdef UNICODE
//
// ANSI version
//
DWORD
SetupGetFileCompressionInfoA(
IN PCSTR SourceFileName,
OUT PSTR *ActualSourceFileName,
OUT PDWORD SourceFileSize,
OUT PDWORD TargetFileSize,
OUT PUINT CompressionType
)
{
WIN32_FIND_DATA FindData;
DWORD d;
PCWSTR source;
PWSTR actualsource;
PSTR actualsourceansi;
DWORD targetsize;
UINT type;
d = CaptureAndConvertAnsiArg(SourceFileName,&source);
if(d != NO_ERROR) {
return(d);
}
d = SetupInternalGetFileCompressionInfo(source,&actualsource,&FindData,&targetsize,&type);
if(d == NO_ERROR) {
if(actualsourceansi = UnicodeToAnsi(actualsource)) {
try {
*SourceFileSize = FindData.nFileSizeLow;
*ActualSourceFileName = actualsourceansi;
*TargetFileSize = targetsize;
*CompressionType = type;
} except(EXCEPTION_EXECUTE_HANDLER) {
d = ERROR_INVALID_PARAMETER;
}
if(d != NO_ERROR) {
MyFree(actualsourceansi);
}
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
MyFree(actualsource);
}
MyFree(source);
return(d);
}
#else
//
// Unicode stub
//
DWORD
SetupGetFileCompressionInfoW(
IN PCWSTR SourceFileName,
OUT PWSTR *ActualSourceFileName,
OUT PDWORD SourceFileSize,
OUT PDWORD TargetFileSize,
OUT PUINT CompressionType
)
{
UNREFERENCED_PARAMETER(SourceFileName);
UNREFERENCED_PARAMETER(ActualSourceFileName);
UNREFERENCED_PARAMETER(SourceFileSize);
UNREFERENCED_PARAMETER(TargetFileSize);
UNREFERENCED_PARAMETER(CompressionType);
return(ERROR_CALL_NOT_IMPLEMENTED);
}
#endif
DWORD
SetupGetFileCompressionInfo(
IN PCTSTR SourceFileName,
OUT PTSTR *ActualSourceFileName,
OUT PDWORD SourceFileSize,
OUT PDWORD TargetFileSize,
OUT PUINT CompressionType
)
/*++
Routine Description:
Determine whether a file is compressed, and retreive additional
information about it.
Arguments:
SourceFileName - supplies filename of the file to be checked.
This filename is used as a base; if not found then we look
for the 2 compressed forms (ie, foo.ex_, foo.ex$) as well.
ActualSourceFileName - receives a pointer to the filename
that was actually located. Caller can free with MyFree().
Valid only if the return code from this routine is NO_ERROR.
SourceFileSize - receives the size of the located file in its
current (ie, compressed) form. Valid only if this routine
returns NO_ERROR.
TargetFileSize - receives the uncompressed size of the file.
If the file is not compressed this will be the same as
SourceFileSize. Valid only if this routine returns NO_ERROR.
CompressionType - receives a value indicating the compression type.
Valid only if this routine returns NO_ERROR.
Return Value:
Win32 error code indicating the outcome.
ERROR_FILE_NOT_FOUND - normal code indicating everything is ok
but we can't find the file
NO_ERROR - file was located and output params are filled in.
Others - something is wrong with the hardware or system.
--*/
{
WIN32_FIND_DATA FindData;
DWORD d;
PCTSTR source;
PTSTR actualsource;
DWORD targetsize;
UINT type;
d = CaptureStringArg(SourceFileName,&source);
if(d != NO_ERROR) {
return(d);
}
d = SetupInternalGetFileCompressionInfo(source,&actualsource,&FindData,&targetsize,&type);
if(d == NO_ERROR) {
try {
*SourceFileSize = FindData.nFileSizeLow;
*ActualSourceFileName = actualsource;
*TargetFileSize = targetsize;
*CompressionType = type;
} except(EXCEPTION_EXECUTE_HANDLER) {
d = ERROR_INVALID_PARAMETER;
}
if(d != NO_ERROR) {
MyFree(actualsource);
}
}
MyFree(source);
return(d);
}
#ifdef UNICODE
//
// ANSI version
//
DWORD
SetupDecompressOrCopyFileA(
IN PCSTR SourceFileName,
OUT PCSTR TargetFileName,
OUT PUINT CompressionType OPTIONAL
)
{
DWORD rc;
PCWSTR s,t;
rc = CaptureAndConvertAnsiArg(SourceFileName,&s);
if(rc == NO_ERROR) {
rc = CaptureAndConvertAnsiArg(TargetFileName,&t);
if(rc == NO_ERROR) {
rc = pSetupDecompressOrCopyFile(s,t,CompressionType,FALSE,NULL);
MyFree(t);
}
MyFree(s);
}
return(rc);
}
#else
//
// Unicode stub
//
DWORD
SetupDecompressOrCopyFileW(
IN PCWSTR SourceFileName,
OUT PCWSTR TargetFileName,
OUT PUINT CompressionType OPTIONAL
)
{
UNREFERENCED_PARAMETER(SourceFileName);
UNREFERENCED_PARAMETER(TargetFileName);
UNREFERENCED_PARAMETER(CompressionType);
return(ERROR_CALL_NOT_IMPLEMENTED);
}
#endif
DWORD
SetupDecompressOrCopyFile(
IN PCTSTR SourceFileName,
IN PCTSTR TargetFileName,
IN PUINT CompressionType OPTIONAL
)
/*++
Routine Description:
Decompress or copy a file.
Arguments:
SourceFileName - supplies filename of the file to be decompressed.
If CompressionType is specified, no additional processing is
performed on this name -- the caller is responsible for determining
the actual file name (ie, foo.ex_ instead of foo.exe) before calling
this routine. If CompressionType is not specified, then this routine
attempts to locate the compressed form of the filename if the file
is not found with the name given.
TargetFileName - supplies filename of target file.
CompressionType - if specified, supplies type of compression in use
on the source. This can be determined by calling
SetupGetFileCompressionInfo(). Specifying FILE_COMPRESSION_NONE
results in the file being copied and not decompressed,
regardless of the type of compression that may be in use on the source.
If this value is not specified then this routine attempts to determine
the compression type and decompresses/copies accordingly.
Return Value:
Win32 error code indicating the outcome.
--*/
{
DWORD rc;
PCTSTR s,t;
rc = CaptureStringArg(SourceFileName,&s);
if(rc == NO_ERROR) {
rc = CaptureStringArg(TargetFileName,&t);
if(rc == NO_ERROR) {
rc = pSetupDecompressOrCopyFile(s,t,CompressionType,FALSE,NULL);
MyFree(t);
}
MyFree(s);
}
return(rc);
}
DWORD
pSetupDecompressOrCopyFile(
IN PCTSTR SourceFileName,
IN PCTSTR TargetFileName,
IN PUINT CompressionType, OPTIONAL
IN BOOL AllowMove,
OUT PBOOL Moved OPTIONAL
)
/*++
Routine Description:
Decompress or copy a file.
Arguments:
SourceFileName - supplies filename of the file to be decompressed.
If CompressionType is specified, no additional processing is
performed on this name -- the caller is responsible for determining
the actual file name (ie, foo.ex_ instead of foo.exe) before calling
this routine. If CompressionType is not specified, then this routine
attempts to locate the compressed form of the filename if the file
is not found with the name given.
TargetFileName - supplies filename of target file.
CompressionType - if specified, supplies type of compression in use
on the source. This can be determined by calling
SetupGetFileCompressionInfo(). Specifying FILE_COMPRESSION_NONE
results in the file being copied and not decompressed,
regardless of the type of compression that may be in use on the source.
If this value is not specified then this routine attempts to determine
the compression type and decompresses/copies accordingly.
AllowMove - if specified, then files that do not require decompression
will be moved instead of copied.
Moved - if specified receives a boolean indicating whether the file was
moved (as opposed to copied or decompressed).
Return Value:
Win32 error code indicating the outcome.
--*/
{
DWORD d;
UINT ComprType;
PTSTR ActualName;
DWORD SourceSize,TargetSize;
FILETIME CreateTime,AccessTime,WriteTime;
SFD_INFO CBData;
BOOL moved;
if(Moved) {
*Moved = FALSE;
}
if(CompressionType) {
ComprType = *CompressionType;
ActualName = (PTSTR)SourceFileName;
} else {
//
// Need to determine compresison type.
//
d = SetupGetFileCompressionInfo(
SourceFileName,
&ActualName,
&SourceSize,
&TargetSize,
&ComprType
);
if(d != NO_ERROR) {
return(d);
}
}
//
// Blast the target file. Ignore if failure -- it'll be caught later.
//
SetFileAttributes(TargetFileName,FILE_ATTRIBUTE_NORMAL);
DeleteFile(TargetFileName);
switch(ComprType) {
case FILE_COMPRESSION_NONE:
moved = (AllowMove ? MoveFile(ActualName,TargetFileName) : FALSE);
if(moved) {
d = NO_ERROR;
if(Moved) {
*Moved = TRUE;
}
} else {
d = GetSetFileTimestamp(ActualName,&CreateTime,&AccessTime,&WriteTime,FALSE);
if(d == NO_ERROR) {
d = CopyFile(ActualName,TargetFileName,FALSE) ? NO_ERROR : GetLastError();
if(d == NO_ERROR) {
GetSetFileTimestamp(TargetFileName,&CreateTime,&AccessTime,&WriteTime,TRUE);
}
}
}
break;
case FILE_COMPRESSION_WINLZA:
d = pSetupDecompressWinLzFile(ActualName,(PTSTR)TargetFileName);
break;
case FILE_COMPRESSION_MSZIP:
CBData.FileCount = 0;
CBData.TargetFile = TargetFileName;
CBData.GotTimestamp = FALSE;
d = DiamondProcessCabinet(
ActualName,
0,
pSingleFileDecompCB,
&CBData,
TRUE
);
break;
default:
d = ERROR_INVALID_PARAMETER;
break;
}
if(!CompressionType) {
MyFree(ActualName);
}
return(d);
}
UINT
pSingleFileDecompCB(
IN PVOID Context,
IN UINT Notification,
IN UINT Param1,
IN UINT Param2
)
{
PSFD_INFO Data;
PFILE_IN_CABINET_INFO FileInfo;
PFILEPATHS FilePaths;
DWORD rc;
HANDLE h;
Data = Context;
switch(Notification) {
case SPFILENOTIFY_CABINETINFO:
//
// We don't do anything with this.
//
rc = NO_ERROR;
break;
case SPFILENOTIFY_FILEINCABINET:
//
// New file within a cabinet.
//
FileInfo = (PFILE_IN_CABINET_INFO)Param1;
FileInfo->Win32Error = NO_ERROR;
//
// We only want the first file. If this is a subsequent file,
// bail out.
//
if(Data->FileCount++) {
rc = FILEOP_ABORT;
} else {
//
// We want the file. Ignore the names in the cabinet and
// use the name given to us. Also, we want to preserve
// the timestamp of the cabinet, not of the file within it.
//
lstrcpyn(FileInfo->FullTargetName,Data->TargetFile,MAX_PATH);
h = CreateFile(
(PCTSTR)Param2, // cabinet filename
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(h != INVALID_HANDLE_VALUE) {
if(GetFileTime(h,NULL,NULL,&Data->FileTime)) {
Data->GotTimestamp = TRUE;
}
CloseHandle(h);
}
rc = FILEOP_DOIT;
}
break;
case SPFILENOTIFY_FILEEXTRACTED:
//
// File was successfully extracted.
// Preserve timestamp.
//
FilePaths = (PFILEPATHS)Param1;
if(Data->GotTimestamp) {
h = CreateFile(
FilePaths->Target,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(h != INVALID_HANDLE_VALUE) {
SetFileTime(h,NULL,NULL,&Data->FileTime);
CloseHandle(h);
}
}
rc = NO_ERROR;
break;
//case SPFILENOTIFY_NEEDNEWCABINET:
default:
//
// We should never get this.
//
MYASSERT(0);
rc = ERROR_INVALID_FUNCTION;
break;
}
return(rc);
}