github.com/hanwen/go-fuse@v1.0.0/fuse/pathfs/xattr_test.go (about)

     1  // Copyright 2016 the Go-FUSE Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build linux
     6  
     7  package pathfs
     8  
     9  import (
    10  	"bytes"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	"github.com/hanwen/go-fuse/fuse"
    16  	"github.com/hanwen/go-fuse/fuse/nodefs"
    17  	"github.com/hanwen/go-fuse/internal/testutil"
    18  )
    19  
    20  var xattrGolden = map[string][]byte{
    21  	"user.attr1": []byte("val1"),
    22  	"user.attr2": []byte("val2")}
    23  var xattrFilename = "filename"
    24  
    25  type XAttrTestFs struct {
    26  	filename string
    27  	attrs    map[string][]byte
    28  
    29  	FileSystem
    30  }
    31  
    32  func NewXAttrFs(nm string, m map[string][]byte) *XAttrTestFs {
    33  	x := &XAttrTestFs{
    34  		filename:   nm,
    35  		attrs:      make(map[string][]byte, len(m)),
    36  		FileSystem: NewDefaultFileSystem(),
    37  	}
    38  
    39  	for k, v := range m {
    40  		x.attrs[k] = v
    41  	}
    42  	return x
    43  }
    44  
    45  func (fs *XAttrTestFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
    46  	a := &fuse.Attr{}
    47  	if name == "" || name == "/" {
    48  		a.Mode = fuse.S_IFDIR | 0700
    49  		return a, fuse.OK
    50  	}
    51  	if name == fs.filename {
    52  		a.Mode = fuse.S_IFREG | 0600
    53  		return a, fuse.OK
    54  	}
    55  	return nil, fuse.ENOENT
    56  }
    57  
    58  func (fs *XAttrTestFs) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
    59  	if name != fs.filename {
    60  		return fuse.ENOENT
    61  	}
    62  	dest := make([]byte, len(data))
    63  	copy(dest, data)
    64  	fs.attrs[attr] = dest
    65  	return fuse.OK
    66  }
    67  
    68  func (fs *XAttrTestFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
    69  	if name != fs.filename {
    70  		return nil, fuse.ENOENT
    71  	}
    72  	v, ok := fs.attrs[attr]
    73  	if !ok {
    74  		return nil, fuse.ENOATTR
    75  	}
    76  	return v, fuse.OK
    77  }
    78  
    79  func (fs *XAttrTestFs) ListXAttr(name string, context *fuse.Context) (data []string, code fuse.Status) {
    80  	if name != fs.filename {
    81  		return nil, fuse.ENOENT
    82  	}
    83  
    84  	for k := range fs.attrs {
    85  		data = append(data, k)
    86  	}
    87  	return data, fuse.OK
    88  }
    89  
    90  func (fs *XAttrTestFs) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
    91  	if name != fs.filename {
    92  		return fuse.ENOENT
    93  	}
    94  	_, ok := fs.attrs[attr]
    95  	if !ok {
    96  		return fuse.ENOATTR
    97  	}
    98  	delete(fs.attrs, attr)
    99  	return fuse.OK
   100  }
   101  
   102  func readXAttr(p, a string) (val []byte, err error) {
   103  	val = make([]byte, 1024)
   104  	return getXAttr(p, a, val)
   105  }
   106  
   107  func xattrTestCase(t *testing.T, nm string, m map[string][]byte) (mountPoint string, cleanup func()) {
   108  	xfs := NewXAttrFs(nm, m)
   109  	mountPoint = testutil.TempDir()
   110  
   111  	nfs := NewPathNodeFs(xfs, nil)
   112  	state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(),
   113  		&nodefs.Options{Debug: VerboseTest()})
   114  	if err != nil {
   115  		t.Fatalf("MountRoot failed: %v", err)
   116  	}
   117  
   118  	go state.Serve()
   119  	return mountPoint, func() {
   120  		state.Unmount()
   121  		os.RemoveAll(mountPoint)
   122  	}
   123  }
   124  
   125  func TestXAttrNoAttrs(t *testing.T) {
   126  	nm := xattrFilename
   127  	mountPoint, clean := xattrTestCase(t, nm, make(map[string][]byte))
   128  	defer clean()
   129  
   130  	mounted := filepath.Join(mountPoint, nm)
   131  	attrs, err := listXAttr(mounted)
   132  	if err != nil {
   133  		t.Error("Unexpected ListXAttr error", err)
   134  	}
   135  
   136  	if len(attrs) > 0 {
   137  		t.Errorf("ListXAttr(%s) = %s, want empty slice", mounted, attrs)
   138  	}
   139  }
   140  
   141  func TestXAttrNoExist(t *testing.T) {
   142  	nm := xattrFilename
   143  	mountPoint, clean := xattrTestCase(t, nm, xattrGolden)
   144  	defer clean()
   145  
   146  	mounted := filepath.Join(mountPoint, nm)
   147  	_, err := os.Lstat(mounted)
   148  	if err != nil {
   149  		t.Error("Unexpected stat error", err)
   150  	}
   151  
   152  	val, err := readXAttr(mounted, "noexist")
   153  	if err == nil {
   154  		t.Error("Expected GetXAttr error", val)
   155  	}
   156  }
   157  
   158  func TestXAttrRead(t *testing.T) {
   159  	nm := xattrFilename
   160  	mountPoint, clean := xattrTestCase(t, nm, xattrGolden)
   161  	defer clean()
   162  
   163  	mounted := filepath.Join(mountPoint, nm)
   164  	attrs, err := listXAttr(mounted)
   165  	readback := make(map[string][]byte)
   166  	if err != nil {
   167  		t.Error("Unexpected ListXAttr error", err)
   168  	} else {
   169  		for _, a := range attrs {
   170  			val, err := readXAttr(mounted, a)
   171  			if err != nil {
   172  				t.Errorf("GetXAttr(%q) failed: %v", a, err)
   173  			}
   174  			readback[a] = val
   175  		}
   176  	}
   177  
   178  	if len(readback) != len(xattrGolden) {
   179  		t.Error("length mismatch", xattrGolden, readback)
   180  	} else {
   181  		for k, v := range readback {
   182  			if bytes.Compare(xattrGolden[k], v) != 0 {
   183  				t.Error("val mismatch", k, v, xattrGolden[k])
   184  			}
   185  		}
   186  	}
   187  
   188  	err = sysSetxattr(mounted, "third", []byte("value"), 0)
   189  	if err != nil {
   190  		t.Error("Setxattr error", err)
   191  	}
   192  	val, err := readXAttr(mounted, "third")
   193  	if err != nil || string(val) != "value" {
   194  		t.Error("Read back set xattr:", err, string(val))
   195  	}
   196  
   197  	sysRemovexattr(mounted, "third")
   198  	val, err = readXAttr(mounted, "third")
   199  	if fuse.ToStatus(err) != fuse.ENOATTR {
   200  		t.Error("Data not removed?", err, val)
   201  	}
   202  }