Skip to content

Commit 904c173

Browse files
authored
Copy sparse files as spase files (#379)
Copy sparse files as spase files
2 parents 9df409b + 13ceaed commit 904c173

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

runtime/jailer_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ package main
1515

1616
import (
1717
"context"
18+
"io/ioutil"
1819
"os"
20+
"path/filepath"
21+
"syscall"
1922
"testing"
2023

2124
"github.com/sirupsen/logrus"
2225
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
2327

2428
"github.com/firecracker-microvm/firecracker-containerd/proto"
2529
)
@@ -36,6 +40,45 @@ func TestCopyFile_simple(t *testing.T) {
3640
info, err := os.Stat(dstPath)
3741
assert.NoError(t, err, "failed to stat file")
3842
assert.Equal(t, os.FileMode(expectedMode), info.Mode())
43+
assert.NotEqual(t, 0, int(info.Size()))
44+
}
45+
46+
func createSparseFile(path string, size int) error {
47+
f, err := os.Create(path)
48+
if err != nil {
49+
return err
50+
}
51+
defer f.Close()
52+
53+
err = f.Truncate(int64(size))
54+
if err != nil {
55+
return err
56+
}
57+
58+
return nil
59+
}
60+
func TestCopyFile_sparse(t *testing.T) {
61+
dir, err := ioutil.TempDir("", t.Name())
62+
require.NoError(t, err)
63+
defer os.RemoveAll(dir)
64+
65+
expectedSize := 1024
66+
67+
src := filepath.Join(dir, "original-sparse-file")
68+
err = createSparseFile(src, expectedSize)
69+
require.NoError(t, err)
70+
71+
dst := filepath.Join(dir, "copied-as-sparse")
72+
err = copyFile(src, dst, 0600)
73+
require.NoError(t, err, "failed to copy file")
74+
75+
stat, err := os.Stat(dst)
76+
require.NoError(t, err)
77+
assert.Equal(t, expectedSize, int(stat.Size()), "metadata-wise, the file is not empty")
78+
79+
unixStat, ok := (stat.Sys()).(*syscall.Stat_t)
80+
require.True(t, ok)
81+
assert.Equal(t, int64(0), unixStat.Blocks, "it doesn't allocate any blocks, since the file is empty")
3982
}
4083

4184
func TestCopyFile_invalidPaths(t *testing.T) {

runtime/runc_jailer.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"context"
1818
"encoding/json"
1919
"fmt"
20-
"io"
2120
"io/ioutil"
2221
"os"
2322
"os/exec"
@@ -348,23 +347,12 @@ func exposeBlockDeviceToJail(dst string, rdev, uid, gid int) error {
348347
}
349348

350349
func copyFile(src, dst string, mode os.FileMode) error {
351-
srcFile, err := os.Open(src)
350+
// --sparse=always is a GNU-only option
351+
output, err := exec.Command("cp", "--sparse=always", src, dst).CombinedOutput()
352352
if err != nil {
353-
return errors.Wrapf(err, "failed to open %v", src)
353+
return errors.Wrapf(err, "failed to copy %q to %q: %s", src, dst, output)
354354
}
355-
defer srcFile.Close()
356-
357-
dstFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_EXCL, mode)
358-
if err != nil {
359-
return errors.Wrapf(err, "failed to open %v", dstFile)
360-
}
361-
defer dstFile.Close()
362-
363-
_, err = io.Copy(dstFile, srcFile)
364-
if err != nil {
365-
return errors.Wrap(err, "failed to copy to destination")
366-
}
367-
return nil
355+
return os.Chmod(dst, mode)
368356
}
369357

370358
func (j *runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd {

0 commit comments

Comments
 (0)