/*++ 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 #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(BytesReadBufSize, 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(BytesReadBufSize, 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; }