aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2024-12-28 12:04:00 -0800
committerRob Mensching <rob@firegiant.com>2025-02-11 15:49:33 -0800
commita797638d231b568b3e53bb2f478c28b6c0d5a1dc (patch)
tree065a51afd27f6d440a94f79daea56bb0d02e1605
parentcfb2df2e88b9ee273852124bbbdb1342207e96f9 (diff)
downloadwix-a797638d231b568b3e53bb2f478c28b6c0d5a1dc.tar.gz
wix-a797638d231b568b3e53bb2f478c28b6c0d5a1dc.tar.bz2
wix-a797638d231b568b3e53bb2f478c28b6c0d5a1dc.zip
Support extracting cabbed file straight to file handle
-rw-r--r--src/burn/engine/cabextract.cpp126
-rw-r--r--src/burn/engine/cabextract.h4
2 files changed, 99 insertions, 31 deletions
diff --git a/src/burn/engine/cabextract.cpp b/src/burn/engine/cabextract.cpp
index 56146a39..5663c3f7 100644
--- a/src/burn/engine/cabextract.cpp
+++ b/src/burn/engine/cabextract.cpp
@@ -55,6 +55,14 @@ static INT_PTR CloseFileInfoCallback(
55 __in BURN_CONTAINER_CONTEXT* pContext, 55 __in BURN_CONTAINER_CONTEXT* pContext,
56 __inout FDINOTIFICATION *pFDINotify 56 __inout FDINOTIFICATION *pFDINotify
57 ); 57 );
58static HRESULT PrepareTargetFile(
59 __in long cb,
60 __in HANDLE hFile
61 );
62static void BestEffortSetFileTime(
63 __in FDINOTIFICATION* pFDINotify,
64 __in HANDLE hFile
65 );
58static LPVOID DIAMONDAPI CabAlloc( 66static LPVOID DIAMONDAPI CabAlloc(
59 __in DWORD dwSize 67 __in DWORD dwSize
60 ); 68 );
@@ -226,6 +234,28 @@ LExit:
226 return hr; 234 return hr;
227} 235}
228 236
237extern "C" HRESULT CabExtractStreamToHandle(
238 __in BURN_CONTAINER_CONTEXT* pContext,
239 __in HANDLE hFile
240 )
241{
242 HRESULT hr = S_OK;
243
244 // set operation to move to next stream
245 pContext->Cabinet.operation = BURN_CAB_OPERATION_STREAM_TO_HANDLE;
246 pContext->Cabinet.hTargetFile = hFile;
247
248 // begin operation and wait
249 hr = BeginAndWaitForOperation(pContext);
250 ExitOnFailure(hr, "Failed to begin and wait for operation.");
251
252 // clear file handle
253 pContext->Cabinet.hTargetFile = INVALID_HANDLE_VALUE;
254
255LExit:
256 return hr;
257}
258
229extern "C" HRESULT CabExtractSkipStream( 259extern "C" HRESULT CabExtractSkipStream(
230 __in BURN_CONTAINER_CONTEXT* pContext 260 __in BURN_CONTAINER_CONTEXT* pContext
231 ) 261 )
@@ -505,8 +535,6 @@ static INT_PTR CopyFileCallback(
505{ 535{
506 HRESULT hr = S_OK; 536 HRESULT hr = S_OK;
507 INT_PTR ipResult = 1; // result to return on success 537 INT_PTR ipResult = 1; // result to return on success
508 LPWSTR pwzPath = NULL;
509 LARGE_INTEGER li = { };
510 538
511 // set operation complete event 539 // set operation complete event
512 if (!::SetEvent(pContext->Cabinet.hOperationCompleteEvent)) 540 if (!::SetEvent(pContext->Cabinet.hOperationCompleteEvent))
@@ -567,23 +595,14 @@ static INT_PTR CopyFileCallback(
567 ExitWithLastError(hr, "Failed to create file: %ls", pContext->Cabinet.wzTargetFile); 595 ExitWithLastError(hr, "Failed to create file: %ls", pContext->Cabinet.wzTargetFile);
568 } 596 }
569 597
570 // set file size 598 hr = PrepareTargetFile(pFDINotify->cb, pContext->Cabinet.hTargetFile);
571 li.QuadPart = pFDINotify->cb; 599 ExitOnFailure(hr, "Failed to prepare target file.");
572 if (!::SetFilePointerEx(pContext->Cabinet.hTargetFile, li, NULL, FILE_BEGIN))
573 {
574 ExitWithLastError(hr, "Failed to set file pointer to end of file.");
575 }
576 600
577 if (!::SetEndOfFile(pContext->Cabinet.hTargetFile)) 601 break;
578 {
579 ExitWithLastError(hr, "Failed to set end of file.");
580 }
581 602
582 li.QuadPart = 0; 603 case BURN_CAB_OPERATION_STREAM_TO_HANDLE:
583 if (!::SetFilePointerEx(pContext->Cabinet.hTargetFile, li, NULL, FILE_BEGIN)) 604 hr = PrepareTargetFile(pFDINotify->cb, pContext->Cabinet.hTargetFile);
584 { 605 ExitOnFailure(hr, "Failed to prepare target file.");
585 ExitWithLastError(hr, "Failed to set file pointer to beginning of file.");
586 }
587 606
588 break; 607 break;
589 608
@@ -611,8 +630,6 @@ static INT_PTR CopyFileCallback(
611 } 630 }
612 631
613LExit: 632LExit:
614 ReleaseStr(pwzPath);
615
616 pContext->Cabinet.hrError = hr; 633 pContext->Cabinet.hrError = hr;
617 return SUCCEEDED(hr) ? ipResult : -1; 634 return SUCCEEDED(hr) ? ipResult : -1;
618} 635}
@@ -624,27 +641,24 @@ static INT_PTR CloseFileInfoCallback(
624{ 641{
625 HRESULT hr = S_OK; 642 HRESULT hr = S_OK;
626 INT_PTR ipResult = 1; // result to return on success 643 INT_PTR ipResult = 1; // result to return on success
627 FILETIME ftLocal = { };
628 FILETIME ft = { };
629 644
630 // read operation 645 // read operation
631 switch (pContext->Cabinet.operation) 646 switch (pContext->Cabinet.operation)
632 { 647 {
633 case BURN_CAB_OPERATION_STREAM_TO_FILE: 648 case BURN_CAB_OPERATION_STREAM_TO_FILE:
634 // Make a best effort to set the time on the new file before 649 BestEffortSetFileTime(pFDINotify, pContext->Cabinet.hTargetFile);
635 // we close it.
636 if (::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal))
637 {
638 if (::LocalFileTimeToFileTime(&ftLocal, &ft))
639 {
640 ::SetFileTime(pContext->Cabinet.hTargetFile, &ft, &ft, &ft);
641 }
642 }
643 650
644 // close file 651 // close file
645 ReleaseFile(pContext->Cabinet.hTargetFile); 652 ReleaseFile(pContext->Cabinet.hTargetFile);
646 break; 653 break;
647 654
655 case BURN_CAB_OPERATION_STREAM_TO_HANDLE:
656 BestEffortSetFileTime(pFDINotify, pContext->Cabinet.hTargetFile);
657
658 // Do NOT close file.
659 pContext->Cabinet.hTargetFile = INVALID_HANDLE_VALUE;
660 break;
661
648 case BURN_CAB_OPERATION_STREAM_TO_BUFFER: 662 case BURN_CAB_OPERATION_STREAM_TO_BUFFER:
649 break; 663 break;
650 664
@@ -676,6 +690,55 @@ LExit:
676 return SUCCEEDED(hr) ? ipResult : -1; 690 return SUCCEEDED(hr) ? ipResult : -1;
677} 691}
678 692
693static HRESULT PrepareTargetFile(
694 __in long cb,
695 __in HANDLE hFile
696 )
697{
698 HRESULT hr = S_OK;
699 LARGE_INTEGER li = { };
700
701 // set file size
702 li.QuadPart = cb;
703 if (!::SetFilePointerEx(hFile, li, NULL, FILE_BEGIN))
704 {
705 ExitWithLastError(hr, "Failed to set file pointer to end of file.");
706 }
707
708 if (!::SetEndOfFile(hFile))
709 {
710 ExitWithLastError(hr, "Failed to set end of file.");
711 }
712
713 li.QuadPart = 0;
714 if (!::SetFilePointerEx(hFile, li, NULL, FILE_BEGIN))
715 {
716 ExitWithLastError(hr, "Failed to set file pointer to beginning of file.");
717 }
718
719LExit:
720 return hr;
721}
722
723static void BestEffortSetFileTime(
724 __in FDINOTIFICATION* pFDINotify,
725 __in HANDLE hFile
726 )
727{
728 FILETIME ftLocal = { };
729 FILETIME ft = { };
730
731 // Make a best effort to set the time on the new file before
732 // we close it.
733 if (::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal))
734 {
735 if (::LocalFileTimeToFileTime(&ftLocal, &ft))
736 {
737 ::SetFileTime(hFile, &ft, &ft, &ft);
738 }
739 }
740}
741
679static LPVOID DIAMONDAPI CabAlloc( 742static LPVOID DIAMONDAPI CabAlloc(
680 __in DWORD dwSize 743 __in DWORD dwSize
681 ) 744 )
@@ -759,7 +822,8 @@ static UINT FAR DIAMONDAPI CabWrite(
759 822
760 switch (pContext->Cabinet.operation) 823 switch (pContext->Cabinet.operation)
761 { 824 {
762 case BURN_CAB_OPERATION_STREAM_TO_FILE: 825 case BURN_CAB_OPERATION_STREAM_TO_FILE: __fallthrough;
826 case BURN_CAB_OPERATION_STREAM_TO_HANDLE:
763 // write file 827 // write file
764 if (!::WriteFile(pContext->Cabinet.hTargetFile, pv, cb, &cbWrite, NULL)) 828 if (!::WriteFile(pContext->Cabinet.hTargetFile, pv, cb, &cbWrite, NULL))
765 { 829 {
diff --git a/src/burn/engine/cabextract.h b/src/burn/engine/cabextract.h
index 31667f2b..13f9ab5d 100644
--- a/src/burn/engine/cabextract.h
+++ b/src/burn/engine/cabextract.h
@@ -27,6 +27,10 @@ HRESULT CabExtractStreamToBuffer(
27 __out BYTE** ppbBuffer, 27 __out BYTE** ppbBuffer,
28 __out SIZE_T* pcbBuffer 28 __out SIZE_T* pcbBuffer
29 ); 29 );
30HRESULT CabExtractStreamToHandle(
31 __in BURN_CONTAINER_CONTEXT* pContext,
32 __in HANDLE hFile
33 );
30HRESULT CabExtractSkipStream( 34HRESULT CabExtractSkipStream(
31 __in BURN_CONTAINER_CONTEXT* pContext 35 __in BURN_CONTAINER_CONTEXT* pContext
32 ); 36 );