365 lines
7.9 KiB
C
365 lines
7.9 KiB
C
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
replace.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code to replace
|
|
a file in the cab file.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 29-Sept-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <ntcabp.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
BOOL
|
|
NtCabReplaceOneFile(
|
|
IN PCAB_INSTANCE_DATA CabInst,
|
|
IN PCWSTR FileName
|
|
)
|
|
{
|
|
BOOL rVal;
|
|
NTSTATUS Status;
|
|
HANDLE hFileTmp;
|
|
HANDLE hFile;
|
|
PCAB_DIR_ENTRY CabDir;
|
|
PCAB_DIR_ENTRY CabDirNew;
|
|
WCHAR TempPath[MAX_PATH];
|
|
WCHAR TempFileName[MAX_PATH];
|
|
DWORD Bytes = 0;
|
|
DWORD BytesRead;
|
|
ULONG FileSize;
|
|
ULONG i;
|
|
DWORD BytesCompressed;
|
|
LPWSTR s;
|
|
|
|
|
|
//
|
|
// file the file to replace
|
|
//
|
|
|
|
CabDir = FindFileInCab( CabInst, FileName );
|
|
if (CabDir == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// open the new data file
|
|
//
|
|
|
|
hFile = CreateFile(
|
|
FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
FileSize = GetFileSize( hFile, NULL );
|
|
|
|
if (FileSize < CabDir->FileSize) {
|
|
//
|
|
// do an inplace update - this is the fast code path
|
|
//
|
|
|
|
//
|
|
// position the cabfile to the data for the old file
|
|
//
|
|
|
|
SetFilePointer( CabInst->hCab, CabDir->Offset, NULL, FILE_BEGIN );
|
|
|
|
//
|
|
// create a directory for the new cab file
|
|
//
|
|
|
|
BytesRead = sizeof(CAB_DIR_ENTRY) + (sizeof(ULONG)*64);
|
|
CabDirNew = (PCAB_DIR_ENTRY) malloc( BytesRead );
|
|
if (CabDirNew == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory( CabDirNew, BytesRead );
|
|
|
|
CabDirNew->Offset = SetFilePointer( CabInst->hCab, 0, NULL, FILE_CURRENT );
|
|
wcscpy( CabDirNew->FileName, FileName );
|
|
i = 0;
|
|
|
|
Bytes = 0;
|
|
FileSize = GetFileSize( hFile, NULL );
|
|
|
|
//
|
|
// copy the data from the new data file into
|
|
// the new cab file, compressing it as we go
|
|
//
|
|
|
|
while (Bytes < FileSize) {
|
|
BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
|
|
Status = ReadFile(
|
|
hFile,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
Bytes += BytesRead;
|
|
Status = RtlCompressBuffer(
|
|
COMPRESSION_FLAGS,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
CabInst->CompressBuf,
|
|
CabInst->CompressBufSize,
|
|
4096,
|
|
&BytesCompressed,
|
|
CabInst->WorkSpace
|
|
);
|
|
Status = WriteFile(
|
|
CabInst->hCab,
|
|
CabInst->CompressBuf,
|
|
BytesCompressed,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
CabDirNew->Segment[i++] = BytesRead;
|
|
CabDirNew->CompressedFileSize += BytesRead;
|
|
}
|
|
|
|
CabDirNew->Segments = i;
|
|
|
|
//
|
|
// put the new file in the dir list and
|
|
// remove the old file from the list
|
|
//
|
|
|
|
RemoveEntryList( &CabDir->Next );
|
|
InsertTailList( &CabInst->CabDir, &CabDirNew->Next );
|
|
|
|
//
|
|
// truncate the dir entries
|
|
//
|
|
|
|
SetFilePointer( CabInst->hCab, CabInst->CabDirOffset, NULL, FILE_BEGIN );
|
|
SetEndOfFile( CabInst->hCab );
|
|
FlushFileBuffers( CabInst->hCab );
|
|
|
|
//
|
|
// trick the close function to rebuild the dirs
|
|
//
|
|
|
|
CabInst->NewCabFile = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// create a file name for the temporary cab file
|
|
//
|
|
|
|
GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath );
|
|
GetTempFileName( TempPath, L"cab", 0, TempFileName );
|
|
|
|
//
|
|
// create the new temporary cab file
|
|
//
|
|
|
|
hFileTmp = CreateFile(
|
|
TempFileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (hFileTmp == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// set the existing cab file pointer to the beginning
|
|
//
|
|
|
|
SetFilePointer( CabInst->hCab, 0, NULL, FILE_BEGIN );
|
|
|
|
FileSize = CabDir->Offset;
|
|
Bytes = 0;
|
|
|
|
//
|
|
// copy the data from the beginning of the cab file
|
|
// to the first byte of the file that needs replacing
|
|
//
|
|
|
|
while(Bytes<FileSize) {
|
|
BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
|
|
rVal = ReadFile(
|
|
CabInst->hCab,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
Bytes += BytesRead;
|
|
rVal = WriteFile(
|
|
hFileTmp,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// create a directory for the new cab file
|
|
//
|
|
|
|
BytesRead = sizeof(CAB_DIR_ENTRY) + (sizeof(ULONG)*64);
|
|
CabDirNew = (PCAB_DIR_ENTRY) malloc( BytesRead );
|
|
if (CabDirNew == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory( CabDirNew, BytesRead );
|
|
|
|
CabDirNew->Offset = SetFilePointer( CabInst->hCab, 0, NULL, FILE_CURRENT );
|
|
wcscpy( CabDirNew->FileName, FileName );
|
|
i = 0;
|
|
|
|
Bytes = 0;
|
|
FileSize = GetFileSize( hFile, NULL );
|
|
|
|
//
|
|
// copy the data from the new data file into
|
|
// the new cab file, compressing it as we go
|
|
//
|
|
|
|
while (Bytes < FileSize) {
|
|
BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
|
|
Status = ReadFile(
|
|
hFile,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
Bytes += BytesRead;
|
|
Status = RtlCompressBuffer(
|
|
COMPRESSION_FLAGS,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
CabInst->CompressBuf,
|
|
CabInst->CompressBufSize,
|
|
4096,
|
|
&BytesCompressed,
|
|
CabInst->WorkSpace
|
|
);
|
|
Status = WriteFile(
|
|
hFileTmp,
|
|
CabInst->CompressBuf,
|
|
BytesCompressed,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
CabDirNew->Segment[i++] = BytesRead;
|
|
CabDirNew->CompressedFileSize += BytesRead;
|
|
}
|
|
|
|
CabDirNew->Segments = i;
|
|
|
|
//
|
|
// skip the data for the original file
|
|
//
|
|
|
|
Bytes = SetFilePointer( CabInst->hCab, CabDir->CompressedFileSize, NULL, FILE_CURRENT );
|
|
|
|
//
|
|
// set up the file size for the remaining data minus the dir
|
|
//
|
|
|
|
FileSize = CabInst->CabDirOffset - Bytes;
|
|
Bytes = 0;
|
|
|
|
//
|
|
// copy the remaining data
|
|
//
|
|
|
|
while(Bytes<FileSize) {
|
|
BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
|
|
rVal = ReadFile(
|
|
CabInst->hCab,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
Bytes += BytesRead;
|
|
rVal = WriteFile(
|
|
hFileTmp,
|
|
CabInst->ReadBuf,
|
|
BytesRead,
|
|
&BytesRead,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// put the new file in the dir list and
|
|
// remove the old file from the list
|
|
//
|
|
|
|
RemoveEntryList( &CabDir->Next );
|
|
InsertTailList( &CabInst->CabDir, &CabDirNew->Next );
|
|
|
|
//
|
|
// close the new cab file and the new data file
|
|
//
|
|
|
|
CloseHandle( hFile );
|
|
CloseHandle( hFileTmp );
|
|
|
|
//
|
|
// copy the new cab as the old cab file
|
|
//
|
|
|
|
CabInst->NewCabFile = TRUE;
|
|
|
|
CloseHandle( CabInst->hCab );
|
|
DeleteFile( CabInst->CabFileName );
|
|
MoveFile( TempFileName, CabInst->CabFileName );
|
|
|
|
//
|
|
// reopen the cab file so we can re-write the
|
|
// dir when it is closed
|
|
//
|
|
|
|
CabInst->hCab = CreateFile(
|
|
CabInst->CabFileName,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (CabInst->hCab == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|