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 }