diff --git a/internal/wclayer/cim/cim_writer_test.go b/internal/wclayer/cim/cim_writer_test.go index 0abc19da74..5f4a6d40d9 100644 --- a/internal/wclayer/cim/cim_writer_test.go +++ b/internal/wclayer/cim/cim_writer_test.go @@ -11,7 +11,7 @@ import ( ) func TestSingleFileWriterTypeMismatch(t *testing.T) { - if !cimfs.IsBlockCimSupported() { + if !cimfs.IsBlockCimWriteSupported() { t.Skipf("BlockCIM not supported") } @@ -34,7 +34,7 @@ func TestSingleFileWriterTypeMismatch(t *testing.T) { } func TestSingleFileWriterInvalidBlockType(t *testing.T) { - if !cimfs.IsBlockCimSupported() { + if !cimfs.IsBlockCimWriteSupported() { t.Skipf("BlockCIM not supported") } diff --git a/internal/winapi/utils.go b/internal/winapi/utils.go index 9afe8263a1..70c43fc1cc 100644 --- a/internal/winapi/utils.go +++ b/internal/winapi/utils.go @@ -8,8 +8,6 @@ import ( "unsafe" "golang.org/x/sys/windows" - - "github.com/Microsoft/hcsshim/internal/winapi/cimfs" ) // Uint16BufferToSlice wraps a uint16 pointer-and-length into a slice @@ -83,8 +81,3 @@ func ConvertStringSetToSlice(buf []byte) ([]string, error) { func ParseUtf16LE(b []byte) string { return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(&b[0]))) } - -// CimFsSupported checks if either CIMFS dll is present on the system. -func CimFsSupported() bool { - return cimfs.Supported() -} diff --git a/pkg/cimfs/cim_test.go b/pkg/cimfs/cim_test.go index 65eeba1845..c6833f9917 100644 --- a/pkg/cimfs/cim_test.go +++ b/pkg/cimfs/cim_test.go @@ -226,7 +226,7 @@ func TestCimReadWrite(t *testing.T) { } func TestBlockCIMInvalidCimName(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimWriteSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -239,7 +239,7 @@ func TestBlockCIMInvalidCimName(t *testing.T) { } func TestBlockCIMInvalidBlockPath(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimWriteSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -252,7 +252,7 @@ func TestBlockCIMInvalidBlockPath(t *testing.T) { } func TestBlockCIMInvalidType(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimWriteSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -265,7 +265,7 @@ func TestBlockCIMInvalidType(t *testing.T) { } func TestCIMMergeInvalidType(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -282,7 +282,7 @@ func TestCIMMergeInvalidType(t *testing.T) { } func TestCIMMergeInvalidSourceType(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -313,7 +313,7 @@ func TestCIMMergeInvalidSourceType(t *testing.T) { } func TestCIMMergeInvalidLength(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -329,7 +329,7 @@ func TestCIMMergeInvalidLength(t *testing.T) { } func TestBlockCIMEmpty(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimWriteSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -347,7 +347,7 @@ func TestBlockCIMEmpty(t *testing.T) { } func TestBlockCIMSingleFileReadWrite(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -411,7 +411,7 @@ func createBlockDevice(t *testing.T, dir string) string { } func TestBlockCIMBlockDeviceReadWrite(t *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { t.Skip("blockCIM not supported on this OS version") } @@ -440,7 +440,7 @@ func TestBlockCIMBlockDeviceReadWrite(t *testing.T) { } func TestMergedBlockCIMs(rootT *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { rootT.Skipf("BlockCIM not supported") } @@ -534,7 +534,7 @@ func TestMergedBlockCIMs(rootT *testing.T) { } func TestTombstoneInMergedBlockCIMs(rootT *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { rootT.Skipf("BlockCIM not supported") } @@ -608,7 +608,7 @@ func TestTombstoneInMergedBlockCIMs(rootT *testing.T) { } func TestMergedLinksInMergedBlockCIMs(rootT *testing.T) { - if !IsBlockCimSupported() { + if !IsBlockCimMountSupported() { rootT.Skipf("BlockCIM not supported") } @@ -688,7 +688,7 @@ func TestMergedLinksInMergedBlockCIMs(rootT *testing.T) { } func TestVerifiedSingleFileBlockCIMMount(t *testing.T) { - if !IsVerifiedCimSupported() { + if !IsVerifiedCimMountSupported() { t.Skipf("verified CIMs are not supported") } @@ -733,7 +733,7 @@ func TestVerifiedSingleFileBlockCIMMount(t *testing.T) { } func TestVerifiedSingleFileBlockCIMMountReadFailure(t *testing.T) { - if !IsVerifiedCimSupported() { + if !IsVerifiedCimMountSupported() { t.Skipf("verified CIMs are not supported") } @@ -777,7 +777,11 @@ func TestVerifiedSingleFileBlockCIMMountReadFailure(t *testing.T) { } func TestMergedVerifiedBlockCIMs(rootT *testing.T) { - if !IsVerifiedCimSupported() { + if !IsVerifiedCimWriteSupported() { + rootT.Skipf("verified BlockCIMs are not supported") + } + + if !IsVerifiedCimMountSupported() { rootT.Skipf("verified BlockCIMs are not supported") } diff --git a/pkg/cimfs/cim_writer_windows.go b/pkg/cimfs/cim_writer_windows.go index 0811816421..0117b9f139 100644 --- a/pkg/cimfs/cim_writer_windows.go +++ b/pkg/cimfs/cim_writer_windows.go @@ -118,11 +118,11 @@ func CreateBlockCIMWithOptions(ctx context.Context, bCIM *BlockCIM, options ...B } // Check OS support - if !IsBlockCimSupported() { + if !IsBlockCimWriteSupported() { return nil, fmt.Errorf("block CIM not supported on this OS version") } - if config.dataIntegrity && !IsVerifiedCimSupported() { + if config.dataIntegrity && !IsVerifiedCimWriteSupported() { return nil, fmt.Errorf("verified CIMs are not supported on this OS version") } @@ -436,7 +436,7 @@ func GetCimUsage(ctx context.Context, cimPath string) (uint64, error) { // files with the same path at all other CIMs) When mounting this merged CIM the source // CIMs MUST be provided in the exact same order. func MergeBlockCIMsWithOpts(ctx context.Context, mergedCIM *BlockCIM, sourceCIMs []*BlockCIM, opts ...BlockCIMOpt) (err error) { - if !IsMergedCimSupported() { + if !IsMergedCimWriteSupported() { return fmt.Errorf("merged CIMs aren't supported on this OS version") } else if len(sourceCIMs) < 2 { return fmt.Errorf("need at least 2 source CIMs, got %d: %w", len(sourceCIMs), os.ErrInvalid) diff --git a/pkg/cimfs/cimfs.go b/pkg/cimfs/cimfs.go index 5c2f2616c8..70bbbac4d5 100644 --- a/pkg/cimfs/cimfs.go +++ b/pkg/cimfs/cimfs.go @@ -4,7 +4,9 @@ package cimfs import ( - "github.com/Microsoft/hcsshim/internal/winapi" + "github.com/Microsoft/hcsshim/internal/winapi/cimfs" + "github.com/Microsoft/hcsshim/internal/winapi/cimwriter" + "path/filepath" "github.com/Microsoft/hcsshim/osversion" @@ -19,7 +21,7 @@ func IsCimFSSupported() bool { build := osversion.Build() // CimFS support is backported to LTSC2022 starting with revision 2031 and should // otherwise be available on all builds >= V25H1Server - return (build >= osversion.V25H1Server || (build == osversion.V21H2Server && rv >= 2031)) && winapi.CimFsSupported() + return (build >= osversion.V25H1Server || (build == osversion.V21H2Server && rv >= 2031)) && cimfs.Supported() } // IsBlockCimSupported returns true if block formatted CIMs (i.e block device CIM & @@ -29,7 +31,27 @@ func IsBlockCimSupported() bool { // TODO(ambarve): Currently we are checking against a higher build number since there is no // official build with block CIM support yet. Once we have that build, we should // update the build number here. - return build >= 27766 && winapi.CimFsSupported() + return build >= 27766 && cimfs.Supported() +} + +// IsBlockCimWriteSupported returns true if block formatted CIMs (i.e block device CIM & +// single file CIM) are supported on the current OS build or if CimWriter is present. +func IsBlockCimWriteSupported() bool { + build := osversion.Build() + // TODO(ambarve): Currently we are checking against a higher build number since there is no + // official build with block CIM support yet. Once we have that build, we should + // update the build number here. + return (build >= 27766 && cimfs.Supported()) || cimwriter.Supported() +} + +// IsBlockCimMountSupported returns true if block formatted CIMs (i.e block device CIM & +// single file CIM) are supported on the current OS build. +func IsBlockCimMountSupported() bool { + build := osversion.Build() + // TODO(ambarve): Currently we are checking against a higher build number since there is no + // official build with block CIM support yet. Once we have that build, we should + // update the build number here. + return build >= 27766 && cimfs.Supported() } // IsVerifiedCimSupported returns true if block CIM format supports also writing verification information in the CIM. @@ -38,7 +60,25 @@ func IsVerifiedCimSupported() bool { // TODO(ambarve): Currently we are checking against a higher build number since there is no // official build with block CIM support yet. Once we have that build, we should // update the build number here. - return build >= 27800 && winapi.CimFsSupported() + return build >= 27800 && cimfs.Supported() +} + +// IsVerifiedCimWriteSupported returns true if block CIM format supports also writing verification information in the CIM. +func IsVerifiedCimWriteSupported() bool { + build := osversion.Build() + // TODO(ambarve): Currently we are checking against a higher build number since there is no + // official build with block CIM support yet. Once we have that build, we should + // update the build number here. + return (build >= 27800 && cimfs.Supported()) || cimwriter.Supported() +} + +// IsVerifiedCimMountSupported returns true if block CIM format supports mounting. +func IsVerifiedCimMountSupported() bool { + build := osversion.Build() + // TODO(ambarve): Currently we are checking against a higher build number since there is no + // official build with block CIM support yet. Once we have that build, we should + // update the build number here. + return build >= 27800 && cimfs.Supported() } func IsMergedCimSupported() bool { @@ -48,6 +88,20 @@ func IsMergedCimSupported() bool { return IsBlockCimSupported() } +func IsMergedCimWriteSupported() bool { + // The merged CIM support was originally added before block CIM support. However, + // some of the merged CIM features that we use (e.g. merged hard links) were added + // later along with block CIM support. So use the same check as block CIM here. + return IsBlockCimWriteSupported() +} + +func IsMergedCimMountSupported() bool { + // The merged CIM support was originally added before block CIM support. However, + // some of the merged CIM features that we use (e.g. merged hard links) were added + // later along with block CIM support. So use the same check as block CIM here. + return IsBlockCimMountSupported() +} + type BlockCIMType uint32 const ( diff --git a/pkg/cimfs/mount_cim.go b/pkg/cimfs/mount_cim.go index 7975f6130f..bfb5e753e0 100644 --- a/pkg/cimfs/mount_cim.go +++ b/pkg/cimfs/mount_cim.go @@ -75,7 +75,7 @@ func Unmount(volumePath string) error { // `MergeBlockCIMs`) at a volume with given GUID. The `sourceCIMs` MUST be identical // to the `sourceCIMs` passed to `MergeBlockCIMs` when creating this merged CIM. func MountMergedBlockCIMs(mergedCIM *BlockCIM, sourceCIMs []*BlockCIM, mountFlags uint32, volumeGUID guid.GUID) (string, error) { - if !IsMergedCimSupported() { + if !IsMergedCimMountSupported() { return "", fmt.Errorf("merged CIMs aren't supported on this OS version") } else if len(sourceCIMs) < 2 { return "", fmt.Errorf("need at least 2 source CIMs, got %d: %w", len(sourceCIMs), os.ErrInvalid) @@ -162,7 +162,7 @@ func MountVerifiedBlockCIM(bCIM *BlockCIM, mountFlags uint32, volumeGUID guid.GU // to match against the provided root hash if it doesn't, the read will fail. The source // CIMs and the merged CIM MUST have been created with the verified creation flag. func MountMergedVerifiedBlockCIMs(mergedCIM *BlockCIM, sourceCIMs []*BlockCIM, mountFlags uint32, volumeGUID guid.GUID, rootHash []byte) (string, error) { - if !IsVerifiedCimSupported() { + if !IsVerifiedCimMountSupported() { return "", fmt.Errorf("verified CIMs aren't supported on this OS version") } else if len(sourceCIMs) < 2 { return "", fmt.Errorf("need at least 2 source CIMs, got %d: %w", len(sourceCIMs), os.ErrInvalid) diff --git a/pkg/extractuvm/bcim_test.go b/pkg/extractuvm/bcim_test.go index f2229bdae1..15602a88b9 100755 --- a/pkg/extractuvm/bcim_test.go +++ b/pkg/extractuvm/bcim_test.go @@ -153,7 +153,7 @@ func extractAndVerifyTarToCIM(t *testing.T, tarContents []testFile, contentsToVe } func TestTarUtilityVMExtract(t *testing.T) { - if !cimfs.IsVerifiedCimSupported() { + if !cimfs.IsVerifiedCimMountSupported() { t.Skip("block CIMs are not supported on this build") } diff --git a/test/functional/make_uvm_cim_test.go b/test/functional/make_uvm_cim_test.go index d99b1d1673..7eb0430c9e 100644 --- a/test/functional/make_uvm_cim_test.go +++ b/test/functional/make_uvm_cim_test.go @@ -192,7 +192,7 @@ func mountBlockCIM(t *testing.T, bCIM *cimfs.BlockCIM, mountFlags uint32) string // TestCompareUtilityVMCIM compares generated UtilityVM CIM's contents against the WCIFS based layer and ensures that they match. func TestCompareUtilityVMCIM(t *testing.T) { - if !cimfs.IsBlockCimSupported() { + if !cimfs.IsBlockCimMountSupported() { t.Skip("block CIMs are not supported on this build") }