📄 cabinet.c
字号:
wcscpy( Search->Cabinet, CabinetName );
if (DiskChangeHandler != NULL)
{
DiskChangeHandler(CabinetNext, DiskNext);
}
Status = CabinetOpen();
if (Status != CAB_STATUS_SUCCESS)
return Status;
}
else
{
return CAB_STATUS_NOFILE;
}
// starting new search or cabinet
Search->File = (PCFFILE)(FileBuffer + PCABHeader->FileTableOffset);
Search->Index = 0;
Prev = 0;
}
else Search->File = (PCFFILE)(strchr( (char *)(Search->File + 1), 0 ) + 1);
}
DPRINT( "Found file %s\n", Search->File->FileName );
return CAB_STATUS_SUCCESS;
}
int Validate()
{
return (int)RtlValidateHeap(ProcessHeap, 0, 0);
}
ULONG CabinetExtractFile( PCAB_SEARCH Search )
/*
* FUNCTION: Extracts a file from the cabinet
* ARGUMENTS:
* Search = Pointer to PCAB_SEARCH structure used to locate the file
* RETURNS
* Status of operation
*/
{
ULONG Size; // remaining file bytes to decompress
ULONG CurrentOffset; // current uncompressed offset within the folder
PUCHAR CurrentBuffer; // current pointer to compressed data in the block
LONG RemainingBlock; // remaining comp data in the block
HANDLE DestFile;
HANDLE DestFileSection;
PVOID DestFileBuffer; // mapped view of dest file
PVOID CurrentDestBuffer; // pointer to the current position in the dest view
PCFDATA CFData; // current data block
ULONG Status;
FILETIME FileTime;
WCHAR DestName[MAX_PATH];
NTSTATUS NtStatus;
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
FILE_BASIC_INFORMATION FileBasic;
PCFFOLDER CurrentFolder;
LARGE_INTEGER MaxDestFileSize;
LONG InputLength, OutputLength;
char Junk[512];
if( wcscmp( Search->Cabinet, CabinetName ) != 0 )
{
// the file is not in the current cabinet
DPRINT( "File is not in this cabinet ( %S != %S )\n", Search->Cabinet, CabinetName );
return CAB_STATUS_NOFILE;
}
// look up the folder that the file specifies
if( Search->File->FolderIndex == 0xFFFD || Search->File->FolderIndex == 0xFFFF )
{
// folder is continued from previous cabinet, that shouldn't happen here
return CAB_STATUS_NOFILE;
}
else if( Search->File->FolderIndex == 0xFFFE )
{
// folder is the last in this cabinet and continues into next
CurrentFolder = &CabinetFolders[PCABHeader->FolderCount-1];
}
else {
// folder is completely contained within this cabinet
CurrentFolder = &CabinetFolders[Search->File->FolderIndex];
}
switch (CurrentFolder->CompressionType & CAB_COMP_MASK)
{
case CAB_COMP_NONE:
CabinetSelectCodec(CAB_CODEC_RAW);
break;
case CAB_COMP_MSZIP:
CabinetSelectCodec(CAB_CODEC_MSZIP);
break;
default:
return CAB_STATUS_UNSUPPCOMP;
}
DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes)).\n",
(UINT)Search->File->FileOffset,
(UINT)Search->File->FileSize);
RtlInitAnsiString( &AnsiString, Search->File->FileName );
wcscpy( DestName, DestPath );
UnicodeString.MaximumLength = sizeof( DestName ) - wcslen( DestName );
UnicodeString.Buffer = DestName + wcslen( DestName );
UnicodeString.Length = 0;
RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
/* Create destination file, fail if it already exists */
RtlInitUnicodeString(&UnicodeString,
DestName);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
NtStatus = NtCreateFile(&DestFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(NtStatus))
{
DPRINT("NtCreateFile() failed (%S) (%x).\n", DestName, NtStatus);
/* If file exists, ask to overwrite file */
if (OverwriteHandler == NULL || OverwriteHandler(Search->File, DestName))
{
/* Create destination file, overwrite if it already exists */
NtStatus = NtCreateFile(&DestFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OVERWRITE,
FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0);
if (!NT_SUCCESS(NtStatus))
{
DPRINT("NtCreateFile() failed 2 (%S) (%x).\n", DestName, NtStatus);
return CAB_STATUS_CANNOT_CREATE;
}
}
else
{
DPRINT("File (%S) exists.\n", DestName);
return CAB_STATUS_FILE_EXISTS;
}
}
MaxDestFileSize.QuadPart = Search->File->FileSize;
NtStatus = NtCreateSection(&DestFileSection,
SECTION_ALL_ACCESS,
0,
&MaxDestFileSize,
PAGE_READWRITE,
SEC_COMMIT,
DestFile);
if(!NT_SUCCESS(NtStatus))
{
DPRINT("NtCreateSection failed: %x\n", NtStatus);
Status = CAB_STATUS_NOMEMORY;
goto CloseDestFile;
}
DestFileBuffer = 0;
DestFileSize = 0;
NtStatus = NtMapViewOfSection(DestFileSection,
NtCurrentProcess(),
&DestFileBuffer,
0,
0,
0,
&DestFileSize,
ViewUnmap,
0,
PAGE_READWRITE);
if(!NT_SUCCESS(NtStatus))
{
DPRINT("NtMapViewOfSection failed: %x\n", NtStatus);
Status = CAB_STATUS_NOMEMORY;
goto CloseDestFileSection;
}
CurrentDestBuffer = DestFileBuffer;
if (!ConvertDosDateTimeToFileTime(Search->File->FileDate, Search->File->FileTime, &FileTime))
{
DPRINT("DosDateTimeToFileTime() failed.\n");
Status = CAB_STATUS_CANNOT_WRITE;
goto UnmapDestFile;
}
NtStatus = NtQueryInformationFile(DestFile,
&IoStatusBlock,
&FileBasic,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(NtStatus))
{
DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus);
}
else
{
memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME));
NtStatus = NtSetInformationFile(DestFile,
&IoStatusBlock,
&FileBasic,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(NtStatus))
{
DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus);
}
}
SetAttributesOnFile(Search->File, DestFile);
/* Call extract event handler */
if (ExtractHandler != NULL)
{
ExtractHandler(Search->File, DestName);
}
// find the starting block of the file
// start with the first data block of the folder
CFData = (PCFDATA)(CabinetFolders[Search->File->FolderIndex].DataOffset + FileBuffer);
CurrentOffset = 0;
while( CurrentOffset + CFData->UncompSize <= Search->File->FileOffset )
{
// walk the data blocks until we reach the one containing the start of the file
CurrentOffset += CFData->UncompSize;
CFData = (PCFDATA)((char *)(CFData+1) + DataReserved + CFData->CompSize);
}
// now decompress and discard any data in the block before the start of the file
CurrentBuffer = ((unsigned char *)(CFData+1)) + DataReserved; // start of comp data
RemainingBlock = CFData->CompSize;
InputLength = RemainingBlock;
while( CurrentOffset < Search->File->FileOffset )
{
// compute remaining uncomp bytes to start of file, bounded by sizeof junk
OutputLength = Search->File->FileOffset - CurrentOffset;
if( OutputLength > (LONG)sizeof( Junk ) )
OutputLength = sizeof( Junk );
OutputLength = -OutputLength; // negate to signal NOT end of block
CodecUncompress( Junk,
CurrentBuffer,
&InputLength,
&OutputLength );
CurrentOffset += OutputLength; // add the uncomp bytes extracted to current folder offset
CurrentBuffer += InputLength; // add comp bytes consumed to CurrentBuffer
RemainingBlock -= InputLength; // subtract bytes consumed from bytes remaining in block
InputLength = -RemainingBlock; // neg for resume decompression of the same block
}
// now CurrentBuffer points to the first comp byte of the file, so we can begin decompressing
Size = Search->File->FileSize; // Size = remaining uncomp bytes of the file to decompress
while(Size > 0)
{
OutputLength = Size;
DPRINT( "Decompressing block at %x with RemainingBlock = %d, Size = %d\n", CurrentBuffer, RemainingBlock, Size );
Status = CodecUncompress(CurrentDestBuffer,
CurrentBuffer,
&InputLength,
&OutputLength);
if (Status != CS_SUCCESS)
{
DPRINT("Cannot uncompress block.\n");
if(Status == CS_NOMEMORY)
Status = CAB_STATUS_NOMEMORY;
Status = CAB_STATUS_INVALID_CAB;
goto UnmapDestFile;
}
CurrentDestBuffer = (PVOID)((ULONG_PTR)CurrentDestBuffer + OutputLength); // advance dest buffer by bytes produced
CurrentBuffer += InputLength; // advance src buffer by bytes consumed
Size -= OutputLength; // reduce remaining file bytes by bytes produced
RemainingBlock -= InputLength; // reduce remaining block size by bytes consumed
if( RemainingBlock == 0 )
{
// used up this block, move on to the next
DPRINT( "Out of block data\n" );
CFData = (PCFDATA)CurrentBuffer;
RemainingBlock = CFData->CompSize;
CurrentBuffer = ((unsigned char *)(CFData+1) + DataReserved);
InputLength = RemainingBlock;
}
}
Status = CAB_STATUS_SUCCESS;
UnmapDestFile:
NtUnmapViewOfSection(NtCurrentProcess(), DestFileBuffer);
CloseDestFileSection:
NtClose(DestFileSection);
CloseDestFile:
NtClose(DestFile);
return Status;
}
VOID
CabinetSelectCodec(ULONG Id)
/*
* FUNCTION: Selects codec engine to use
* ARGUMENTS:
* Id = Codec identifier
*/
{
if (CodecSelected)
{
if (Id == CodecId)
return;
CodecSelected = FALSE;
}
switch (Id)
{
case CAB_CODEC_RAW:
CodecUncompress = RawCodecUncompress;
break;
case CAB_CODEC_MSZIP:
CodecUncompress = MSZipCodecUncompress;
break;
default:
return;
}
CodecId = Id;
CodecSelected = TRUE;
}
VOID
CabinetSetEventHandlers(PCABINET_OVERWRITE Overwrite,
PCABINET_EXTRACT Extract,
PCABINET_DISK_CHANGE DiskChange)
/*
* FUNCTION: Set event handlers
* ARGUMENTS:
* Overwrite = Handler called when a file is to be overwritten
* Extract = Handler called when a file is to be extracted
* DiskChange = Handler called when changing the disk
*/
{
OverwriteHandler = Overwrite;
ExtractHandler = Extract;
DiskChangeHandler = DiskChange;
}
PVOID
CabinetGetCabinetReservedArea(PULONG Size)
/*
* FUNCTION: Get pointer to cabinet reserved area. NULL if none
*/
{
if (CabinetReservedArea != NULL)
{
if (Size != NULL)
{
*Size = CabinetReserved;
}
return CabinetReservedArea;
}
else
{
if (Size != NULL)
{
*Size = 0;
}
return NULL;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -