github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/fs/mut.go (about)

     1  // +build linux darwin
     2  
     3  /*
     4  Copyright 2013 Google Inc.
     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  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"log"
    27  	"os"
    28  	"path/filepath"
    29  	"strings"
    30  	"sync"
    31  	"time"
    32  
    33  	"camlistore.org/pkg/blob"
    34  	"camlistore.org/pkg/readerutil"
    35  	"camlistore.org/pkg/schema"
    36  	"camlistore.org/pkg/search"
    37  	"camlistore.org/pkg/syncutil"
    38  
    39  	"camlistore.org/third_party/bazil.org/fuse"
    40  	"camlistore.org/third_party/bazil.org/fuse/fs"
    41  )
    42  
    43  // How often to refresh directory nodes by reading from the blobstore.
    44  const populateInterval = 30 * time.Second
    45  
    46  // How long an item that was created locally will be present
    47  // regardless of its presence in the indexing server.
    48  const deletionRefreshWindow = time.Minute
    49  
    50  type nodeType int
    51  
    52  const (
    53  	fileType nodeType = iota
    54  	dirType
    55  	symlinkType
    56  )
    57  
    58  // mutDir is a mutable directory.
    59  // Its br is the permanode with camliPath:entname attributes.
    60  type mutDir struct {
    61  	fs        *CamliFileSystem
    62  	permanode blob.Ref
    63  	parent    *mutDir // or nil, if the root within its roots.go root.
    64  	name      string  // ent name (base name within parent)
    65  
    66  	localCreateTime time.Time // time this node was created locally (iff it was)
    67  
    68  	mu       sync.Mutex
    69  	lastPop  time.Time
    70  	children map[string]mutFileOrDir
    71  	xattrs   map[string][]byte
    72  	deleted  bool
    73  }
    74  
    75  func (m *mutDir) String() string {
    76  	return fmt.Sprintf("&mutDir{%p name=%q perm:%v}", m, m.fullPath(), m.permanode)
    77  }
    78  
    79  // for debugging
    80  func (n *mutDir) fullPath() string {
    81  	if n == nil {
    82  		return ""
    83  	}
    84  	return filepath.Join(n.parent.fullPath(), n.name)
    85  }
    86  
    87  func (n *mutDir) Attr() fuse.Attr {
    88  	return fuse.Attr{
    89  		Inode: n.permanode.Sum64(),
    90  		Mode:  os.ModeDir | 0700,
    91  		Uid:   uint32(os.Getuid()),
    92  		Gid:   uint32(os.Getgid()),
    93  	}
    94  }
    95  
    96  func (n *mutDir) Access(req *fuse.AccessRequest, intr fs.Intr) fuse.Error {
    97  	n.mu.Lock()
    98  	defer n.mu.Unlock()
    99  	if n.deleted {
   100  		return fuse.ENOENT
   101  	}
   102  	return nil
   103  }
   104  
   105  func (n *mutFile) Access(req *fuse.AccessRequest, intr fs.Intr) fuse.Error {
   106  	n.mu.Lock()
   107  	defer n.mu.Unlock()
   108  	if n.deleted {
   109  		return fuse.ENOENT
   110  	}
   111  	return nil
   112  }
   113  
   114  // populate hits the blobstore to populate map of child nodes.
   115  func (n *mutDir) populate() error {
   116  	n.mu.Lock()
   117  	defer n.mu.Unlock()
   118  
   119  	// Only re-populate if we haven't done so recently.
   120  	now := time.Now()
   121  	if n.lastPop.Add(populateInterval).After(now) {
   122  		return nil
   123  	}
   124  	n.lastPop = now
   125  
   126  	res, err := n.fs.client.Describe(&search.DescribeRequest{
   127  		BlobRef: n.permanode,
   128  		Depth:   3,
   129  	})
   130  	if err != nil {
   131  		log.Println("mutDir.paths:", err)
   132  		return nil
   133  	}
   134  	db := res.Meta[n.permanode.String()]
   135  	if db == nil {
   136  		return errors.New("dir blobref not described")
   137  	}
   138  
   139  	// Find all child permanodes and stick them in n.children
   140  	if n.children == nil {
   141  		n.children = make(map[string]mutFileOrDir)
   142  	}
   143  	currentChildren := map[string]bool{}
   144  	for k, v := range db.Permanode.Attr {
   145  		const p = "camliPath:"
   146  		if !strings.HasPrefix(k, p) || len(v) < 1 {
   147  			continue
   148  		}
   149  		name := k[len(p):]
   150  		childRef := v[0]
   151  		child := res.Meta[childRef]
   152  		if child == nil {
   153  			log.Printf("child not described: %v", childRef)
   154  			continue
   155  		}
   156  		if child.Permanode == nil {
   157  			log.Printf("invalid child, not a permanode: %v", childRef)
   158  			continue
   159  		}
   160  		if target := child.Permanode.Attr.Get("camliSymlinkTarget"); target != "" {
   161  			// This is a symlink.
   162  			n.maybeAddChild(name, child.Permanode, &mutFile{
   163  				fs:        n.fs,
   164  				permanode: blob.ParseOrZero(childRef),
   165  				parent:    n,
   166  				name:      name,
   167  				symLink:   true,
   168  				target:    target,
   169  			})
   170  		} else if isDir(child.Permanode) {
   171  			// This is a directory.
   172  			n.maybeAddChild(name, child.Permanode, &mutDir{
   173  				fs:        n.fs,
   174  				permanode: blob.ParseOrZero(childRef),
   175  				parent:    n,
   176  				name:      name,
   177  			})
   178  		} else if contentRef := child.Permanode.Attr.Get("camliContent"); contentRef != "" {
   179  			// This is a file.
   180  			content := res.Meta[contentRef]
   181  			if content == nil {
   182  				log.Printf("child content not described: %v", childRef)
   183  				continue
   184  			}
   185  			if content.CamliType != "file" {
   186  				log.Printf("child not a file: %v", childRef)
   187  				continue
   188  			}
   189  			if content.File == nil {
   190  				log.Printf("camlitype \"file\" child %v has no described File member", childRef)
   191  				continue
   192  			}
   193  			n.maybeAddChild(name, child.Permanode, &mutFile{
   194  				fs:        n.fs,
   195  				permanode: blob.ParseOrZero(childRef),
   196  				parent:    n,
   197  				name:      name,
   198  				content:   blob.ParseOrZero(contentRef),
   199  				size:      content.File.Size,
   200  			})
   201  		} else {
   202  			// unhandled type...
   203  			continue
   204  		}
   205  		currentChildren[name] = true
   206  	}
   207  	// Remove unreferenced children
   208  	for name, oldchild := range n.children {
   209  		if _, ok := currentChildren[name]; !ok {
   210  			if oldchild.eligibleToDelete() {
   211  				delete(n.children, name)
   212  			}
   213  		}
   214  	}
   215  	return nil
   216  }
   217  
   218  // maybeAddChild adds a child directory to this mutable directory
   219  // unless it already has one with this name and permanode.
   220  func (m *mutDir) maybeAddChild(name string, permanode *search.DescribedPermanode,
   221  	child mutFileOrDir) {
   222  	if current, ok := m.children[name]; !ok ||
   223  		current.permanodeString() != child.permanodeString() {
   224  
   225  		child.xattr().load(permanode)
   226  		m.children[name] = child
   227  	}
   228  }
   229  
   230  func isDir(d *search.DescribedPermanode) bool {
   231  	// Explicit
   232  	if d.Attr.Get("camliNodeType") == "directory" {
   233  		return true
   234  	}
   235  	// Implied
   236  	for k := range d.Attr {
   237  		if strings.HasPrefix(k, "camliPath:") {
   238  			return true
   239  		}
   240  	}
   241  	return false
   242  }
   243  
   244  func (n *mutDir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
   245  	if err := n.populate(); err != nil {
   246  		log.Println("populate:", err)
   247  		return nil, fuse.EIO
   248  	}
   249  	n.mu.Lock()
   250  	defer n.mu.Unlock()
   251  	var ents []fuse.Dirent
   252  	for name, childNode := range n.children {
   253  		var ino uint64
   254  		switch v := childNode.(type) {
   255  		case *mutDir:
   256  			ino = v.permanode.Sum64()
   257  		case *mutFile:
   258  			ino = v.permanode.Sum64()
   259  		default:
   260  			log.Printf("mutDir.ReadDir: unknown child type %T", childNode)
   261  		}
   262  
   263  		// TODO: figure out what Dirent.Type means.
   264  		// fuse.go says "Type uint32 // ?"
   265  		dirent := fuse.Dirent{
   266  			Name:  name,
   267  			Inode: ino,
   268  		}
   269  		log.Printf("mutDir(%q) appending inode %x, %+v", n.fullPath(), dirent.Inode, dirent)
   270  		ents = append(ents, dirent)
   271  	}
   272  	return ents, nil
   273  }
   274  
   275  func (n *mutDir) Lookup(name string, intr fs.Intr) (ret fs.Node, err fuse.Error) {
   276  	defer func() {
   277  		log.Printf("mutDir(%q).Lookup(%q) = %v, %v", n.fullPath(), name, ret, err)
   278  	}()
   279  	if err := n.populate(); err != nil {
   280  		log.Println("populate:", err)
   281  		return nil, fuse.EIO
   282  	}
   283  	n.mu.Lock()
   284  	defer n.mu.Unlock()
   285  	if n2 := n.children[name]; n2 != nil {
   286  		return n2, nil
   287  	}
   288  	return nil, fuse.ENOENT
   289  }
   290  
   291  // Create of regular file. (not a dir)
   292  //
   293  // Flags are always 514:  O_CREAT is 0x200 | O_RDWR is 0x2.
   294  // From fuse_vnops.c:
   295  //    /* XXX: We /always/ creat() like this. Wish we were on Linux. */
   296  //    foi->flags = O_CREAT | O_RDWR;
   297  //
   298  // 2013/07/21 05:26:35 <- &{Create [ID=0x3 Node=0x8 Uid=61652 Gid=5000 Pid=13115] "x" fl=514 mode=-rw-r--r-- fuse.Intr}
   299  // 2013/07/21 05:26:36 -> 0x3 Create {LookupResponse:{Node:23 Generation:0 EntryValid:1m0s AttrValid:1m0s Attr:{Inode:15976986887557313215 Size:0 Blocks:0 Atime:2013-07-21 05:23:51.537251251 +1200 NZST Mtime:2013-07-21 05:23:51.537251251 +1200 NZST Ctime:2013-07-21 05:23:51.537251251 +1200 NZST Crtime:2013-07-21 05:23:51.537251251 +1200 NZST Mode:-rw------- Nlink:1 Uid:61652 Gid:5000 Rdev:0 Flags:0}} OpenResponse:{Handle:1 Flags:OpenDirectIO}}
   300  func (n *mutDir) Create(req *fuse.CreateRequest, res *fuse.CreateResponse, intr fs.Intr) (fs.Node, fs.Handle, fuse.Error) {
   301  	child, err := n.creat(req.Name, fileType)
   302  	if err != nil {
   303  		log.Printf("mutDir.Create(%q): %v", req.Name, err)
   304  		return nil, nil, fuse.EIO
   305  	}
   306  
   307  	// Create and return a file handle.
   308  	h, ferr := child.(*mutFile).newHandle(nil)
   309  	if ferr != nil {
   310  		return nil, nil, ferr
   311  	}
   312  
   313  	// This isn't required (or even ever been shown to make a
   314  	// difference), but we do it to match OpenRequest below, where
   315  	// it causes test failures without:
   316  	res.OpenResponse.Flags &= ^fuse.OpenDirectIO
   317  
   318  	return child, h, nil
   319  }
   320  
   321  func (n *mutDir) Mkdir(req *fuse.MkdirRequest, intr fs.Intr) (fs.Node, fuse.Error) {
   322  	child, err := n.creat(req.Name, dirType)
   323  	if err != nil {
   324  		log.Printf("mutDir.Mkdir(%q): %v", req.Name, err)
   325  		return nil, fuse.EIO
   326  	}
   327  	return child, nil
   328  }
   329  
   330  // &fuse.SymlinkRequest{Header:fuse.Header{Conn:(*fuse.Conn)(0xc210047180), ID:0x4, Node:0x8, Uid:0xf0d4, Gid:0x1388, Pid:0x7e88}, NewName:"some-link", Target:"../../some-target"}
   331  func (n *mutDir) Symlink(req *fuse.SymlinkRequest, intr fs.Intr) (fs.Node, fuse.Error) {
   332  	node, err := n.creat(req.NewName, symlinkType)
   333  	if err != nil {
   334  		log.Printf("mutDir.Symlink(%q): %v", req.NewName, err)
   335  		return nil, fuse.EIO
   336  	}
   337  	mf := node.(*mutFile)
   338  	mf.symLink = true
   339  	mf.target = req.Target
   340  
   341  	claim := schema.NewSetAttributeClaim(mf.permanode, "camliSymlinkTarget", req.Target)
   342  	_, err = n.fs.client.UploadAndSignBlob(claim)
   343  	if err != nil {
   344  		log.Printf("mutDir.Symlink(%q) upload error: %v", req.NewName, err)
   345  		return nil, fuse.EIO
   346  	}
   347  
   348  	return node, nil
   349  }
   350  
   351  func (n *mutDir) creat(name string, typ nodeType) (fs.Node, error) {
   352  	// Create a Permanode for the file/directory.
   353  	pr, err := n.fs.client.UploadNewPermanode()
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  
   358  	var grp syncutil.Group
   359  	grp.Go(func() (err error) {
   360  		// Add a camliPath:name attribute to the directory permanode.
   361  		claim := schema.NewSetAttributeClaim(n.permanode, "camliPath:"+name, pr.BlobRef.String())
   362  		_, err = n.fs.client.UploadAndSignBlob(claim)
   363  		return
   364  	})
   365  
   366  	// Hide OS X Finder .DS_Store junk.  This is distinct from
   367  	// extended attributes.
   368  	if name == ".DS_Store" {
   369  		grp.Go(func() (err error) {
   370  			claim := schema.NewSetAttributeClaim(pr.BlobRef, "camliDefVis", "hide")
   371  			_, err = n.fs.client.UploadAndSignBlob(claim)
   372  			return
   373  		})
   374  	}
   375  
   376  	if typ == dirType {
   377  		grp.Go(func() (err error) {
   378  			// Set a directory type on the permanode
   379  			claim := schema.NewSetAttributeClaim(pr.BlobRef, "camliNodeType", "directory")
   380  			_, err = n.fs.client.UploadAndSignBlob(claim)
   381  			return
   382  		})
   383  	}
   384  	if err := grp.Err(); err != nil {
   385  		return nil, err
   386  	}
   387  
   388  	// Add a child node to this node.
   389  	var child mutFileOrDir
   390  	switch typ {
   391  	case dirType:
   392  		child = &mutDir{
   393  			fs:              n.fs,
   394  			permanode:       pr.BlobRef,
   395  			parent:          n,
   396  			name:            name,
   397  			xattrs:          map[string][]byte{},
   398  			localCreateTime: time.Now(),
   399  		}
   400  	case fileType, symlinkType:
   401  		child = &mutFile{
   402  			fs:              n.fs,
   403  			permanode:       pr.BlobRef,
   404  			parent:          n,
   405  			name:            name,
   406  			xattrs:          map[string][]byte{},
   407  			localCreateTime: time.Now(),
   408  		}
   409  	default:
   410  		panic("bogus creat type")
   411  	}
   412  	n.mu.Lock()
   413  	if n.children == nil {
   414  		n.children = make(map[string]mutFileOrDir)
   415  	}
   416  	n.children[name] = child
   417  	n.mu.Unlock()
   418  
   419  	log.Printf("Created %v in %p", child, n)
   420  
   421  	return child, nil
   422  }
   423  
   424  func (n *mutDir) Remove(req *fuse.RemoveRequest, intr fs.Intr) fuse.Error {
   425  	// Remove the camliPath:name attribute from the directory permanode.
   426  	claim := schema.NewDelAttributeClaim(n.permanode, "camliPath:"+req.Name, "")
   427  	_, err := n.fs.client.UploadAndSignBlob(claim)
   428  	if err != nil {
   429  		log.Println("mutDir.Create:", err)
   430  		return fuse.EIO
   431  	}
   432  	// Remove child from map.
   433  	n.mu.Lock()
   434  	if n.children != nil {
   435  		if removed, ok := n.children[req.Name]; ok {
   436  			removed.invalidate()
   437  			delete(n.children, req.Name)
   438  			log.Printf("Removed %v from %p", removed, n)
   439  		}
   440  	}
   441  	n.mu.Unlock()
   442  	return nil
   443  }
   444  
   445  // &RenameRequest{Header:fuse.Header{Conn:(*fuse.Conn)(0xc210048180), ID:0x2, Node:0x8, Uid:0xf0d4, Gid:0x1388, Pid:0x5edb}, NewDir:0x8, OldName:"1", NewName:"2"}
   446  func (n *mutDir) Rename(req *fuse.RenameRequest, newDir fs.Node, intr fs.Intr) fuse.Error {
   447  	n2, ok := newDir.(*mutDir)
   448  	if !ok {
   449  		log.Printf("*mutDir newDir node isn't a *mutDir; is a %T; can't handle. returning EIO.", newDir)
   450  		return fuse.EIO
   451  	}
   452  
   453  	var wg syncutil.Group
   454  	wg.Go(n.populate)
   455  	wg.Go(n2.populate)
   456  	if err := wg.Err(); err != nil {
   457  		log.Printf("*mutDir.Rename src dir populate = %v", err)
   458  		return fuse.EIO
   459  	}
   460  
   461  	n.mu.Lock()
   462  	target, ok := n.children[req.OldName]
   463  	n.mu.Unlock()
   464  	if !ok {
   465  		log.Printf("*mutDir.Rename src name %q isn't known", req.OldName)
   466  		return fuse.ENOENT
   467  	}
   468  
   469  	now := time.Now()
   470  
   471  	// Add a camliPath:name attribute to the dest permanode before unlinking it from
   472  	// the source.
   473  	claim := schema.NewSetAttributeClaim(n2.permanode, "camliPath:"+req.NewName, target.permanodeString())
   474  	claim.SetClaimDate(now)
   475  	_, err := n.fs.client.UploadAndSignBlob(claim)
   476  	if err != nil {
   477  		log.Printf("Upload rename link error: %v", err)
   478  		return fuse.EIO
   479  	}
   480  
   481  	delClaim := schema.NewDelAttributeClaim(n.permanode, "camliPath:"+req.OldName, "")
   482  	delClaim.SetClaimDate(now)
   483  	_, err = n.fs.client.UploadAndSignBlob(delClaim)
   484  	if err != nil {
   485  		log.Printf("Upload rename src unlink error: %v", err)
   486  		return fuse.EIO
   487  	}
   488  
   489  	// TODO(bradfitz): this locking would be racy, if the kernel
   490  	// doesn't do it properly. (It should) Let's just trust the
   491  	// kernel for now. Later we can verify and remove this
   492  	// comment.
   493  	n.mu.Lock()
   494  	if n.children[req.OldName] != target {
   495  		panic("Race.")
   496  	}
   497  	delete(n.children, req.OldName)
   498  	n.mu.Unlock()
   499  	n2.mu.Lock()
   500  	n2.children[req.NewName] = target
   501  	n2.mu.Unlock()
   502  
   503  	return nil
   504  }
   505  
   506  // mutFile is a mutable file, or symlink.
   507  type mutFile struct {
   508  	fs        *CamliFileSystem
   509  	permanode blob.Ref
   510  	parent    *mutDir
   511  	name      string // ent name (base name within parent)
   512  
   513  	localCreateTime time.Time // time this node was created locally (iff it was)
   514  
   515  	mu           sync.Mutex // protects all following fields
   516  	symLink      bool       // if true, is a symlink
   517  	target       string     // if a symlink
   518  	content      blob.Ref   // if a regular file
   519  	size         int64
   520  	mtime, atime time.Time // if zero, use serverStart
   521  	xattrs       map[string][]byte
   522  	deleted      bool
   523  }
   524  
   525  func (m *mutFile) String() string {
   526  	return fmt.Sprintf("&mutFile{%p name=%q perm:%v}", m, m.fullPath(), m.permanode)
   527  }
   528  
   529  // for debugging
   530  func (n *mutFile) fullPath() string {
   531  	if n == nil {
   532  		return ""
   533  	}
   534  	return filepath.Join(n.parent.fullPath(), n.name)
   535  }
   536  
   537  func (n *mutFile) xattr() *xattr {
   538  	return &xattr{"mutFile", n.fs, n.permanode, &n.mu, &n.xattrs}
   539  }
   540  
   541  func (n *mutDir) xattr() *xattr {
   542  	return &xattr{"mutDir", n.fs, n.permanode, &n.mu, &n.xattrs}
   543  }
   544  
   545  func (n *mutDir) Removexattr(req *fuse.RemovexattrRequest, intr fs.Intr) fuse.Error {
   546  	return n.xattr().remove(req)
   547  }
   548  
   549  func (n *mutDir) Setxattr(req *fuse.SetxattrRequest, intr fs.Intr) fuse.Error {
   550  	return n.xattr().set(req)
   551  }
   552  
   553  func (n *mutDir) Getxattr(req *fuse.GetxattrRequest, res *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
   554  	return n.xattr().get(req, res)
   555  }
   556  
   557  func (n *mutDir) Listxattr(req *fuse.ListxattrRequest, res *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
   558  	return n.xattr().list(req, res)
   559  }
   560  
   561  func (n *mutFile) Getxattr(req *fuse.GetxattrRequest, res *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
   562  	return n.xattr().get(req, res)
   563  }
   564  
   565  func (n *mutFile) Listxattr(req *fuse.ListxattrRequest, res *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
   566  	return n.xattr().list(req, res)
   567  }
   568  
   569  func (n *mutFile) Removexattr(req *fuse.RemovexattrRequest, intr fs.Intr) fuse.Error {
   570  	return n.xattr().remove(req)
   571  }
   572  
   573  func (n *mutFile) Setxattr(req *fuse.SetxattrRequest, intr fs.Intr) fuse.Error {
   574  	return n.xattr().set(req)
   575  }
   576  
   577  func (n *mutFile) Attr() fuse.Attr {
   578  	// TODO: don't grab n.mu three+ times in here.
   579  	var mode os.FileMode = 0600 // writable
   580  
   581  	n.mu.Lock()
   582  	size := n.size
   583  	var blocks uint64
   584  	if size > 0 {
   585  		blocks = uint64(size)/512 + 1
   586  	}
   587  	inode := n.permanode.Sum64()
   588  	if n.symLink {
   589  		mode |= os.ModeSymlink
   590  	}
   591  	n.mu.Unlock()
   592  
   593  	return fuse.Attr{
   594  		Inode:  inode,
   595  		Mode:   mode,
   596  		Uid:    uint32(os.Getuid()),
   597  		Gid:    uint32(os.Getgid()),
   598  		Size:   uint64(size),
   599  		Blocks: blocks,
   600  		Mtime:  n.modTime(),
   601  		Atime:  n.accessTime(),
   602  		Ctime:  serverStart,
   603  		Crtime: serverStart,
   604  	}
   605  }
   606  
   607  func (n *mutFile) accessTime() time.Time {
   608  	n.mu.Lock()
   609  	if !n.atime.IsZero() {
   610  		defer n.mu.Unlock()
   611  		return n.atime
   612  	}
   613  	n.mu.Unlock()
   614  	return n.modTime()
   615  }
   616  
   617  func (n *mutFile) modTime() time.Time {
   618  	n.mu.Lock()
   619  	defer n.mu.Unlock()
   620  	if !n.mtime.IsZero() {
   621  		return n.mtime
   622  	}
   623  	return serverStart
   624  }
   625  
   626  func (n *mutFile) setContent(br blob.Ref, size int64) error {
   627  	n.mu.Lock()
   628  	defer n.mu.Unlock()
   629  	n.content = br
   630  	n.size = size
   631  	claim := schema.NewSetAttributeClaim(n.permanode, "camliContent", br.String())
   632  	_, err := n.fs.client.UploadAndSignBlob(claim)
   633  	return err
   634  }
   635  
   636  func (n *mutFile) setSizeAtLeast(size int64) {
   637  	n.mu.Lock()
   638  	defer n.mu.Unlock()
   639  	log.Printf("mutFile.setSizeAtLeast(%d). old size = %d", size, n.size)
   640  	if size > n.size {
   641  		n.size = size
   642  	}
   643  }
   644  
   645  // Empirically:
   646  //  open for read:   req.Flags == 0
   647  //  open for append: req.Flags == 1
   648  //  open for write:  req.Flags == 1
   649  //  open for read/write (+<)   == 2 (bitmask? of?)
   650  //
   651  // open flags are O_WRONLY (1), O_RDONLY (0), or O_RDWR (2). and also
   652  // bitmaks of O_SYMLINK (0x200000) maybe. (from
   653  // fuse_filehandle_xlate_to_oflags in macosx/kext/fuse_file.h)
   654  func (n *mutFile) Open(req *fuse.OpenRequest, res *fuse.OpenResponse, intr fs.Intr) (fs.Handle, fuse.Error) {
   655  	mutFileOpen.Incr()
   656  
   657  	log.Printf("mutFile.Open: %v: content: %v dir=%v flags=%v", n.permanode, n.content, req.Dir, req.Flags)
   658  	r, err := schema.NewFileReader(n.fs.fetcher, n.content)
   659  	if err != nil {
   660  		mutFileOpenError.Incr()
   661  		log.Printf("mutFile.Open: %v", err)
   662  		return nil, fuse.EIO
   663  	}
   664  
   665  	// Turn off the OpenDirectIO bit (on by default in rsc fuse server.go),
   666  	// else append operations don't work for some reason.
   667  	res.Flags &= ^fuse.OpenDirectIO
   668  
   669  	// Read-only.
   670  	if !isWriteFlags(req.Flags) {
   671  		mutFileOpenRO.Incr()
   672  		log.Printf("mutFile.Open returning read-only file")
   673  		n := &node{
   674  			fs:      n.fs,
   675  			blobref: n.content,
   676  		}
   677  		return &nodeReader{n: n, fr: r}, nil
   678  	}
   679  
   680  	mutFileOpenRW.Incr()
   681  	log.Printf("mutFile.Open returning read-write filehandle")
   682  
   683  	defer r.Close()
   684  	return n.newHandle(r)
   685  }
   686  
   687  func (n *mutFile) Fsync(r *fuse.FsyncRequest, intr fs.Intr) fuse.Error {
   688  	// TODO(adg): in the fuse package, plumb through fsync to mutFileHandle
   689  	// in the same way we did Truncate.
   690  	log.Printf("mutFile.Fsync: TODO")
   691  	return nil
   692  }
   693  
   694  func (n *mutFile) Readlink(req *fuse.ReadlinkRequest, intr fs.Intr) (string, fuse.Error) {
   695  	n.mu.Lock()
   696  	defer n.mu.Unlock()
   697  	if !n.symLink {
   698  		log.Printf("mutFile.Readlink on node that's not a symlink?")
   699  		return "", fuse.EIO
   700  	}
   701  	return n.target, nil
   702  }
   703  
   704  func (n *mutFile) Setattr(req *fuse.SetattrRequest, res *fuse.SetattrResponse, intr fs.Intr) fuse.Error {
   705  	log.Printf("mutFile.Setattr on %q: %#v", n.fullPath(), req)
   706  	// 2013/07/17 19:43:41 mutFile.Setattr on "foo": &fuse.SetattrRequest{Header:fuse.Header{Conn:(*fuse.Conn)(0xc210047180), ID:0x3, Node:0x3d, Uid:0xf0d4, Gid:0x1388, Pid:0x75e8}, Valid:0x30, Handle:0x0, Size:0x0, Atime:time.Time{sec:63509651021, nsec:0x4aec6b8, loc:(*time.Location)(0x47f7600)}, Mtime:time.Time{sec:63509651021, nsec:0x4aec6b8, loc:(*time.Location)(0x47f7600)}, Mode:0x4000000, Uid:0x0, Gid:0x0, Bkuptime:time.Time{sec:62135596800, nsec:0x0, loc:(*time.Location)(0x47f7600)}, Chgtime:time.Time{sec:62135596800, nsec:0x0, loc:(*time.Location)(0x47f7600)}, Crtime:time.Time{sec:0, nsec:0x0, loc:(*time.Location)(nil)}, Flags:0x0}
   707  
   708  	n.mu.Lock()
   709  	if req.Valid&fuse.SetattrMtime != 0 {
   710  		n.mtime = req.Mtime
   711  	}
   712  	if req.Valid&fuse.SetattrAtime != 0 {
   713  		n.atime = req.Atime
   714  	}
   715  	if req.Valid&fuse.SetattrSize != 0 {
   716  		// TODO(bradfitz): truncate?
   717  		n.size = int64(req.Size)
   718  	}
   719  	n.mu.Unlock()
   720  
   721  	res.AttrValid = 1 * time.Minute
   722  	res.Attr = n.Attr()
   723  	return nil
   724  }
   725  
   726  func (n *mutFile) newHandle(body io.Reader) (fs.Handle, fuse.Error) {
   727  	tmp, err := ioutil.TempFile("", "camli-")
   728  	if err == nil && body != nil {
   729  		_, err = io.Copy(tmp, body)
   730  	}
   731  	if err != nil {
   732  		log.Printf("mutFile.newHandle: %v", err)
   733  		if tmp != nil {
   734  			tmp.Close()
   735  			os.Remove(tmp.Name())
   736  		}
   737  		return nil, fuse.EIO
   738  	}
   739  	return &mutFileHandle{f: n, tmp: tmp}, nil
   740  }
   741  
   742  // mutFileHandle represents an open mutable file.
   743  // It stores the file contents in a temporary file, and
   744  // delegates reads and writes directly to the temporary file.
   745  // When the handle is released, it writes the contents of the
   746  // temporary file to the blobstore, and instructs the parent
   747  // mutFile to update the file permanode.
   748  type mutFileHandle struct {
   749  	f   *mutFile
   750  	tmp *os.File
   751  }
   752  
   753  func (h *mutFileHandle) Read(req *fuse.ReadRequest, res *fuse.ReadResponse, intr fs.Intr) fuse.Error {
   754  	if h.tmp == nil {
   755  		log.Printf("Read called on camli mutFileHandle without a tempfile set")
   756  		return fuse.EIO
   757  	}
   758  
   759  	buf := make([]byte, req.Size)
   760  	n, err := h.tmp.ReadAt(buf, req.Offset)
   761  	if err == io.EOF {
   762  		err = nil
   763  	}
   764  	if err != nil {
   765  		log.Printf("mutFileHandle.Read: %v", err)
   766  		return fuse.EIO
   767  	}
   768  	res.Data = buf[:n]
   769  	return nil
   770  }
   771  
   772  func (h *mutFileHandle) Write(req *fuse.WriteRequest, res *fuse.WriteResponse, intr fs.Intr) fuse.Error {
   773  	if h.tmp == nil {
   774  		log.Printf("Write called on camli mutFileHandle without a tempfile set")
   775  		return fuse.EIO
   776  	}
   777  
   778  	n, err := h.tmp.WriteAt(req.Data, req.Offset)
   779  	log.Printf("mutFileHandle.Write(%q, %d bytes at %d, flags %v) = %d, %v",
   780  		h.f.fullPath(), len(req.Data), req.Offset, req.Flags, n, err)
   781  	if err != nil {
   782  		log.Println("mutFileHandle.Write:", err)
   783  		return fuse.EIO
   784  	}
   785  	res.Size = n
   786  	h.f.setSizeAtLeast(req.Offset + int64(n))
   787  	return nil
   788  }
   789  
   790  // Flush is called to let the file system clean up any data buffers
   791  // and to pass any errors in the process of closing a file to the user
   792  // application.
   793  //
   794  // Flush *may* be called more than once in the case where a file is
   795  // opened more than once, but it's not possible to detect from the
   796  // call itself whether this is a final flush.
   797  //
   798  // This is generally the last opportunity to finalize data and the
   799  // return value sets the return value of the Close that led to the
   800  // calling of Flush.
   801  //
   802  // Note that this is distinct from Fsync -- which is a user-requested
   803  // flush (fsync, etc...)
   804  func (h *mutFileHandle) Flush(*fuse.FlushRequest, fs.Intr) fuse.Error {
   805  	if h.tmp == nil {
   806  		log.Printf("Flush called on camli mutFileHandle without a tempfile set")
   807  		return fuse.EIO
   808  	}
   809  	_, err := h.tmp.Seek(0, 0)
   810  	if err != nil {
   811  		log.Println("mutFileHandle.Flush:", err)
   812  		return fuse.EIO
   813  	}
   814  	var n int64
   815  	br, err := schema.WriteFileFromReader(h.f.fs.client, h.f.name, readerutil.CountingReader{Reader: h.tmp, N: &n})
   816  	if err != nil {
   817  		log.Println("mutFileHandle.Flush:", err)
   818  		return fuse.EIO
   819  	}
   820  	err = h.f.setContent(br, n)
   821  	if err != nil {
   822  		log.Printf("mutFileHandle.Flush: %v", err)
   823  		return fuse.EIO
   824  	}
   825  
   826  	return nil
   827  }
   828  
   829  // Release is called when a file handle is no longer needed.  This is
   830  // called asynchronously after the last handle to a file is closed.
   831  func (h *mutFileHandle) Release(req *fuse.ReleaseRequest, intr fs.Intr) fuse.Error {
   832  	h.tmp.Close()
   833  	os.Remove(h.tmp.Name())
   834  	h.tmp = nil
   835  
   836  	return nil
   837  }
   838  
   839  func (h *mutFileHandle) Truncate(size uint64, intr fs.Intr) fuse.Error {
   840  	if h.tmp == nil {
   841  		log.Printf("Truncate called on camli mutFileHandle without a tempfile set")
   842  		return fuse.EIO
   843  	}
   844  
   845  	log.Printf("mutFileHandle.Truncate(%q) to size %d", h.f.fullPath(), size)
   846  	if err := h.tmp.Truncate(int64(size)); err != nil {
   847  		log.Println("mutFileHandle.Truncate:", err)
   848  		return fuse.EIO
   849  	}
   850  	return nil
   851  }
   852  
   853  // mutFileOrDir is a *mutFile or *mutDir
   854  type mutFileOrDir interface {
   855  	fs.Node
   856  	invalidate()
   857  	permanodeString() string
   858  	xattr() *xattr
   859  	eligibleToDelete() bool
   860  }
   861  
   862  func (n *mutFile) permanodeString() string {
   863  	return n.permanode.String()
   864  }
   865  
   866  func (n *mutDir) permanodeString() string {
   867  	return n.permanode.String()
   868  }
   869  
   870  func (n *mutFile) invalidate() {
   871  	n.mu.Lock()
   872  	n.deleted = true
   873  	n.mu.Unlock()
   874  }
   875  
   876  func (n *mutDir) invalidate() {
   877  	n.mu.Lock()
   878  	n.deleted = true
   879  	n.mu.Unlock()
   880  }
   881  
   882  func (n *mutFile) eligibleToDelete() bool {
   883  	return n.localCreateTime.Before(time.Now().Add(-deletionRefreshWindow))
   884  }
   885  
   886  func (n *mutDir) eligibleToDelete() bool {
   887  	return n.localCreateTime.Before(time.Now().Add(-deletionRefreshWindow))
   888  }