Home Download Docs Code Community
     1	//go:build linux
     2	
     3	/*
     4	Copyright 2013 The Perkeep Authors
     5	
     6	Licensed under the Apache License, Version 2.0 (the "License");
     7	you may not use this file except in compliance with the License.
     8	You may obtain a copy of the License at
     9	
    10	     http://www.apache.org/licenses/LICENSE-2.0
    11	
    12	Unless required by applicable law or agreed to in writing, software
    13	distributed under the License is distributed on an "AS IS" BASIS,
    14	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15	See the License for the specific language governing permissions and
    16	limitations under the License.
    17	*/
    18	
    19	package fs
    20	
    21	import (
    22		"context"
    23		"encoding/base64"
    24		"strings"
    25		"sync"
    26	
    27		"perkeep.org/pkg/blob"
    28		"perkeep.org/pkg/schema"
    29		"perkeep.org/pkg/search"
    30	
    31		"bazil.org/fuse"
    32	)
    33	
    34	// xattrPrefix is the permanode attribute prefix used for record
    35	// extended attributes.
    36	const xattrPrefix = "xattr:"
    37	
    38	// xattr provides common support for extended attributes for various
    39	// file and directory implementations (fuse.Node) within the FUSE services.
    40	type xattr struct {
    41		typeName  string // for logging
    42		fs        *CamliFileSystem
    43		permanode blob.Ref
    44	
    45		// mu guards xattrs.  Both mu and the xattrs map are provided by the
    46		// fuse.Node when the struct is created.
    47		mu *sync.Mutex
    48	
    49		// This is a pointer to the particular fuse.Node's location of its
    50		// xattr map so that it can be initialized commonly when the fuse.Node
    51		// calls xattr.load(*search.DescribedPermanode)
    52		xattrs *map[string][]byte
    53	}
    54	
    55	// load is invoked after the creation of a fuse.Node that may contain extended
    56	// attributes.  This creates the node's xattr map as well as fills it with any
    57	// extended attributes found in the permanode's claims.
    58	func (x *xattr) load(p *search.DescribedPermanode) {
    59		x.mu.Lock()
    60		defer x.mu.Unlock()
    61	
    62		*x.xattrs = map[string][]byte{}
    63		for k, v := range p.Attr {
    64			if strings.HasPrefix(k, xattrPrefix) {
    65				name := k[len(xattrPrefix):]
    66				val, err := base64.StdEncoding.DecodeString(v[0])
    67				if err != nil {
    68					Logger.Printf("Base64 decoding error on attribute %v: %v", name, err)
    69					continue
    70				}
    71				(*x.xattrs)[name] = val
    72			}
    73		}
    74	}
    75	
    76	func (x *xattr) set(ctx context.Context, req *fuse.SetxattrRequest) error {
    77		Logger.Printf("%s.setxattr(%q) -> %q", x.typeName, req.Name, req.Xattr)
    78	
    79		claim := schema.NewSetAttributeClaim(x.permanode, xattrPrefix+req.Name,
    80			base64.StdEncoding.EncodeToString(req.Xattr))
    81		_, err := x.fs.client.UploadAndSignBlob(ctx, claim)
    82		if err != nil {
    83			Logger.Printf("Error setting xattr: %v", err)
    84			return handleEIOorEINTR(err)
    85		}
    86	
    87		val := make([]byte, len(req.Xattr))
    88		copy(val, req.Xattr)
    89		x.mu.Lock()
    90		(*x.xattrs)[req.Name] = val
    91		x.mu.Unlock()
    92	
    93		return nil
    94	}
    95	
    96	func (x *xattr) remove(ctx context.Context, req *fuse.RemovexattrRequest) error {
    97		Logger.Printf("%s.Removexattr(%q)", x.typeName, req.Name)
    98	
    99		claim := schema.NewDelAttributeClaim(x.permanode, xattrPrefix+req.Name, "")
   100		_, err := x.fs.client.UploadAndSignBlob(ctx, claim)
   101	
   102		if err != nil {
   103			Logger.Printf("Error removing xattr: %v", err)
   104			return handleEIOorEINTR(err)
   105		}
   106	
   107		x.mu.Lock()
   108		delete(*x.xattrs, req.Name)
   109		x.mu.Unlock()
   110	
   111		return nil
   112	}
   113	
   114	func (x *xattr) get(req *fuse.GetxattrRequest, res *fuse.GetxattrResponse) error {
   115		x.mu.Lock()
   116		defer x.mu.Unlock()
   117	
   118		val, found := (*x.xattrs)[req.Name]
   119	
   120		if !found {
   121			return fuse.ErrNoXattr
   122		}
   123	
   124		res.Xattr = val
   125	
   126		return nil
   127	}
   128	
   129	func (x *xattr) list(req *fuse.ListxattrRequest, res *fuse.ListxattrResponse) error {
   130		x.mu.Lock()
   131		defer x.mu.Unlock()
   132	
   133		for k := range *x.xattrs {
   134			res.Xattr = append(res.Xattr, k...)
   135			res.Xattr = append(res.Xattr, '\x00')
   136		}
   137		return nil
   138	}
Website layout inspired by memcached.
Content by the authors.