From 4f3b4c771d76ab9472f503810e1a2cd126e0c4a5 Mon Sep 17 00:00:00 2001 From: Tim Serong Date: Fri, 8 Mar 2024 15:45:32 +1100 Subject: [PATCH] Consolidate GetImageVirtualSize and DetectFileFormat functions Signed-off-by: Tim Serong --- pkg/backingimage/backingimage.go | 8 ++-- pkg/sync/server_test.go | 4 +- pkg/sync/sync_file.go | 4 +- pkg/util/util.go | 67 ++++++-------------------------- 4 files changed, 20 insertions(+), 63 deletions(-) diff --git a/pkg/backingimage/backingimage.go b/pkg/backingimage/backingimage.go index ab094751..c2833637 100644 --- a/pkg/backingimage/backingimage.go +++ b/pkg/backingimage/backingimage.go @@ -183,13 +183,13 @@ func OpenBackingImage(path string) (*BackingImage, error) { return nil, err } - format, err := util.DetectFileFormat(file) + imgInfo, err := util.GetQemuImgInfo(file) if err != nil { return nil, err } var f enginetypes.DiffDisk - switch format { + switch imgInfo.Format { case "qcow2": // This is only used when doing backup. // We open qcow2 like raw file and simply backup all the blocks of the qcow2 @@ -202,7 +202,7 @@ func OpenBackingImage(path string) (*BackingImage, error) { return nil, err } default: - return nil, fmt.Errorf("format %v of the backing file %v is not supported", format, file) + return nil, fmt.Errorf("format %v of the backing file %v is not supported", imgInfo.Format, file) } size, err := f.Size() @@ -224,7 +224,7 @@ func OpenBackingImage(path string) (*BackingImage, error) { SectorSize: diskutil.BackingImageSectorSize, Path: file, Disk: f, - Format: format, + Format: imgInfo.Format, Location: location, }, nil diff --git a/pkg/sync/server_test.go b/pkg/sync/server_test.go index 3c044644..6cbfed12 100644 --- a/pkg/sync/server_test.go +++ b/pkg/sync/server_test.go @@ -501,9 +501,9 @@ func (s *SyncTestSuite) TestDownloadToDst(c *C) { c.Assert(err, IsNil) c.Assert(downloadChecksum, Equals, checksum) // Downloaded file can be identified as a qcow2 file as well. - downloadFileFormat, err := util.DetectFileFormat(unzipDownloadFilePath) + downloadFileInfo, err := util.GetQemuImgInfo(unzipDownloadFilePath) c.Assert(err, IsNil) - c.Assert(downloadFileFormat, Equals, "qcow2") + c.Assert(downloadFileInfo.Format, Equals, "qcow2") } func (s *SyncTestSuite) TestDuplicateCalls(c *C) { diff --git a/pkg/sync/sync_file.go b/pkg/sync/sync_file.go index cfd029c1..3751b5d9 100644 --- a/pkg/sync/sync_file.go +++ b/pkg/sync/sync_file.go @@ -820,14 +820,14 @@ func (sf *SyncingFile) updateSyncReadyNoLock() { func (sf *SyncingFile) updateVirtualSizeNoLock(filePath string) { // This only works if filePath is valid - sometimes we need to call it // with sf.tmpFilePath, sometimes with sf.filePath :-/ - virtualSize, err := util.GetImageVirtualSize(filePath) + imgInfo, err := util.GetQemuImgInfo(filePath) if err != nil { sf.log.Warnf("SyncingFile: failed to get backing image virtual size: %v", err) } // This will be zero when there is an error, which allows components // further up the stack to know that the virtual size somehow isn't // available yet. - sf.virtualSize = virtualSize + sf.virtualSize = imgInfo.VirtualSize } func (sf *SyncingFile) handleFailureNoLock(err error) { diff --git a/pkg/util/util.go b/pkg/util/util.go index ababb372..d80f22fd 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -1,7 +1,6 @@ package util import ( - "bufio" "bytes" "compress/gzip" "context" @@ -15,7 +14,6 @@ import ( "os/exec" "path/filepath" "regexp" - "strings" "time" "github.com/pkg/errors" @@ -233,68 +231,27 @@ func ExecuteWithTimeout(timeout time.Duration, envs []string, binary string, arg return output.String(), nil } -func DetectFileFormat(filePath string) (string, error) { - - /* Example command outputs - $ qemu-img info parrot.raw - image: parrot.raw - file format: raw - virtual size: 32M (33554432 bytes) - disk size: 2.2M - - $ qemu-img info parrot.qcow2 - image: parrot.qcow2 - file format: qcow2 - virtual size: 32M (33554432 bytes) - disk size: 2.3M - cluster_size: 65536 - Format specific information: - compat: 1.1 - lazy refcounts: false - refcount bits: 16 - corrupt: false - */ - - output, err := Execute([]string{}, QemuImgBinary, "info", filePath) - if err != nil { - return "", err - } - - scanner := bufio.NewScanner(strings.NewReader(output)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if strings.HasPrefix(line, "file format: ") { - return strings.TrimPrefix(line, "file format: "), nil - } - } - - return "", fmt.Errorf("cannot find the file format in the output %s", output) +type QemuImgInfo struct { + // For qcow2 files, VirtualSize may be larger than the physical + // image size on disk. For raw files, `qemu-img info` will report + // VirtualSize as being the same as the physical file size. + VirtualSize int64 `json:"virtual-size"` + Format string `json:"format"` } -func GetImageVirtualSize(filePath string) (int64, error) { - type qemuImgInfo struct { - VirtualSize int64 `json:"virtual-size"` - } - +func GetQemuImgInfo(filePath string) (imgInfo QemuImgInfo, err error) { output, err := Execute([]string{}, QemuImgBinary, "info", "--output=json", filePath) if err != nil { - return 0, err + return } - - var q qemuImgInfo - err = json.Unmarshal([]byte(output), &q) - if err != nil { - return 0, err - } - - // If it's a raw file, `qemu-img info` will return virtual size == size - return q.VirtualSize, nil + err = json.Unmarshal([]byte(output), &imgInfo) + return } func ConvertFromRawToQcow2(filePath string) error { - if format, err := DetectFileFormat(filePath); err != nil { + if imgInfo, err := GetQemuImgInfo(filePath); err != nil { return err - } else if format == "qcow2" { + } else if imgInfo.Format == "qcow2" { return nil }