Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed the sparse compatibility #249

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/catalog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@
return "unknown", errors.New("file format not recognized as gzip or tar")
}

func (s *CatalogManifestService) Unzip(ctx basecontext.ApiContext, machineFilePath string, destination string) error {
return s.decompressMachine(ctx, machineFilePath, destination)
}

func (s *CatalogManifestService) decompressMachine(ctx basecontext.ApiContext, machineFilePath string, destination string) error {
staringTime := time.Now()
filePath := filepath.Clean(machineFilePath)
Expand Down Expand Up @@ -417,7 +421,7 @@
return err
}

machineFilePath, err := helpers.SanitizeArchivePath(destination, header.Name)

Check failure

Code scanning / CodeQL

Arbitrary file write extracting an archive containing symbolic links High

Unresolved path from an archive header, which may point outside the archive root, is used in
symlink creation
.
Unresolved path from an archive header, which may point outside the archive root, is used in symlink creation.
if err != nil {
return err
}
Expand All @@ -432,21 +436,39 @@

switch header.Typeflag {
case tar.TypeDir:
ctx.LogDebugf("Directory type found for file %v (byte %v, rune %v)", machineFilePath, header.Typeflag, string(header.Typeflag))
if _, err := os.Stat(machineFilePath); os.IsNotExist(err) {
if err := os.MkdirAll(machineFilePath, os.FileMode(header.Mode)); err != nil {
return err
}
}
case tar.TypeReg:
ctx.LogDebugf("HardFile type found for file %v (byte %v, rune %v): size %v", machineFilePath, header.Typeflag, string(header.Typeflag), header.Size)
file, err := os.OpenFile(filepath.Clean(machineFilePath), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(header.Mode))
if err != nil {
return err
}
defer file.Close()

if err := helpers.CopyTarChunks(file, tarReader); err != nil {
if err := helpers.CopyTarChunks(file, tarReader, header.Size); err != nil {
return err
}
case tar.TypeGNUSparse:
ctx.LogDebugf("Sparse File type found for file %v (byte %v, rune %v): size %v", machineFilePath, header.Typeflag, string(header.Typeflag), header.Size)
file, err := os.OpenFile(filepath.Clean(machineFilePath), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(header.Mode))
if err != nil {
return err
}
defer file.Close()

if err := helpers.CopyTarChunks(file, tarReader, header.Size); err != nil {
return err
}
case tar.TypeSymlink:
ctx.LogDebugf("Symlink File type found for file %v (byte %v, rune %v)", machineFilePath, header.Typeflag, string(header.Typeflag))
os.Symlink(header.Linkname, machineFilePath)
Fixed Show fixed Hide fixed
default:
ctx.LogWarnf("Unknown type found for file %v, ignoring (byte %v, rune %v)", machineFilePath, header.Typeflag, string(header.Typeflag))
}
}

Expand All @@ -455,6 +477,38 @@
return nil
}

func handleSparseFile(header *tar.Header, tarReader *tar.Reader, destDir string) error {
outFile, err := os.Create(destDir + "/" + header.Name)
if err != nil {
return fmt.Errorf("error creating file: %v", err)
}
defer outFile.Close()

fmt.Printf("Writing sparse file: %s (%d bytes)\n", header.Name, header.Size)

// Copy exactly the size of the sparse file
if _, err := io.CopyN(outFile, tarReader, header.Size); err != nil && err != io.EOF {
return fmt.Errorf("error writing sparse file content: %v", err)
}
return nil
}

func handleRegularFile(header *tar.Header, tarReader *tar.Reader, destDir string) error {
outFile, err := os.Create(destDir + "/" + header.Name)
if err != nil {
return fmt.Errorf("error creating file: %v", err)
}
defer outFile.Close()

fmt.Printf("Writing regular file: %s (%d bytes)\n", header.Name, header.Size)

// Copy exactly the size of the regular file
if _, err := io.CopyN(outFile, tarReader, header.Size); err != nil && err != io.EOF {
return fmt.Errorf("error writing file content: %v", err)
}
return nil
}

func (s *CatalogManifestService) sendPullStepInfo(r *models.PullCatalogManifestRequest, msg string) {
if r.StepChannel != nil {
r.StepChannel <- msg
Expand Down
10 changes: 10 additions & 0 deletions src/cmd/test_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/Parallels/prl-devops-service/basecontext"
"github.com/Parallels/prl-devops-service/catalog"
"github.com/Parallels/prl-devops-service/constants"
"github.com/Parallels/prl-devops-service/tests"
"github.com/cjlapao/common-go/helper"
Expand All @@ -20,6 +21,15 @@ func processTestProviders(ctx basecontext.ApiContext, cmd string) {
ctx.LogErrorf(err.Error())
os.Exit(1)
}
case "unzip":
rootctx := basecontext.NewBaseContext()
filename := helper.GetFlagValue("zip-file", "")
destination := helper.GetFlagValue("destination", "")
if destination == "" {
destination = "/tmp"
}
cSrv := catalog.NewManifestService(rootctx)
cSrv.Unzip(rootctx, filename, destination)
default:
processHelp(constants.TEST_COMMAND)

Expand Down
10 changes: 9 additions & 1 deletion src/helpers/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ func GetFileMD5Checksum(path string) (string, error) {
return checksum, nil
}

func CopyTarChunks(file *os.File, reader *tar.Reader) error {
func CopyTarChunks(file *os.File, reader *tar.Reader, fileSize int64) error {
// extractedSize := int64(0)
// lastPrintTime := time.Now()
for {
_, err := io.CopyN(file, reader, 1024)
if err != nil {
Expand All @@ -316,6 +318,12 @@ func CopyTarChunks(file *os.File, reader *tar.Reader) error {
}
return err
}
// extractedSize += 1024
// percentage := float64(extractedSize) / float64(fileSize) * 100
// if time.Since(lastPrintTime) >= 10*time.Second {
// fmt.Printf("\rExtracted: %.2f%%", percentage)
// lastPrintTime = time.Now()
// }
}

return nil
Expand Down
Loading