Rewrote usetup's file copy and cabinet extraction code to use memory mapped files

This increased performance and the code is cleaner
Still needs a bit more cleaning up, but so far, looks good, needs some testing



svn path=/trunk/; revision=15403
This commit is contained in:
Phillip Susi 2005-05-19 00:59:40 +00:00
parent 7403e34ca9
commit 5d4d912efd
3 changed files with 577 additions and 1610 deletions

File diff suppressed because it is too large Load diff

View file

@ -82,12 +82,13 @@ typedef struct _CFFOLDER
typedef struct _CFFILE typedef struct _CFFILE
{ {
ULONG FileSize; // Uncompressed file size in bytes ULONG FileSize; // Uncompressed file size in bytes
ULONG FileOffset; // Uncompressed offset of file in the folder ULONG FileOffset; // Uncompressed offset of file in the folder
WORD FileControlID; // File control ID (CAB_FILE_*) WORD FolderIndex; // Index number of the folder that contains this file
WORD FileDate; // File date stamp, as used by DOS WORD FileDate; // File date stamp, as used by DOS
WORD FileTime; // File time stamp, as used by DOS WORD FileTime; // File time stamp, as used by DOS
WORD Attributes; // File attributes (CAB_ATTRIB_*) WORD Attributes; // File attributes (CAB_ATTRIB_*)
CHAR FileName[];
/* After this is the NULL terminated filename */ /* After this is the NULL terminated filename */
} CFFILE, *PCFFILE; } CFFILE, *PCFFILE;
@ -102,50 +103,12 @@ typedef struct _CFDATA
*/ */
} CFDATA, *PCFDATA; } CFDATA, *PCFDATA;
typedef struct _CFDATA_NODE
{
struct _CFDATA_NODE *Next;
struct _CFDATA_NODE *Prev;
ULONG ScratchFilePosition; // Absolute offset in scratch file
ULONG AbsoluteOffset; // Absolute offset in cabinet
ULONG UncompOffset; // Uncompressed offset in folder
CFDATA Data;
} CFDATA_NODE, *PCFDATA_NODE;
typedef struct _CFFOLDER_NODE
{
struct _CFFOLDER_NODE *Next;
struct _CFFOLDER_NODE *Prev;
ULONG UncompOffset; // File size accumulator
ULONG AbsoluteOffset;
ULONG TotalFolderSize; // Total size of folder in current disk
PCFDATA_NODE DataListHead;
PCFDATA_NODE DataListTail;
ULONG Index;
BOOL Commit; // TRUE if the folder should be committed
BOOL Delete; // TRUE if marked for deletion
CFFOLDER Folder;
} CFFOLDER_NODE, *PCFFOLDER_NODE;
typedef struct _CFFILE_NODE
{
struct _CFFILE_NODE *Next;
struct _CFFILE_NODE *Prev;
CFFILE File;
PWCHAR FileName;
PCFDATA_NODE DataBlock; // First data block of file. NULL if not known
BOOL Commit; // TRUE if the file data should be committed
BOOL Delete; // TRUE if marked for deletion
PCFFOLDER_NODE FolderNode; // Folder this file belong to
} CFFILE_NODE, *PCFFILE_NODE;
typedef struct _CAB_SEARCH typedef struct _CAB_SEARCH
{ {
WCHAR Search[MAX_PATH]; // Search criteria WCHAR Search[MAX_PATH]; // Search criteria
PCFFILE_NODE Next; // Pointer to next node WCHAR Cabinet[MAX_PATH];
PCFFILE File; // Pointer to current CFFILE USHORT Index;
PWCHAR FileName; // Current filename PCFFILE File; // Pointer to current CFFILE
} CAB_SEARCH, *PCAB_SEARCH; } CAB_SEARCH, *PCAB_SEARCH;
@ -169,9 +132,9 @@ typedef struct _CAB_SEARCH
/* Uncompresses a data block */ /* Uncompresses a data block */
typedef ULONG (*PCABINET_CODEC_UNCOMPRESS)(PVOID OutputBuffer, typedef ULONG (*PCABINET_CODEC_UNCOMPRESS)(PVOID OutputBuffer,
PVOID InputBuffer, PVOID InputBuffer,
ULONG InputLength, PLONG InputLength,
PULONG OutputLength); PLONG OutputLength);
/* Codec status codes */ /* Codec status codes */
@ -232,7 +195,7 @@ ULONG CabinetFindFirst(PWCHAR FileName, PCAB_SEARCH Search);
/* Locates the next file in the current cabinet file */ /* Locates the next file in the current cabinet file */
ULONG CabinetFindNext(PCAB_SEARCH Search); ULONG CabinetFindNext(PCAB_SEARCH Search);
/* Extracts a file from the current cabinet file */ /* Extracts a file from the current cabinet file */
ULONG CabinetExtractFile(PWCHAR FileName); ULONG CabinetExtractFile(PCAB_SEARCH Search);
/* Select codec engine to use */ /* Select codec engine to use */
VOID CabinetSelectCodec(ULONG Id); VOID CabinetSelectCodec(ULONG Id);
/* Set event handlers */ /* Set event handlers */

View file

@ -107,11 +107,13 @@ SetupCopyFile(PWCHAR SourceFileName,
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION FileStandard; FILE_STANDARD_INFORMATION FileStandard;
FILE_BASIC_INFORMATION FileBasic; FILE_BASIC_INFORMATION FileBasic;
FILE_POSITION_INFORMATION FilePosition;
PUCHAR Buffer; PUCHAR Buffer;
ULONG RegionSize; ULONG RegionSize;
UNICODE_STRING FileName; UNICODE_STRING FileName;
NTSTATUS Status; NTSTATUS Status;
PVOID SourceFileMap = 0;
HANDLE SourceFileSection;
ULONG SourceSectionSize = 0;
Buffer = NULL; Buffer = NULL;
@ -130,9 +132,10 @@ SetupCopyFile(PWCHAR SourceFileName,
&IoStatusBlock, &IoStatusBlock,
FILE_SHARE_READ, FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY);
if (!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
return(Status); DPRINT1("NtOpenFile failed: %x\n", Status);
goto done;
} }
Status = NtQueryInformationFile(FileHandleSource, Status = NtQueryInformationFile(FileHandleSource,
@ -140,20 +143,48 @@ SetupCopyFile(PWCHAR SourceFileName,
&FileStandard, &FileStandard,
sizeof(FILE_STANDARD_INFORMATION), sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation); FileStandardInformation);
if (!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
NtClose(FileHandleSource); DPRINT1("NtQueryInformationFile failed: %x\n", Status);
return(Status); goto closesrc;
} }
Status = NtQueryInformationFile(FileHandleSource, Status = NtQueryInformationFile(FileHandleSource,
&IoStatusBlock,&FileBasic, &IoStatusBlock,&FileBasic,
sizeof(FILE_BASIC_INFORMATION), sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation); FileBasicInformation);
if (!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
NtClose(FileHandleSource); DPRINT1("NtQueryInformationFile failed: %x\n", Status);
return(Status); goto closesrc;
}
Status = NtCreateSection( &SourceFileSection,
SECTION_MAP_READ,
0,
0,
PAGE_READONLY,
0,
FileHandleSource);
if(!NT_SUCCESS(Status))
{
DPRINT1("NtCreateSection failed: %x\n", Status);
goto closesrc;
}
Status = NtMapViewOfSection( SourceFileSection,
NtCurrentProcess(),
&SourceFileMap,
0,
0,
0,
&SourceSectionSize,
0,
SEC_COMMIT,
PAGE_READONLY );
if(!NT_SUCCESS(Status))
{
DPRINT1("NtMapViewOfSection failed: %x\n", Status);
goto closesrcsec;
} }
RtlInitUnicodeString(&FileName, RtlInitUnicodeString(&FileName,
@ -176,121 +207,55 @@ SetupCopyFile(PWCHAR SourceFileName,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
NULL, NULL,
0); 0);
if (!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
NtClose(FileHandleSource); DPRINT1("NtCreateFile failed: %x\n", Status);
return(Status); goto unmapsrcsec;
}
FilePosition.CurrentByteOffset.QuadPart = 0;
Status = NtSetInformationFile(FileHandleSource,
&IoStatusBlock,
&FilePosition,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation);
if (!NT_SUCCESS(Status))
{
NtClose(FileHandleSource);
NtClose(FileHandleDest);
return(Status);
}
Status = NtSetInformationFile(FileHandleDest,
&IoStatusBlock,
&FilePosition,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation);
if (!NT_SUCCESS(Status))
{
NtClose(FileHandleSource);
NtClose(FileHandleDest);
return(Status);
} }
RegionSize = PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart); RegionSize = PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
if (RegionSize > 0x100000) IoStatusBlock.Status = 0;
Status = NtWriteFile(FileHandleDest,
0,
0,
0,
&IoStatusBlock,
SourceFileMap,
RegionSize,
0,
0);
if(!NT_SUCCESS(Status))
{ {
RegionSize = 0x100000; DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
goto closedest;
} }
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
(PVOID *)&Buffer,
2,
&RegionSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
NtClose(FileHandleSource);
NtClose(FileHandleDest);
return(Status);
}
while (TRUE)
{
Status = NtReadFile(FileHandleSource,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
RegionSize,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
NtFreeVirtualMemory(NtCurrentProcess(),
(PVOID *)&Buffer,
&RegionSize,
MEM_RELEASE);
if (Status == STATUS_END_OF_FILE)
{
DPRINT("STATUS_END_OF_FILE\n");
break;
}
NtClose(FileHandleSource);
NtClose(FileHandleDest);
return(Status);
}
DPRINT("Bytes read %lu\n", IoStatusBlock.Information);
Status = NtWriteFile(FileHandleDest,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
IoStatusBlock.Information,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
NtFreeVirtualMemory(NtCurrentProcess(),
(PVOID *)&Buffer,
&RegionSize,
MEM_RELEASE);
NtClose(FileHandleSource);
NtClose(FileHandleDest);
return(Status);
}
}
/* Copy file date/time from source file */ /* Copy file date/time from source file */
Status = NtSetInformationFile(FileHandleDest, Status = NtSetInformationFile(FileHandleDest,
&IoStatusBlock, &IoStatusBlock,
&FileBasic, &FileBasic,
sizeof(FILE_BASIC_INFORMATION), sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation); FileBasicInformation);
if (!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
{ {
DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status); DPRINT1("NtSetInformationFile failed: %x\n", Status);
goto closedest;
} }
NtClose(FileHandleSource); /* shorten the file back to it's real size after completing the write */
NtSetInformationFile(FileHandleDest,
&IoStatusBlock,
&FileStandard.EndOfFile,
sizeof(FILE_END_OF_FILE_INFORMATION),
FileEndOfFileInformation);
closedest:
NtClose(FileHandleDest); NtClose(FileHandleDest);
unmapsrcsec:
NtUnmapViewOfSection( NtCurrentProcess(), SourceFileMap );
closesrcsec:
NtClose(SourceFileSection);
closesrc:
NtClose(FileHandleSource);
done:
return(Status); return(Status);
} }
@ -301,6 +266,7 @@ SetupExtractFile(PWCHAR CabinetFileName,
PWCHAR DestinationPathName) PWCHAR DestinationPathName)
{ {
ULONG CabStatus; ULONG CabStatus;
CAB_SEARCH Search;
DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n", DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
CabinetFileName, SourceFileName, DestinationPathName); CabinetFileName, SourceFileName, DestinationPathName);
@ -343,7 +309,8 @@ SetupExtractFile(PWCHAR CabinetFileName,
} }
CabinetSetDestinationPath(DestinationPathName); CabinetSetDestinationPath(DestinationPathName);
CabStatus = CabinetExtractFile(SourceFileName); CabinetFindFirst( SourceFileName, &Search );
CabStatus = CabinetExtractFile(&Search);
if (CabStatus != CAB_STATUS_SUCCESS) if (CabStatus != CAB_STATUS_SUCCESS)
{ {
DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus); DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);