implement GetCompression; add tests

This commit is contained in:
Denys Smirnov 2016-10-05 16:45:57 +03:00
parent b56d643295
commit 3343324613
3 changed files with 237 additions and 1 deletions

View File

@ -1,6 +1,7 @@
package btrfs
import (
"bytes"
"fmt"
"github.com/dennwc/btrfs/ioctl"
"io"
@ -228,6 +229,8 @@ const (
ZLIB = Compression("zlib")
)
const xattrCompression = xattrPrefix + "compression"
func SetCompression(path string, v Compression) error {
var value []byte
if v != CompressionNone {
@ -237,9 +240,39 @@ func SetCompression(path string, v Compression) error {
return err
}
}
err := syscall.Setxattr(path, xattrPrefix+"compression", value, 0)
err := syscall.Setxattr(path, xattrCompression, value, 0)
if err != nil {
return &os.PathError{Op: "setxattr", Path: path, Err: err}
}
return nil
}
func GetCompression(path string) (Compression, error) {
var buf []byte
for {
sz, err := syscall.Getxattr(path, xattrCompression, nil)
if err == syscall.ENODATA || sz == 0 {
return CompressionNone, nil
} else if err != nil {
return CompressionNone, &os.PathError{Op: "getxattr", Path: path, Err: err}
}
if cap(buf) < sz {
buf = make([]byte, sz)
} else {
buf = buf[:sz]
}
sz, err = syscall.Getxattr(path, xattrCompression, buf)
if err == syscall.ENODATA {
return CompressionNone, nil
} else if err == syscall.ERANGE {
// xattr changed by someone else, and is larger than our current buffer
continue
} else if err != nil {
return CompressionNone, &os.PathError{Op: "getxattr", Path: path, Err: err}
}
buf = buf[:sz]
break
}
buf = bytes.TrimSuffix(buf, []byte{0})
return Compression(buf), nil
}

97
btrfs_test.go Normal file
View File

@ -0,0 +1,97 @@
package btrfs
import (
"github.com/dennwc/btrfs/test"
"os"
"path/filepath"
"testing"
)
const sizeDef = 256 * 1024 * 1024
func TestOpen(t *testing.T) {
dir, closer := btrfstest.New(t, sizeDef)
defer closer()
fs, err := Open(dir, true)
if err != nil {
t.Fatal(err)
}
if err = fs.Close(); err != nil {
t.Fatal(err)
}
}
func TestIsSubvolume(t *testing.T) {
dir, closer := btrfstest.New(t, sizeDef)
defer closer()
isSubvol := func(path string, expect bool) {
ok, err := IsSubVolume(path)
if err != nil {
t.Errorf("failed to check subvolume %v: %v", path, err)
return
} else if ok != expect {
t.Errorf("unexpected result for %v", path)
}
}
mkdir := func(path string) {
path = filepath.Join(dir, path)
if err := os.MkdirAll(path, 0755); err != nil {
t.Fatalf("cannot create dir %v: %v", path, err)
}
isSubvol(path, false)
}
mksub := func(path string) {
path = filepath.Join(dir, path)
if err := CreateSubVolume(path); err != nil {
t.Fatalf("cannot create subvolume %v: %v", path, err)
}
isSubvol(path, true)
}
mksub("v1")
mkdir("v1/d2")
mksub("v1/v2")
mkdir("v1/d2/d3")
mksub("v1/d2/v3")
mkdir("v1/v2/d3")
mksub("v1/v2/v3")
mkdir("d1")
mkdir("d1/d2")
mksub("d1/v2")
mkdir("d1/d2/d3")
mksub("d1/d2/v3")
mkdir("d1/v2/d3")
mksub("d1/v2/v3")
}
func TestCompression(t *testing.T) {
dir, closer := btrfstest.New(t, sizeDef)
defer closer()
fs, err := Open(dir, true)
if err != nil {
t.Fatal(err)
}
defer fs.Close()
if err := fs.CreateSubVolume("sub"); err != nil {
t.Fatal(err)
}
path := filepath.Join(dir, "sub")
if err := SetCompression(path, LZO); err != nil {
t.Fatal(err)
}
if c, err := GetCompression(path); err != nil {
t.Fatal(err)
} else if c != LZO {
t.Fatalf("unexpected compression returned: %q", string(c))
}
}

106
test/btrfstest.go Normal file
View File

@ -0,0 +1,106 @@
package btrfstest
import (
"bytes"
"errors"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"testing"
"time"
)
func run(name string, args ...string) error {
buf := bytes.NewBuffer(nil)
cmd := exec.Command(name, args...)
cmd.Stdout = buf
cmd.Stderr = buf
err := cmd.Run()
if err == nil {
return nil
} else if buf.Len() == 0 {
return err
}
return errors.New("error: " + strings.TrimSpace(string(buf.Bytes())))
}
func Mkfs(file string, size int64) error {
f, err := os.Create(file)
if err != nil {
return err
}
if err = f.Truncate(size); err != nil {
f.Close()
return err
}
if err = f.Close(); err != nil {
return err
}
if err = run("mkfs.btrfs", file); err != nil {
os.Remove(file)
return err
}
return err
}
func Mount(mount string, file string) error {
if err := run("mount", file, mount); err != nil {
return err
}
return nil
}
func New(t testing.TB, size int64) (string, func()) {
f, err := ioutil.TempFile("", "btrfs_vol")
if err != nil {
t.Fatal(err)
}
name := f.Name()
f.Close()
rm := func() {
os.Remove(name)
}
if err = Mkfs(name, size); err != nil {
rm()
}
mount, err := ioutil.TempDir("", "btrfs_mount")
if err != nil {
rm()
t.Fatal(err)
}
if err = Mount(mount, name); err != nil {
rm()
os.RemoveAll(mount)
if txt := err.Error(); strings.Contains(txt, "permission denied") ||
strings.Contains(txt, "only root") {
t.Skip(err)
} else {
t.Fatal(err)
}
}
done := false
return mount, func() {
if done {
return
}
for i := 0; i < 5; i++ {
if err := run("umount", mount); err == nil {
break
} else {
log.Println("umount failed:", err)
if strings.Contains(err.Error(), "busy") {
time.Sleep(time.Second)
} else {
break
}
}
}
if err := os.Remove(mount); err != nil {
log.Println("cleanup failed:", err)
}
rm()
done = true
}
}