github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libfuse/mount_test.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 // 5 //go:build !windows 6 // +build !windows 7 8 package libfuse 9 10 import ( 11 "bytes" 12 "encoding/json" 13 "fmt" 14 "io" 15 "os" 16 "os/exec" 17 "path" 18 "reflect" 19 "runtime" 20 "strconv" 21 "strings" 22 "syscall" 23 "testing" 24 "time" 25 26 "bazil.org/fuse" 27 "bazil.org/fuse/fs" 28 "bazil.org/fuse/fs/fstestutil" 29 "github.com/keybase/client/go/kbfs/ioutil" 30 "github.com/keybase/client/go/kbfs/libcontext" 31 "github.com/keybase/client/go/kbfs/libfs" 32 "github.com/keybase/client/go/kbfs/libkbfs" 33 "github.com/keybase/client/go/kbfs/test/clocktest" 34 "github.com/keybase/client/go/kbfs/tlf" 35 kbname "github.com/keybase/client/go/kbun" 36 "github.com/keybase/client/go/logger" 37 "github.com/keybase/client/go/protocol/keybase1" 38 "github.com/pkg/errors" 39 "github.com/stretchr/testify/require" 40 "golang.org/x/net/context" 41 "golang.org/x/sys/unix" 42 ) 43 44 func makeFS(ctx context.Context, t testing.TB, config *libkbfs.ConfigLocal) ( 45 *fstestutil.Mount, *FS, func()) { 46 log := logger.NewTestLogger(t) 47 debugLog := log.CloneWithAddedDepth(1) 48 fuse.Debug = MakeFuseDebugFn(debugLog, false /* superVerbose */) 49 50 // TODO duplicates main() in kbfsfuse/main.go too much 51 filesys := &FS{ 52 config: config, 53 log: log, 54 vlog: config.MakeVLogger(log), 55 errLog: log, 56 errVlog: config.MakeVLogger(log), 57 notifications: libfs.NewFSNotifications(log), 58 root: NewRoot(), 59 } 60 filesys.root.private = &FolderList{ 61 fs: filesys, 62 tlfType: tlf.Private, 63 folders: make(map[string]*TLF), 64 } 65 filesys.root.public = &FolderList{ 66 fs: filesys, 67 tlfType: tlf.Public, 68 folders: make(map[string]*TLF), 69 } 70 filesys.root.team = &FolderList{ 71 fs: filesys, 72 tlfType: tlf.SingleTeam, 73 folders: make(map[string]*TLF), 74 } 75 filesys.execAfterDelay = func(d time.Duration, f func()) { 76 time.AfterFunc(d, f) 77 } 78 fn := func(mnt *fstestutil.Mount) fs.FS { 79 filesys.fuse = mnt.Server 80 filesys.conn = mnt.Conn 81 return filesys 82 } 83 options := GetPlatformSpecificMountOptionsForTest() 84 mnt, err := fstestutil.MountedFuncT(t, fn, &fs.Config{ 85 WithContext: func(ctx context.Context, req fuse.Request) context.Context { 86 return filesys.WithContext(ctx) 87 }, 88 }, options...) 89 if err != nil { 90 t.Fatal(err) 91 } 92 // the cancelFn returned will cancel notification processing; the 93 // FUSE serve loop is terminated by unmounting the filesystem 94 ctx = context.WithValue(ctx, libfs.CtxAppIDKey, filesys) 95 ctx, cancelFn := context.WithCancel(ctx) 96 filesys.LaunchNotificationProcessor(ctx) 97 return mnt, filesys, func() { 98 cancelFn() 99 } 100 } 101 102 type fileInfoCheck func(fi os.FileInfo) error 103 104 func mustBeFileWithSize(fi os.FileInfo, size int64) error { 105 if fi.Size() != size { 106 return fmt.Errorf("Bad file size: %d", fi.Size()) 107 } 108 return nil 109 } 110 111 func mustBeDir(fi os.FileInfo) error { 112 if !fi.IsDir() { 113 return fmt.Errorf("not a directory: %v", fi) 114 } 115 return nil 116 } 117 118 func checkDirNoTestError( 119 t testing.TB, dir string, want map[string]fileInfoCheck) error { 120 // make a copy of want, to be safe 121 { 122 tmp := make(map[string]fileInfoCheck, len(want)) 123 for k, v := range want { 124 tmp[k] = v 125 } 126 want = tmp 127 } 128 129 fis, err := ioutil.ReadDir(dir) 130 if err != nil { 131 t.Fatal(err) 132 } 133 for _, fi := range fis { 134 if check, ok := want[fi.Name()]; ok { 135 delete(want, fi.Name()) 136 if check != nil { 137 if err := check(fi); err != nil { 138 return fmt.Errorf("check failed: %v: %v", fi.Name(), err) 139 } 140 } 141 continue 142 } 143 return fmt.Errorf("unexpected direntry: %q size=%v mode=%v", 144 fi.Name(), fi.Size(), fi.Mode()) 145 } 146 for filename := range want { 147 return fmt.Errorf("never saw file: %v", filename) 148 } 149 return nil 150 } 151 152 func checkDir(t testing.TB, dir string, want map[string]fileInfoCheck) { 153 err := checkDirNoTestError(t, dir, want) 154 if err != nil { 155 t.Error(err) 156 } 157 } 158 159 // timeEqualFuzzy returns whether a is b+-skew. 160 func timeEqualFuzzy(a, b time.Time, skew time.Duration) bool { 161 b1 := b.Add(-skew) 162 b2 := b.Add(skew) 163 return !a.Before(b1) && !a.After(b2) 164 } 165 166 func testCleanupDelayer(ctx context.Context, t *testing.T) { 167 err := libcontext.CleanupCancellationDelayer(ctx) 168 require.NoError(t, err) 169 } 170 171 func TestStatRoot(t *testing.T) { 172 ctx := libcontext.BackgroundContextWithCancellationDelayer() 173 defer testCleanupDelayer(ctx, t) 174 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 175 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 176 mnt, _, cancelFn := makeFS(ctx, t, config) 177 defer mnt.Close() 178 defer cancelFn() 179 180 fi, err := ioutil.Lstat(mnt.Dir) 181 if err != nil { 182 t.Fatal(err) 183 } 184 if g, e := fi.Mode().String(), `dr-x------`; g != e { 185 t.Errorf("wrong mode for folder: %q != %q", g, e) 186 } 187 } 188 189 func TestStatPrivate(t *testing.T) { 190 ctx := libcontext.BackgroundContextWithCancellationDelayer() 191 defer testCleanupDelayer(ctx, t) 192 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 193 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 194 mnt, _, cancelFn := makeFS(ctx, t, config) 195 defer mnt.Close() 196 defer cancelFn() 197 198 fi, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName)) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if g, e := fi.Mode().String(), `dr-x------`; g != e { 203 t.Errorf("wrong mode for folder: %q != %q", g, e) 204 } 205 } 206 207 func TestStatPublic(t *testing.T) { 208 ctx := libcontext.BackgroundContextWithCancellationDelayer() 209 defer testCleanupDelayer(ctx, t) 210 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 211 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 212 mnt, _, cancelFn := makeFS(ctx, t, config) 213 defer mnt.Close() 214 defer cancelFn() 215 216 fi, err := ioutil.Lstat(path.Join(mnt.Dir, PublicName)) 217 if err != nil { 218 t.Fatal(err) 219 } 220 if g, e := fi.Mode().String(), `dr-x------`; g != e { 221 t.Errorf("wrong mode for folder: %q != %q", g, e) 222 } 223 } 224 225 func TestStatMyFolder(t *testing.T) { 226 ctx := libcontext.BackgroundContextWithCancellationDelayer() 227 defer testCleanupDelayer(ctx, t) 228 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 229 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 230 mnt, _, cancelFn := makeFS(ctx, t, config) 231 defer mnt.Close() 232 defer cancelFn() 233 234 // Access the tlf once to have the *Dir populated in tlf.go 235 if err := ioutil.Mkdir( 236 path.Join(mnt.Dir, PrivateName, "jdoe", "d"), os.ModeDir); err != nil { 237 t.Fatal(err) 238 } 239 240 fi, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName, "jdoe")) 241 if err != nil { 242 t.Fatal(err) 243 } 244 if g, e := fi.Mode().String(), `drwx------`; g != e { 245 t.Errorf("wrong mode for folder: %q != %q", g, e) 246 } 247 } 248 249 func TestStatNonexistentFolder(t *testing.T) { 250 ctx := libcontext.BackgroundContextWithCancellationDelayer() 251 defer testCleanupDelayer(ctx, t) 252 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 253 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 254 mnt, _, cancelFn := makeFS(ctx, t, config) 255 defer mnt.Close() 256 defer cancelFn() 257 258 if _, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName, "does-not-exist")); !ioutil.IsNotExist(err) { 259 t.Fatalf("expected ENOENT: %v", err) 260 } 261 } 262 263 func TestStatAlias(t *testing.T) { 264 ctx := libcontext.BackgroundContextWithCancellationDelayer() 265 defer testCleanupDelayer(ctx, t) 266 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 267 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 268 mnt, _, cancelFn := makeFS(ctx, t, config) 269 defer mnt.Close() 270 defer cancelFn() 271 272 p := path.Join(mnt.Dir, PrivateName, "jdoe,jdoe") 273 fi, err := ioutil.Lstat(p) 274 if err != nil { 275 t.Fatal(err) 276 } 277 if g, e := fi.Mode().String(), `Lrwxrwxrwx`; g != e { 278 t.Errorf("wrong mode for alias : %q != %q", g, e) 279 } 280 target, err := os.Readlink(p) 281 if err != nil { 282 t.Fatal(err) 283 } 284 if g, e := target, "jdoe"; g != e { 285 t.Errorf("wrong alias symlink target: %q != %q", g, e) 286 } 287 } 288 289 // Test that we can determine a normalized alias without any identify 290 // calls (regression test for KBFS-531). 291 func TestStatAliasCausesNoIdentifies(t *testing.T) { 292 ctx := libcontext.BackgroundContextWithCancellationDelayer() 293 defer testCleanupDelayer(ctx, t) 294 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 295 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 296 297 mnt, _, cancelFn := makeFS(ctx, t, config) 298 defer mnt.Close() 299 defer cancelFn() 300 301 p := path.Join(mnt.Dir, PublicName, "HEAD") 302 // Even though "head" is not a real user in our config, this stat 303 // should succeed because no identify calls should be triggered. 304 fi, err := ioutil.Lstat(p) 305 if err != nil { 306 t.Fatal(err) 307 } 308 if g, e := fi.Mode().String(), `Lrwxrwxrwx`; g != e { 309 t.Errorf("wrong mode for alias : %q != %q", g, e) 310 } 311 target, err := os.Readlink(p) 312 if err != nil { 313 t.Fatal(err) 314 } 315 if g, e := target, "head"; g != e { 316 t.Errorf("wrong alias symlink target: %q != %q", g, e) 317 } 318 } 319 320 func TestStatInvalidAliasFails(t *testing.T) { 321 ctx := libcontext.BackgroundContextWithCancellationDelayer() 322 defer testCleanupDelayer(ctx, t) 323 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 324 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 325 326 mnt, _, cancelFn := makeFS(ctx, t, config) 327 defer mnt.Close() 328 defer cancelFn() 329 330 p := path.Join(mnt.Dir, PublicName, "HEAD.JPG") 331 // This should fail as HEAD.JPG has the wrong format. 332 _, err := ioutil.Lstat(p) 333 if err == nil { 334 t.Fatal("Lstat of HEAD.JPG didn't return an error!") 335 } 336 } 337 338 func TestRemoveAlias(t *testing.T) { 339 ctx := libcontext.BackgroundContextWithCancellationDelayer() 340 defer testCleanupDelayer(ctx, t) 341 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 342 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 343 mnt, _, cancelFn := makeFS(ctx, t, config) 344 defer mnt.Close() 345 defer cancelFn() 346 347 p := path.Join(mnt.Dir, PrivateName, "jdoe,jdoe") 348 err := ioutil.Remove(p) 349 if err != nil { 350 t.Fatalf("Removing alias failed: %v", err) 351 } 352 } 353 354 func TestStatMyPublic(t *testing.T) { 355 ctx := libcontext.BackgroundContextWithCancellationDelayer() 356 defer testCleanupDelayer(ctx, t) 357 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 358 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 359 mnt, _, cancelFn := makeFS(ctx, t, config) 360 defer mnt.Close() 361 defer cancelFn() 362 363 // Access the tlf once to have the *Dir populated in tlf.go 364 if err := ioutil.Mkdir( 365 path.Join(mnt.Dir, PublicName, "jdoe", "d"), os.ModeDir); err != nil { 366 t.Fatal(err) 367 } 368 369 fi, err := ioutil.Lstat(path.Join(mnt.Dir, PublicName, "jdoe")) 370 if err != nil { 371 t.Fatal(err) 372 } 373 if g, e := fi.Mode().String(), `drwx------`; g != e { 374 t.Errorf("wrong mode for folder: %q != %q", g, e) 375 } 376 } 377 378 func TestReaddirRoot(t *testing.T) { 379 ctx := libcontext.BackgroundContextWithCancellationDelayer() 380 defer testCleanupDelayer(ctx, t) 381 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 382 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 383 mnt, _, cancelFn := makeFS(ctx, t, config) 384 defer mnt.Close() 385 defer cancelFn() 386 387 checkDir(t, mnt.Dir, map[string]fileInfoCheck{ 388 PrivateName: mustBeDir, 389 PublicName: mustBeDir, 390 TeamName: mustBeDir, 391 }) 392 } 393 394 func TestReaddirPrivate(t *testing.T) { 395 ctx := libcontext.BackgroundContextWithCancellationDelayer() 396 defer testCleanupDelayer(ctx, t) 397 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 398 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 399 mnt, _, cancelFn := makeFS(ctx, t, config) 400 defer mnt.Close() 401 defer cancelFn() 402 403 { 404 ctx := libcontext.BackgroundContextWithCancellationDelayer() 405 defer testCleanupDelayer(ctx, t) 406 // Force FakeMDServer to have some TlfIDs it can present to us 407 // as favorites. Don't go through VFS to avoid caching causing 408 // false positives. 409 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 410 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 411 } 412 413 checkDir(t, path.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 414 "jdoe,janedoe": mustBeDir, 415 "jdoe": mustBeDir, // default home directory 416 }) 417 } 418 419 func TestReaddirPrivateDeleteAndReaddFavorite(t *testing.T) { 420 ctx := libcontext.BackgroundContextWithCancellationDelayer() 421 defer testCleanupDelayer(ctx, t) 422 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 423 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 424 mnt, fs, cancelFn := makeFS(ctx, t, config) 425 fs.execAfterDelay = func(d time.Duration, f func()) { 426 // this causes the entry added to fl.recentlyRemoved (in 427 // addToRecentlyRemove) to be removed instantly. this way we can avoid 428 // adding delays in tests. 429 f() 430 } 431 defer mnt.Close() 432 defer cancelFn() 433 434 { 435 ctx := libcontext.BackgroundContextWithCancellationDelayer() 436 defer testCleanupDelayer(ctx, t) 437 // Force FakeMDServer to have some TlfIDs it can present to us 438 // as favorites. Don't go through VFS to avoid caching causing 439 // false positives. 440 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 441 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 442 } 443 444 err := ioutil.Remove(path.Join(mnt.Dir, PrivateName, "jdoe,janedoe")) 445 if err != nil { 446 t.Fatalf("Removing favorite failed: %v", err) 447 } 448 449 checkDir(t, path.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 450 "jdoe": mustBeDir, // default home directory 451 }) 452 453 // Re-add the favorite by doing a readdir 454 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe,janedoe"), 455 map[string]fileInfoCheck{}) 456 457 checkDir(t, path.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 458 "jdoe,janedoe": mustBeDir, 459 "jdoe": mustBeDir, // default home directory 460 }) 461 } 462 463 func TestReaddirPublic(t *testing.T) { 464 ctx := libcontext.BackgroundContextWithCancellationDelayer() 465 defer testCleanupDelayer(ctx, t) 466 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 467 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 468 mnt, _, cancelFn := makeFS(ctx, t, config) 469 defer mnt.Close() 470 defer cancelFn() 471 472 { 473 ctx := libcontext.BackgroundContextWithCancellationDelayer() 474 defer testCleanupDelayer(ctx, t) 475 // Force FakeMDServer to have some TlfIDs it can present to us 476 // as favorites. Don't go through VFS to avoid caching causing 477 // false positives. 478 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 479 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 480 } 481 482 checkDir(t, path.Join(mnt.Dir, PublicName), map[string]fileInfoCheck{ 483 "jdoe,janedoe": mustBeDir, 484 "jdoe": mustBeDir, // default personal public directory 485 }) 486 } 487 488 type kbserviceBrokenIdentify struct { 489 libkbfs.KeybaseService 490 } 491 492 func (k kbserviceBrokenIdentify) Identify( 493 ctx context.Context, assertion, reason string, 494 _ keybase1.OfflineAvailability) ( 495 kbname.NormalizedUsername, keybase1.UserOrTeamID, error) { 496 return kbname.NormalizedUsername(""), keybase1.UserOrTeamID(""), 497 errors.New("Fake identify error") 498 } 499 500 // Regression test for KBFS-772 on OSX. (There's a bug where ls only 501 // respects errors from Open, not from ReadDirAll.) 502 func TestReaddirPublicFailedIdentifyViaOSCall(t *testing.T) { 503 ctx := libcontext.BackgroundContextWithCancellationDelayer() 504 defer testCleanupDelayer(ctx, t) 505 config1 := libkbfs.MakeTestConfigOrBust(t, "u1", "u2") 506 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 507 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 508 defer mnt1.Close() 509 defer cancelFn1() 510 511 config2 := libkbfs.ConfigAsUser(config1, "u2") 512 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 513 mnt2, _, cancelFn2 := makeFS(ctx, t, config2) 514 defer mnt2.Close() 515 defer cancelFn2() 516 517 // Create a shared folder via u2. 518 p := path.Join(mnt2.Dir, PrivateName, "u1,u2", "mydir") 519 if err := ioutil.Mkdir(p, 0755); err != nil { 520 t.Fatal(err) 521 } 522 523 // Make u1 get failures for every identify call. 524 config1.SetKeybaseService(kbserviceBrokenIdentify{ 525 KeybaseService: config1.KeybaseService(), 526 }) 527 528 // A private non-existing home folder, with write permissions, fails. 529 err := exec.Command("ls", path.Join(mnt1.Dir, PublicName, "u1")).Run() 530 if _, ok := err.(*exec.ExitError); !ok { 531 t.Fatalf("No error as expected on broken user identify: %v", err) 532 } 533 534 // A private existing shared folder, with write permissions, fails. 535 err = exec.Command("ls", path.Join(mnt1.Dir, PrivateName, "u1,u2")).Run() 536 if _, ok := err.(*exec.ExitError); !ok { 537 t.Fatalf("No error as expected on broken user identify: %v", err) 538 } 539 540 // A public, non-existing folder, without write permissions, fails. 541 err = exec.Command("ls", path.Join(mnt1.Dir, PublicName, "u2")).Run() 542 if _, ok := err.(*exec.ExitError); !ok { 543 t.Fatalf("No error as expected on broken user identify: %v", err) 544 } 545 } 546 547 func TestReaddirMyFolderEmpty(t *testing.T) { 548 ctx := libcontext.BackgroundContextWithCancellationDelayer() 549 defer testCleanupDelayer(ctx, t) 550 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 551 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 552 mnt, _, cancelFn := makeFS(ctx, t, config) 553 defer mnt.Close() 554 defer cancelFn() 555 556 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 557 } 558 559 func syncAll(t *testing.T, tlf string, ty tlf.Type, fs *FS) { 560 // golang doesn't let us sync on a directory handle, so if we need 561 // to sync all without a file, go through libkbfs directly. 562 ctx := libcontext.BackgroundContextWithCancellationDelayer() 563 defer testCleanupDelayer(ctx, t) 564 root := libkbfs.GetRootNodeOrBust(ctx, t, fs.config, tlf, ty) 565 err := fs.config.KBFSOps().SyncAll(ctx, root.GetFolderBranch()) 566 if err != nil { 567 t.Fatalf("Couldn't sync all: %v", err) 568 } 569 } 570 571 func syncAndClose(t *testing.T, f *os.File) { 572 if f == nil { 573 return 574 } 575 err := f.Sync() 576 if err != nil { 577 t.Fatal(err) 578 } 579 f.Close() 580 } 581 582 func syncFilename(t *testing.T, name string) { 583 f, err := os.OpenFile(name, os.O_WRONLY, 0644) 584 if err != nil { 585 t.Fatal(err) 586 } 587 syncAndClose(t, f) 588 } 589 590 func TestReaddirMyFolderWithFiles(t *testing.T) { 591 ctx := libcontext.BackgroundContextWithCancellationDelayer() 592 defer testCleanupDelayer(ctx, t) 593 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 594 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 595 mnt, _, cancelFn := makeFS(ctx, t, config) 596 defer mnt.Close() 597 defer cancelFn() 598 599 files := map[string]fileInfoCheck{ 600 "one": nil, 601 "two": nil, 602 } 603 for filename, check := range files { 604 if check != nil { 605 // only set up the files 606 continue 607 } 608 p := path.Join(mnt.Dir, PrivateName, "jdoe", filename) 609 if err := ioutil.WriteFile( 610 p, []byte("data for "+filename), 0644); err != nil { 611 t.Fatal(err) 612 } 613 syncFilename(t, p) 614 } 615 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), files) 616 } 617 618 func testOneCreateThenRead(t *testing.T, p string) { 619 f, err := os.Create(p) 620 if err != nil { 621 t.Fatal(err) 622 } 623 // Call in a closure since `f` is overridden below. 624 defer func() { syncAndClose(t, f) }() 625 const input = "hello, world\n" 626 if _, err := io.WriteString(f, input); err != nil { 627 t.Fatalf("write error: %v", err) 628 } 629 syncAndClose(t, f) 630 f = nil 631 632 buf, err := ioutil.ReadFile(p) 633 if err != nil { 634 t.Fatalf("read error: %v", err) 635 } 636 if g, e := string(buf), input; g != e { 637 t.Errorf("bad file contents: %q != %q", g, e) 638 } 639 } 640 641 func TestCreateThenRead(t *testing.T) { 642 ctx := libcontext.BackgroundContextWithCancellationDelayer() 643 defer testCleanupDelayer(ctx, t) 644 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 645 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 646 mnt, _, cancelFn := makeFS(ctx, t, config) 647 defer mnt.Close() 648 defer cancelFn() 649 650 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 651 testOneCreateThenRead(t, p) 652 } 653 654 // Tests that writing and reading multiple files works, implicitly 655 // exercising any block pointer reference counting code (since the 656 // initial created files will have identical empty blocks to start 657 // with). 658 func TestMultipleCreateThenRead(t *testing.T) { 659 ctx := libcontext.BackgroundContextWithCancellationDelayer() 660 defer testCleanupDelayer(ctx, t) 661 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 662 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 663 mnt, _, cancelFn := makeFS(ctx, t, config) 664 defer mnt.Close() 665 defer cancelFn() 666 667 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile1") 668 testOneCreateThenRead(t, p1) 669 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile2") 670 testOneCreateThenRead(t, p2) 671 } 672 673 func TestReadUnflushed(t *testing.T) { 674 ctx := libcontext.BackgroundContextWithCancellationDelayer() 675 defer testCleanupDelayer(ctx, t) 676 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 677 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 678 mnt, _, cancelFn := makeFS(ctx, t, config) 679 defer mnt.Close() 680 defer cancelFn() 681 682 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 683 f, err := os.Create(p) 684 if err != nil { 685 t.Fatal(err) 686 } 687 defer syncAndClose(t, f) 688 const input = "hello, world\n" 689 if _, err := io.WriteString(f, input); err != nil { 690 t.Fatalf("write error: %v", err) 691 } 692 // explicitly no close here 693 694 buf, err := ioutil.ReadFile(p) 695 if err != nil { 696 t.Fatalf("read error: %v", err) 697 } 698 if g, e := string(buf), input; g != e { 699 t.Errorf("bad file contents: %q != %q", g, e) 700 } 701 } 702 703 func TestMountAgain(t *testing.T) { 704 ctx := libcontext.BackgroundContextWithCancellationDelayer() 705 defer testCleanupDelayer(ctx, t) 706 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 707 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 708 709 const input = "hello, world\n" 710 const filename = "myfile" 711 func() { 712 mnt, _, cancelFn := makeFS(ctx, t, config) 713 defer mnt.Close() 714 defer cancelFn() 715 716 p := path.Join(mnt.Dir, PrivateName, "jdoe", filename) 717 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 718 t.Fatal(err) 719 } 720 syncFilename(t, p) 721 }() 722 723 func() { 724 mnt, _, cancelFn := makeFS(ctx, t, config) 725 defer mnt.Close() 726 defer cancelFn() 727 p := path.Join(mnt.Dir, PrivateName, "jdoe", filename) 728 buf, err := ioutil.ReadFile(p) 729 if err != nil { 730 t.Fatalf("read error: %v", err) 731 } 732 if g, e := string(buf), input; g != e { 733 t.Errorf("bad file contents: %q != %q", g, e) 734 } 735 }() 736 } 737 738 func TestCreateExecutable(t *testing.T) { 739 ctx := libcontext.BackgroundContextWithCancellationDelayer() 740 defer testCleanupDelayer(ctx, t) 741 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 742 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 743 mnt, _, cancelFn := makeFS(ctx, t, config) 744 defer mnt.Close() 745 defer cancelFn() 746 747 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 748 if err := ioutil.WriteFile(p, []byte("fake binary"), 0755); err != nil { 749 t.Fatal(err) 750 } 751 syncFilename(t, p) 752 fi, err := ioutil.Lstat(p) 753 if err != nil { 754 t.Fatal(err) 755 } 756 if g, e := fi.Mode().String(), `-rwx------`; g != e { 757 t.Errorf("wrong mode for executable: %q != %q", g, e) 758 } 759 } 760 761 func TestMkdir(t *testing.T) { 762 ctx := libcontext.BackgroundContextWithCancellationDelayer() 763 defer testCleanupDelayer(ctx, t) 764 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 765 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 766 mnt, _, cancelFn := makeFS(ctx, t, config) 767 defer mnt.Close() 768 defer cancelFn() 769 770 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 771 if err := ioutil.Mkdir(p, 0755); err != nil { 772 t.Fatal(err) 773 } 774 fi, err := ioutil.Lstat(p) 775 if err != nil { 776 t.Fatal(err) 777 } 778 if g, e := fi.Mode().String(), `drwx------`; g != e { 779 t.Errorf("wrong mode for subdir: %q != %q", g, e) 780 } 781 } 782 783 func TestMkdirAndCreateDeep(t *testing.T) { 784 ctx := libcontext.BackgroundContextWithCancellationDelayer() 785 defer testCleanupDelayer(ctx, t) 786 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 787 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 788 const input = "hello, world\n" 789 790 func() { 791 mnt, _, cancelFn := makeFS(ctx, t, config) 792 defer mnt.Close() 793 defer cancelFn() 794 795 one := path.Join(mnt.Dir, PrivateName, "jdoe", "one") 796 if err := ioutil.Mkdir(one, 0755); err != nil { 797 t.Fatal(err) 798 } 799 two := path.Join(one, "two") 800 if err := ioutil.Mkdir(two, 0755); err != nil { 801 t.Fatal(err) 802 } 803 three := path.Join(two, "three") 804 if err := ioutil.WriteFile(three, []byte(input), 0644); err != nil { 805 t.Fatal(err) 806 } 807 syncFilename(t, three) 808 }() 809 810 // unmount to flush cache 811 func() { 812 mnt, _, cancelFn := makeFS(ctx, t, config) 813 defer mnt.Close() 814 defer cancelFn() 815 816 p := path.Join(mnt.Dir, PrivateName, "jdoe", "one", "two", "three") 817 buf, err := ioutil.ReadFile(p) 818 if err != nil { 819 t.Fatalf("read error: %v", err) 820 } 821 if g, e := string(buf), input; g != e { 822 t.Errorf("bad file contents: %q != %q", g, e) 823 } 824 }() 825 } 826 827 func TestSymlink(t *testing.T) { 828 ctx := libcontext.BackgroundContextWithCancellationDelayer() 829 defer testCleanupDelayer(ctx, t) 830 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 831 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 832 833 func() { 834 mnt, _, cancelFn := makeFS(ctx, t, config) 835 defer mnt.Close() 836 defer cancelFn() 837 838 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mylink") 839 if err := os.Symlink("myfile", p); err != nil { 840 t.Fatal(err) 841 } 842 }() 843 844 // unmount to flush cache 845 func() { 846 mnt, _, cancelFn := makeFS(ctx, t, config) 847 defer mnt.Close() 848 defer cancelFn() 849 850 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mylink") 851 target, err := os.Readlink(p) 852 if err != nil { 853 t.Fatal(err) 854 } 855 if g, e := target, "myfile"; g != e { 856 t.Errorf("bad symlink target: %q != %q", g, e) 857 } 858 }() 859 } 860 861 func TestRename(t *testing.T) { 862 ctx := libcontext.BackgroundContextWithCancellationDelayer() 863 defer testCleanupDelayer(ctx, t) 864 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 865 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 866 mnt, _, cancelFn := makeFS(ctx, t, config) 867 defer mnt.Close() 868 defer cancelFn() 869 870 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "old") 871 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "new") 872 const input = "hello, world\n" 873 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 874 t.Fatal(err) 875 } 876 syncFilename(t, p1) 877 878 if err := ioutil.Rename(p1, p2); err != nil { 879 t.Fatal(err) 880 } 881 882 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 883 "new": func(fi os.FileInfo) error { 884 return mustBeFileWithSize(fi, int64(len(input))) 885 }, 886 }) 887 888 buf, err := ioutil.ReadFile(p2) 889 if err != nil { 890 t.Errorf("read error: %v", err) 891 } 892 if g, e := string(buf), input; g != e { 893 t.Errorf("bad file contents: %q != %q", g, e) 894 } 895 896 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 897 t.Errorf("old name still exists: %v", err) 898 } 899 } 900 901 func TestRenameOverwrite(t *testing.T) { 902 ctx := libcontext.BackgroundContextWithCancellationDelayer() 903 defer testCleanupDelayer(ctx, t) 904 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 905 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 906 mnt, _, cancelFn := makeFS(ctx, t, config) 907 defer mnt.Close() 908 defer cancelFn() 909 910 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "old") 911 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "new") 912 const input = "hello, world\n" 913 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 914 t.Fatal(err) 915 } 916 syncFilename(t, p1) 917 if err := ioutil.WriteFile(p2, []byte("loser\n"), 0644); err != nil { 918 t.Fatal(err) 919 } 920 syncFilename(t, p2) 921 922 if err := ioutil.Rename(p1, p2); err != nil { 923 t.Fatal(err) 924 } 925 926 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 927 "new": nil, 928 }) 929 930 buf, err := ioutil.ReadFile(p2) 931 if err != nil { 932 t.Errorf("read error: %v", err) 933 } 934 if g, e := string(buf), input; g != e { 935 t.Errorf("bad file contents: %q != %q", g, e) 936 } 937 938 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 939 t.Errorf("old name still exists: %v", err) 940 } 941 } 942 943 func TestRenameCrossDir(t *testing.T) { 944 ctx := libcontext.BackgroundContextWithCancellationDelayer() 945 defer testCleanupDelayer(ctx, t) 946 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 947 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 948 mnt, _, cancelFn := makeFS(ctx, t, config) 949 defer mnt.Close() 950 defer cancelFn() 951 952 if err := ioutil.Mkdir(path.Join(mnt.Dir, PrivateName, "jdoe", "one"), 0755); err != nil { 953 t.Fatal(err) 954 } 955 if err := ioutil.Mkdir(path.Join(mnt.Dir, PrivateName, "jdoe", "two"), 0755); err != nil { 956 t.Fatal(err) 957 } 958 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "one", "old") 959 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "two", "new") 960 const input = "hello, world\n" 961 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 962 t.Fatal(err) 963 } 964 syncFilename(t, p1) 965 966 if err := ioutil.Rename(p1, p2); err != nil { 967 t.Fatal(err) 968 } 969 970 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe", "one"), map[string]fileInfoCheck{}) 971 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe", "two"), map[string]fileInfoCheck{ 972 "new": nil, 973 }) 974 975 buf, err := ioutil.ReadFile(p2) 976 if err != nil { 977 t.Errorf("read error: %v", err) 978 } 979 if g, e := string(buf), input; g != e { 980 t.Errorf("bad file contents: %q != %q", g, e) 981 } 982 983 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 984 t.Errorf("old name still exists: %v", err) 985 } 986 } 987 988 func TestRenameCrossFolder(t *testing.T) { 989 ctx := libcontext.BackgroundContextWithCancellationDelayer() 990 defer testCleanupDelayer(ctx, t) 991 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 992 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 993 mnt, _, cancelFn := makeFS(ctx, t, config) 994 defer mnt.Close() 995 defer cancelFn() 996 997 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "old") 998 p2 := path.Join(mnt.Dir, PrivateName, "wsmith,jdoe", "new") 999 const input = "hello, world\n" 1000 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 1001 t.Fatal(err) 1002 } 1003 syncFilename(t, p1) 1004 1005 err := ioutil.Rename(p1, p2) 1006 if err == nil { 1007 t.Fatalf("expected an error from rename: %v", err) 1008 } 1009 lerr, ok := errors.Cause(err).(*os.LinkError) 1010 if !ok { 1011 t.Fatalf("expected a LinkError from rename: %v", err) 1012 } 1013 if g, e := lerr.Op, "rename"; g != e { 1014 t.Errorf("wrong LinkError.Op: %q != %q", g, e) 1015 } 1016 if g, e := lerr.Old, p1; g != e { 1017 t.Errorf("wrong LinkError.Old: %q != %q", g, e) 1018 } 1019 if g, e := lerr.New, p2; g != e { 1020 t.Errorf("wrong LinkError.New: %q != %q", g, e) 1021 } 1022 if g, e := lerr.Err, syscall.EXDEV; g != e { 1023 t.Errorf("expected EXDEV: %T %v", lerr.Err, lerr.Err) 1024 } 1025 1026 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 1027 "old": nil, 1028 }) 1029 checkDir(t, path.Join(mnt.Dir, PrivateName, "wsmith,jdoe"), map[string]fileInfoCheck{}) 1030 1031 buf, err := ioutil.ReadFile(p1) 1032 if err != nil { 1033 t.Errorf("read error: %v", err) 1034 } 1035 if g, e := string(buf), input; g != e { 1036 t.Errorf("bad file contents: %q != %q", g, e) 1037 } 1038 1039 if _, err := ioutil.ReadFile(p2); !ioutil.IsNotExist(err) { 1040 t.Errorf("new name exists even on error: %v", err) 1041 } 1042 } 1043 1044 func TestWriteThenRename(t *testing.T) { 1045 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1046 defer testCleanupDelayer(ctx, t) 1047 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1048 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1049 mnt, _, cancelFn := makeFS(ctx, t, config) 1050 defer mnt.Close() 1051 defer cancelFn() 1052 1053 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "old") 1054 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "new") 1055 1056 f, err := os.Create(p1) 1057 if err != nil { 1058 t.Fatalf("cannot create file: %v", err) 1059 } 1060 defer syncAndClose(t, f) 1061 1062 // write to the file 1063 const input = "hello, world\n" 1064 if _, err := f.Write([]byte(input)); err != nil { 1065 t.Fatalf("cannot write: %v", err) 1066 } 1067 1068 // now rename the file while it's still open 1069 if err := ioutil.Rename(p1, p2); err != nil { 1070 t.Fatal(err) 1071 } 1072 1073 // check that the new path has the right length still 1074 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 1075 "new": func(fi os.FileInfo) error { 1076 return mustBeFileWithSize(fi, int64(len(input))) 1077 }, 1078 }) 1079 1080 // write again to the same file 1081 const input2 = "goodbye, world\n" 1082 if _, err := f.Write([]byte(input2)); err != nil { 1083 t.Fatalf("cannot write after rename: %v", err) 1084 } 1085 1086 buf, err := ioutil.ReadFile(p2) 1087 if err != nil { 1088 t.Errorf("read error: %v", err) 1089 } 1090 if g, e := string(buf), input+input2; g != e { 1091 t.Errorf("bad file contents: %q != %q", g, e) 1092 } 1093 1094 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 1095 t.Errorf("old name still exists: %v", err) 1096 } 1097 } 1098 1099 func TestWriteThenRenameCrossDir(t *testing.T) { 1100 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1101 defer testCleanupDelayer(ctx, t) 1102 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1103 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1104 mnt, _, cancelFn := makeFS(ctx, t, config) 1105 defer mnt.Close() 1106 defer cancelFn() 1107 1108 if err := ioutil.Mkdir(path.Join(mnt.Dir, PrivateName, "jdoe", "one"), 0755); err != nil { 1109 t.Fatal(err) 1110 } 1111 if err := ioutil.Mkdir(path.Join(mnt.Dir, PrivateName, "jdoe", "two"), 0755); err != nil { 1112 t.Fatal(err) 1113 } 1114 p1 := path.Join(mnt.Dir, PrivateName, "jdoe", "one", "old") 1115 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "two", "new") 1116 1117 f, err := os.Create(p1) 1118 if err != nil { 1119 t.Fatalf("cannot create file: %v", err) 1120 } 1121 defer syncAndClose(t, f) 1122 1123 // write to the file 1124 const input = "hello, world\n" 1125 if _, err := f.Write([]byte(input)); err != nil { 1126 t.Fatalf("cannot write: %v", err) 1127 } 1128 1129 // now rename the file while it's still open 1130 if err := ioutil.Rename(p1, p2); err != nil { 1131 t.Fatal(err) 1132 } 1133 1134 // check that the new path has the right length still 1135 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe", "two"), map[string]fileInfoCheck{ 1136 "new": func(fi os.FileInfo) error { 1137 return mustBeFileWithSize(fi, int64(len(input))) 1138 }, 1139 }) 1140 1141 // write again to the same file 1142 const input2 = "goodbye, world\n" 1143 if _, err := f.Write([]byte(input2)); err != nil { 1144 t.Fatalf("cannot write after rename: %v", err) 1145 } 1146 1147 buf, err := ioutil.ReadFile(p2) 1148 if err != nil { 1149 t.Errorf("read error: %v", err) 1150 } 1151 if g, e := string(buf), input+input2; g != e { 1152 t.Errorf("bad file contents: %q != %q", g, e) 1153 } 1154 1155 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 1156 t.Errorf("old name still exists: %v", err) 1157 } 1158 } 1159 1160 func TestRemoveFile(t *testing.T) { 1161 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1162 defer testCleanupDelayer(ctx, t) 1163 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1164 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1165 mnt, _, cancelFn := makeFS(ctx, t, config) 1166 defer mnt.Close() 1167 defer cancelFn() 1168 1169 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1170 const input = "hello, world\n" 1171 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1172 t.Fatal(err) 1173 } 1174 syncFilename(t, p) 1175 1176 if err := ioutil.Remove(p); err != nil { 1177 t.Fatal(err) 1178 } 1179 1180 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1181 1182 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1183 t.Errorf("file still exists: %v", err) 1184 } 1185 } 1186 1187 func TestRemoveTLF(t *testing.T) { 1188 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1189 defer testCleanupDelayer(ctx, t) 1190 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "pikachu") 1191 mnt, _, cancelFn := makeFS(ctx, t, config) 1192 defer mnt.Close() 1193 defer cancelFn() 1194 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1195 1196 p := path.Join(mnt.Dir, PrivateName, "jdoe,pikachu") 1197 f1, err := os.Create(path.Join(p, "f")) 1198 if err != nil { 1199 t.Fatal(err) 1200 } 1201 syncAndClose(t, f1) 1202 1203 privatePath := path.Join(mnt.Dir, PrivateName) 1204 checks := map[string]fileInfoCheck{ 1205 "jdoe": nil, 1206 } 1207 1208 var lastErr error 1209 for i := 0; i < 10; i++ { 1210 if err := syscall.Rmdir(p); err != nil { 1211 t.Fatal(err) 1212 } 1213 1214 if runtime.GOOS != "darwin" { 1215 checkDir(t, privatePath, checks) 1216 return 1217 } 1218 1219 // On OSX, the OS might decide to look up "f" at exactly the wrong 1220 // time, and reinstate the "jdoe,pikachu". Unfortunately there's 1221 // no good way to prevent this, so for now we just allow it to 1222 // happen and retry until we get what we want. See KBFS-1370. 1223 lastErr = checkDirNoTestError(t, privatePath, checks) 1224 if lastErr == nil { 1225 return 1226 } 1227 1228 // Make sure the test should still be running. 1229 select { 1230 case <-ctx.Done(): 1231 t.Fatal(ctx.Err()) 1232 default: 1233 t.Logf("Retrying TLF removal after error %+v", lastErr) 1234 } 1235 } 1236 if lastErr != nil { 1237 t.Error(lastErr) 1238 } 1239 } 1240 1241 func TestRemoveDir(t *testing.T) { 1242 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1243 defer testCleanupDelayer(ctx, t) 1244 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1245 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1246 mnt, _, cancelFn := makeFS(ctx, t, config) 1247 defer mnt.Close() 1248 defer cancelFn() 1249 1250 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1251 if err := ioutil.Mkdir(p, 0755); err != nil { 1252 t.Fatal(err) 1253 } 1254 1255 if err := syscall.Rmdir(p); err != nil { 1256 t.Fatal(err) 1257 } 1258 1259 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1260 1261 if _, err := ioutil.Stat(p); !ioutil.IsNotExist(err) { 1262 t.Errorf("file still exists: %v", err) 1263 } 1264 } 1265 1266 func TestRemoveDirNotEmpty(t *testing.T) { 1267 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1268 defer testCleanupDelayer(ctx, t) 1269 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1270 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1271 mnt, _, cancelFn := makeFS(ctx, t, config) 1272 defer mnt.Close() 1273 defer cancelFn() 1274 1275 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1276 if err := ioutil.Mkdir(p, 0755); err != nil { 1277 t.Fatal(err) 1278 } 1279 pFile := path.Join(p, "myfile") 1280 if err := ioutil.WriteFile(pFile, []byte("i'm important"), 0644); err != nil { 1281 t.Fatal(err) 1282 } 1283 syncFilename(t, pFile) 1284 1285 err := syscall.Rmdir(p) 1286 if g, e := err, syscall.ENOTEMPTY; g != e { 1287 t.Fatalf("wrong error from rmdir: %v (%T) != %v (%T)", g, g, e, e) 1288 } 1289 1290 if _, err := ioutil.ReadFile(pFile); err != nil { 1291 t.Errorf("file was lost: %v", err) 1292 } 1293 } 1294 1295 func TestRemoveFileWhileOpenSetEx(t *testing.T) { 1296 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1297 defer testCleanupDelayer(ctx, t) 1298 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1299 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1300 mnt, _, cancelFn := makeFS(ctx, t, config) 1301 defer mnt.Close() 1302 defer cancelFn() 1303 1304 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1305 f, err := os.Create(p) 1306 if err != nil { 1307 t.Fatalf("cannot create file: %v", err) 1308 } 1309 // Call in a closure since `f` is overridden below. 1310 defer func() { syncAndClose(t, f) }() 1311 1312 if err := ioutil.Remove(p); err != nil { 1313 t.Fatalf("cannot delete file: %v", err) 1314 } 1315 1316 // this must not resurrect a deleted file 1317 if err := f.Chmod(0755); err != nil { 1318 t.Fatalf("cannot setex: %v", err) 1319 } 1320 1321 // Make sure the mode sticks around even though the file was unlinked. 1322 fi, err := f.Stat() 1323 if err != nil { 1324 t.Fatal(err) 1325 } 1326 if g, e := fi.Mode().String(), `-rwx------`; g != e { 1327 t.Errorf("wrong mode: %q != %q", g, e) 1328 } 1329 syncAndClose(t, f) 1330 f = nil 1331 1332 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), 1333 map[string]fileInfoCheck{}) 1334 1335 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1336 t.Errorf("file still exists: %v", err) 1337 } 1338 } 1339 1340 func TestRemoveFileWhileOpenWritingInTLFRoot(t *testing.T) { 1341 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1342 defer testCleanupDelayer(ctx, t) 1343 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1344 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1345 mnt, _, cancelFn := makeFS(ctx, t, config) 1346 defer mnt.Close() 1347 defer cancelFn() 1348 1349 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1350 f, err := os.Create(p) 1351 if err != nil { 1352 t.Fatalf("cannot create file: %v", err) 1353 } 1354 // Call in a closure since `f` is overridden below. 1355 defer func() { syncAndClose(t, f) }() 1356 1357 if err := ioutil.Remove(p); err != nil { 1358 t.Fatalf("cannot delete file: %v", err) 1359 } 1360 1361 // this must not resurrect a deleted file 1362 const input = "hello, world\n" 1363 if _, err := f.Write([]byte(input)); err != nil { 1364 t.Fatalf("cannot write: %v", err) 1365 } 1366 syncAndClose(t, f) 1367 f = nil 1368 1369 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1370 1371 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1372 t.Errorf("file still exists: %v", err) 1373 } 1374 } 1375 1376 func TestRemoveFileWhileOpenWritingInSubDir(t *testing.T) { 1377 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1378 defer testCleanupDelayer(ctx, t) 1379 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1380 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1381 mnt, _, cancelFn := makeFS(ctx, t, config) 1382 defer mnt.Close() 1383 defer cancelFn() 1384 1385 dirPath := path.Join(mnt.Dir, PrivateName, "jdoe", "dir") 1386 if err := os.Mkdir(dirPath, 0700); err != nil { 1387 t.Fatal(err) 1388 } 1389 1390 p := path.Join(dirPath, "myfile") 1391 f, err := os.Create(p) 1392 if err != nil { 1393 t.Fatalf("cannot create file: %v", err) 1394 } 1395 // Call in a closure since `f` is overridden below. 1396 defer func() { syncAndClose(t, f) }() 1397 1398 if err := ioutil.Remove(p); err != nil { 1399 t.Fatalf("cannot delete file: %v", err) 1400 } 1401 1402 // this must not resurrect a deleted file 1403 const input = "hello, world\n" 1404 if _, err := f.Write([]byte(input)); err != nil { 1405 t.Fatalf("cannot write: %v", err) 1406 } 1407 syncAndClose(t, f) 1408 f = nil 1409 1410 checkDir(t, dirPath, map[string]fileInfoCheck{}) 1411 1412 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1413 t.Errorf("file still exists: %v", err) 1414 } 1415 } 1416 1417 func TestRenameOverFileWhileOpenWritingInDifferentDir(t *testing.T) { 1418 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1419 defer testCleanupDelayer(ctx, t) 1420 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1421 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1422 mnt, _, cancelFn := makeFS(ctx, t, config) 1423 defer mnt.Close() 1424 defer cancelFn() 1425 1426 dirPath := path.Join(mnt.Dir, PrivateName, "jdoe", "dir") 1427 if err := os.Mkdir(dirPath, 0700); err != nil { 1428 t.Fatal(err) 1429 } 1430 1431 p1 := path.Join(dirPath, "myfile") 1432 f1, err := os.Create(p1) 1433 if err != nil { 1434 t.Fatalf("cannot create file: %v", err) 1435 } 1436 // Call in a closure since `f1` is overridden below. 1437 defer func() { syncAndClose(t, f1) }() 1438 1439 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "mynewfile") 1440 f2, err := os.Create(p2) 1441 if err != nil { 1442 t.Fatalf("cannot create file: %v", err) 1443 } 1444 syncAndClose(t, f2) 1445 1446 if err := os.Rename(p2, p1); err != nil { 1447 t.Fatalf("cannot move file: %v", err) 1448 } 1449 1450 // this must not resurrect content in f2 1451 const input = "hello, world\n" 1452 if _, err := f1.Write([]byte(input)); err != nil { 1453 t.Fatalf("cannot write: %v", err) 1454 } 1455 syncAndClose(t, f1) 1456 f1 = nil 1457 1458 checkDir(t, dirPath, map[string]fileInfoCheck{"myfile": nil}) 1459 1460 content, err := ioutil.ReadFile(p1) 1461 if err != nil { 1462 t.Fatal(err) 1463 } 1464 if len(content) > 0 { 1465 t.Errorf("write to overwritee resulted in content in overwriter") 1466 } 1467 } 1468 1469 func TestRenameOverFileWhileOpenWritingInSameSubDir(t *testing.T) { 1470 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1471 defer testCleanupDelayer(ctx, t) 1472 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1473 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1474 mnt, _, cancelFn := makeFS(ctx, t, config) 1475 defer mnt.Close() 1476 defer cancelFn() 1477 1478 dirPath := path.Join(mnt.Dir, PrivateName, "jdoe", "dir") 1479 if err := os.Mkdir(dirPath, 0700); err != nil { 1480 t.Fatal(err) 1481 } 1482 1483 p1 := path.Join(dirPath, "myfile") 1484 f1, err := os.Create(p1) 1485 if err != nil { 1486 t.Fatalf("cannot create file: %v", err) 1487 } 1488 // Call in a closure since `f1` is overridden below. 1489 defer func() { syncAndClose(t, f1) }() 1490 1491 p2 := path.Join(dirPath, "mynewfile") 1492 f2, err := os.Create(p2) 1493 if err != nil { 1494 t.Fatalf("cannot create file: %v", err) 1495 } 1496 syncAndClose(t, f2) 1497 1498 if err := os.Rename(p2, p1); err != nil { 1499 t.Fatalf("cannot move file: %v", err) 1500 } 1501 1502 // this must not resurrect content in f2 1503 const input = "hello, world\n" 1504 if _, err := f1.Write([]byte(input)); err != nil { 1505 t.Fatalf("cannot write: %v", err) 1506 } 1507 syncAndClose(t, f1) 1508 f1 = nil 1509 1510 checkDir(t, dirPath, map[string]fileInfoCheck{"myfile": nil}) 1511 1512 content, err := ioutil.ReadFile(p1) 1513 if err != nil { 1514 t.Fatal(err) 1515 } 1516 if len(content) > 0 { 1517 t.Errorf("write to overwritee resulted in content in overwriter") 1518 } 1519 } 1520 1521 func TestRemoveFileWhileOpenReading(t *testing.T) { 1522 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1523 defer testCleanupDelayer(ctx, t) 1524 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1525 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1526 mnt, _, cancelFn := makeFS(ctx, t, config) 1527 defer mnt.Close() 1528 defer cancelFn() 1529 1530 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1531 const input = "hello, world\n" 1532 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1533 t.Fatal(err) 1534 } 1535 syncFilename(t, p) 1536 1537 f, err := os.Open(p) 1538 if err != nil { 1539 t.Fatalf("cannot open file: %v", err) 1540 } 1541 // Call in a closure since `f` is overridden below. 1542 defer func() { syncAndClose(t, f) }() 1543 1544 if err := ioutil.Remove(p); err != nil { 1545 t.Fatalf("cannot delete file: %v", err) 1546 } 1547 1548 buf, err := ioutil.ReadAll(f) 1549 if err != nil { 1550 t.Fatalf("cannot read unlinked file: %v", err) 1551 } 1552 if g, e := string(buf), input; g != e { 1553 t.Errorf("read wrong content: %q != %q", g, e) 1554 } 1555 1556 syncAndClose(t, f) 1557 f = nil 1558 1559 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1560 1561 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1562 t.Errorf("file still exists: %v", err) 1563 } 1564 } 1565 1566 func TestRemoveFileWhileOpenReadingAcrossMounts(t *testing.T) { 1567 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1568 defer testCleanupDelayer(ctx, t) 1569 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 1570 "user2") 1571 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 1572 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 1573 defer mnt1.Close() 1574 defer cancelFn1() 1575 1576 config2 := libkbfs.ConfigAsUser(config1, "user2") 1577 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 1578 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 1579 defer mnt2.Close() 1580 defer cancelFn2() 1581 1582 if !mnt2.Conn.Protocol().HasInvalidate() { 1583 t.Skip("Old FUSE protocol") 1584 } 1585 1586 p1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 1587 const input = "hello, world\n" 1588 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 1589 t.Fatal(err) 1590 } 1591 syncFilename(t, p1) 1592 1593 f, err := os.Open(p1) 1594 if err != nil { 1595 t.Fatalf("cannot open file: %v", err) 1596 } 1597 // Call in a closure since `f` is overridden below. 1598 defer func() { syncAndClose(t, f) }() 1599 1600 syncFolderToServer(t, "user1,user2", fs2) 1601 1602 p2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 1603 if err := ioutil.Remove(p2); err != nil { 1604 t.Fatalf("cannot delete file: %v", err) 1605 } 1606 syncAll(t, "user1,user2", tlf.Private, fs2) 1607 1608 syncFolderToServer(t, "user1,user2", fs1) 1609 1610 buf, err := ioutil.ReadAll(f) 1611 if err != nil { 1612 t.Fatalf("cannot read unlinked file: %v", err) 1613 } 1614 if g, e := string(buf), input; g != e { 1615 t.Errorf("read wrong content: %q != %q", g, e) 1616 } 1617 1618 syncAndClose(t, f) 1619 f = nil 1620 1621 checkDir(t, path.Join(mnt1.Dir, PrivateName, "user1,user2"), 1622 map[string]fileInfoCheck{}) 1623 1624 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 1625 t.Errorf("file still exists: %v", err) 1626 } 1627 } 1628 1629 func TestRenameOverFileWhileOpenReadingAcrossMounts(t *testing.T) { 1630 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1631 defer testCleanupDelayer(ctx, t) 1632 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 1633 "user2") 1634 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 1635 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 1636 defer mnt1.Close() 1637 defer cancelFn1() 1638 1639 config2 := libkbfs.ConfigAsUser(config1, "user2") 1640 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 1641 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 1642 defer mnt2.Close() 1643 defer cancelFn2() 1644 1645 if !mnt2.Conn.Protocol().HasInvalidate() { 1646 t.Skip("Old FUSE protocol") 1647 } 1648 1649 p1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 1650 const input = "hello, world\n" 1651 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 1652 t.Fatal(err) 1653 } 1654 syncFilename(t, p1) 1655 1656 p1Other := path.Join(mnt1.Dir, PrivateName, "user1,user2", "other") 1657 const inputOther = "hello, other\n" 1658 if err := ioutil.WriteFile(p1Other, []byte(inputOther), 0644); err != nil { 1659 t.Fatal(err) 1660 } 1661 syncFilename(t, p1Other) 1662 1663 f, err := os.Open(p1) 1664 if err != nil { 1665 t.Fatalf("cannot open file: %v", err) 1666 } 1667 // Call in a closure since `f` is overridden below. 1668 defer func() { syncAndClose(t, f) }() 1669 1670 syncFolderToServer(t, "user1,user2", fs2) 1671 1672 p2Other := path.Join(mnt2.Dir, PrivateName, "user1,user2", "other") 1673 p2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 1674 if err := ioutil.Rename(p2Other, p2); err != nil { 1675 t.Fatalf("cannot rename file: %v", err) 1676 } 1677 syncAll(t, "user1,user2", tlf.Private, fs2) 1678 1679 syncFolderToServer(t, "user1,user2", fs1) 1680 1681 buf, err := ioutil.ReadAll(f) 1682 if err != nil { 1683 t.Fatalf("cannot read unlinked file: %v", err) 1684 } 1685 if g, e := string(buf), input; g != e { 1686 t.Errorf("read wrong content: %q != %q", g, e) 1687 } 1688 1689 syncAndClose(t, f) 1690 f = nil 1691 1692 checkDir(t, path.Join(mnt1.Dir, PrivateName, "user1,user2"), 1693 map[string]fileInfoCheck{ 1694 "myfile": nil, 1695 }) 1696 1697 if _, err := ioutil.ReadFile(p1Other); !ioutil.IsNotExist(err) { 1698 t.Errorf("other file still exists: %v", err) 1699 } 1700 1701 buf, err = ioutil.ReadFile(p1) 1702 if err != nil { 1703 t.Errorf("read error: %v", err) 1704 } 1705 if g, e := string(buf), inputOther; g != e { 1706 t.Errorf("bad file contents: %q != %q", g, e) 1707 } 1708 } 1709 1710 func TestTruncateGrow(t *testing.T) { 1711 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1712 defer testCleanupDelayer(ctx, t) 1713 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1714 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1715 mnt, _, cancelFn := makeFS(ctx, t, config) 1716 defer mnt.Close() 1717 defer cancelFn() 1718 1719 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1720 const input = "hello, world\n" 1721 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1722 t.Fatal(err) 1723 } 1724 syncFilename(t, p) 1725 1726 const newSize = 100 1727 if err := os.Truncate(p, newSize); err != nil { 1728 t.Fatal(err) 1729 } 1730 syncFilename(t, p) 1731 1732 fi, err := ioutil.Lstat(p) 1733 if err != nil { 1734 t.Fatal(err) 1735 } 1736 if g, e := fi.Size(), int64(newSize); g != e { 1737 t.Errorf("wrong size: %v != %v", g, e) 1738 } 1739 1740 buf, err := ioutil.ReadFile(p) 1741 if err != nil { 1742 t.Fatalf("cannot read unlinked file: %v", err) 1743 } 1744 if g, e := string(buf), input+strings.Repeat("\x00", newSize-len(input)); g != e { 1745 t.Errorf("read wrong content: %q != %q", g, e) 1746 } 1747 } 1748 1749 func TestTruncateShrink(t *testing.T) { 1750 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1751 defer testCleanupDelayer(ctx, t) 1752 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1753 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1754 mnt, _, cancelFn := makeFS(ctx, t, config) 1755 defer mnt.Close() 1756 defer cancelFn() 1757 1758 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1759 const input = "hello, world\n" 1760 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1761 t.Fatal(err) 1762 } 1763 syncFilename(t, p) 1764 1765 const newSize = 4 1766 if err := os.Truncate(p, newSize); err != nil { 1767 t.Fatal(err) 1768 } 1769 syncFilename(t, p) 1770 1771 fi, err := ioutil.Lstat(p) 1772 if err != nil { 1773 t.Fatal(err) 1774 } 1775 if g, e := fi.Size(), int64(newSize); g != e { 1776 t.Errorf("wrong size: %v != %v", g, e) 1777 } 1778 1779 buf, err := ioutil.ReadFile(p) 1780 if err != nil { 1781 t.Fatalf("cannot read unlinked file: %v", err) 1782 } 1783 if g, e := string(buf), input[:newSize]; g != e { 1784 t.Errorf("read wrong content: %q != %q", g, e) 1785 } 1786 } 1787 1788 func TestChmodExec(t *testing.T) { 1789 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1790 defer testCleanupDelayer(ctx, t) 1791 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1792 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1793 mnt, _, cancelFn := makeFS(ctx, t, config) 1794 defer mnt.Close() 1795 defer cancelFn() 1796 1797 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1798 const input = "hello, world\n" 1799 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1800 t.Fatal(err) 1801 } 1802 syncFilename(t, p) 1803 1804 if err := os.Chmod(p, 0744); err != nil { 1805 t.Fatal(err) 1806 } 1807 1808 fi, err := ioutil.Lstat(p) 1809 if err != nil { 1810 t.Fatal(err) 1811 } 1812 if g, e := fi.Mode().String(), `-rwx------`; g != e { 1813 t.Errorf("wrong mode: %q != %q", g, e) 1814 } 1815 } 1816 1817 func TestChmodNonExec(t *testing.T) { 1818 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1819 defer testCleanupDelayer(ctx, t) 1820 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1821 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1822 mnt, _, cancelFn := makeFS(ctx, t, config) 1823 defer mnt.Close() 1824 defer cancelFn() 1825 1826 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1827 const input = "hello, world\n" 1828 if err := ioutil.WriteFile(p, []byte(input), 0755); err != nil { 1829 t.Fatal(err) 1830 } 1831 syncFilename(t, p) 1832 1833 if err := os.Chmod(p, 0655); err != nil { 1834 t.Fatal(err) 1835 } 1836 1837 fi, err := ioutil.Lstat(p) 1838 if err != nil { 1839 t.Fatal(err) 1840 } 1841 if g, e := fi.Mode().String(), `-rw-------`; g != e { 1842 t.Errorf("wrong mode: %q != %q", g, e) 1843 } 1844 } 1845 1846 func TestChownFileIgnored(t *testing.T) { 1847 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1848 defer testCleanupDelayer(ctx, t) 1849 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1850 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1851 mnt, _, cancelFn := makeFS(ctx, t, config) 1852 defer mnt.Close() 1853 defer cancelFn() 1854 1855 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1856 const input = "hello, world\n" 1857 if err := ioutil.WriteFile(p, []byte(input), 0755); err != nil { 1858 t.Fatal(err) 1859 } 1860 syncFilename(t, p) 1861 1862 fi, err := ioutil.Lstat(p) 1863 if err != nil { 1864 t.Fatal(err) 1865 } 1866 oldOwner := int(fi.Sys().(*syscall.Stat_t).Uid) 1867 1868 if err := os.Chown(p, oldOwner+1, oldOwner+1); err != nil { 1869 t.Fatalf("Expecting the file chown to get swallowed silently, "+ 1870 "but got: %v", err) 1871 } 1872 1873 newFi, err := ioutil.Lstat(p) 1874 if err != nil { 1875 t.Fatal(err) 1876 } 1877 newOwner := int(newFi.Sys().(*syscall.Stat_t).Uid) 1878 if oldOwner != newOwner { 1879 t.Fatalf("Owner changed unexpectedly to %d after a chown", newOwner) 1880 } 1881 } 1882 1883 func TestChmodDirIgnored(t *testing.T) { 1884 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1885 defer testCleanupDelayer(ctx, t) 1886 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1887 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1888 mnt, _, cancelFn := makeFS(ctx, t, config) 1889 defer mnt.Close() 1890 defer cancelFn() 1891 1892 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1893 if err := ioutil.Mkdir(p, 0755); err != nil { 1894 t.Fatal(err) 1895 } 1896 1897 if err := os.Chmod(p, 0655); err != nil { 1898 t.Fatalf("Expecting the dir chmod to get swallowed silently, "+ 1899 "but got: %v", err) 1900 } 1901 } 1902 1903 func TestChownDirIgnored(t *testing.T) { 1904 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1905 defer testCleanupDelayer(ctx, t) 1906 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1907 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1908 mnt, _, cancelFn := makeFS(ctx, t, config) 1909 defer mnt.Close() 1910 defer cancelFn() 1911 1912 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1913 if err := ioutil.Mkdir(p, 0755); err != nil { 1914 t.Fatal(err) 1915 } 1916 1917 fi, err := ioutil.Lstat(p) 1918 if err != nil { 1919 t.Fatal(err) 1920 } 1921 oldOwner := int(fi.Sys().(*syscall.Stat_t).Uid) 1922 1923 if err := os.Chown(p, 1, 1); err != nil { 1924 t.Fatalf("Expecting the dir chown to get swallowed silently, "+ 1925 "but got: %v", err) 1926 } 1927 1928 newFi, err := ioutil.Lstat(p) 1929 if err != nil { 1930 t.Fatal(err) 1931 } 1932 newOwner := int(newFi.Sys().(*syscall.Stat_t).Uid) 1933 if oldOwner != newOwner { 1934 t.Fatalf("Owner changed unexpectedly to %d after a chown", newOwner) 1935 } 1936 } 1937 1938 func TestSetattrFileMtime(t *testing.T) { 1939 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1940 defer testCleanupDelayer(ctx, t) 1941 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1942 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1943 mnt, _, cancelFn := makeFS(ctx, t, config) 1944 defer mnt.Close() 1945 defer cancelFn() 1946 1947 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1948 const input = "hello, world\n" 1949 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1950 t.Fatal(err) 1951 } 1952 syncFilename(t, p) 1953 1954 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 1955 // KBFS does not respect atime (which is ok), but we need to give 1956 // something to the syscall. 1957 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 1958 if err := os.Chtimes(p, atime, mtime); err != nil { 1959 t.Fatal(err) 1960 } 1961 1962 fi, err := ioutil.Lstat(p) 1963 if err != nil { 1964 t.Fatal(err) 1965 } 1966 if g, e := fi.ModTime(), mtime; !libfs.TimeEqual(g, e) { 1967 t.Errorf("wrong mtime: %v !~= %v", g, e) 1968 } 1969 } 1970 1971 func TestSetattrFileMtimeAfterWrite(t *testing.T) { 1972 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1973 defer testCleanupDelayer(ctx, t) 1974 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1975 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1976 mnt, _, cancelFn := makeFS(ctx, t, config) 1977 defer mnt.Close() 1978 defer cancelFn() 1979 1980 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1981 const input = "hello, world\n" 1982 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1983 t.Fatal(err) 1984 } 1985 syncFilename(t, p) 1986 1987 const input2 = "second round of content" 1988 { 1989 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1990 defer testCleanupDelayer(ctx, t) 1991 1992 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config, "jdoe", tlf.Private) 1993 1994 ops := config.KBFSOps() 1995 myfile, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName("myfile")) 1996 if err != nil { 1997 t.Fatal(err) 1998 } 1999 if err := ops.Write(ctx, myfile, []byte(input2), 0); err != nil { 2000 t.Fatal(err) 2001 } 2002 // Don't sync 2003 } 2004 2005 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 2006 // KBFS does not respect atime (which is ok), but we need to give 2007 // something to the syscall. 2008 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 2009 if err := os.Chtimes(p, atime, mtime); err != nil { 2010 t.Fatal(err) 2011 } 2012 2013 fi, err := ioutil.Lstat(p) 2014 if err != nil { 2015 t.Fatal(err) 2016 } 2017 if g, e := fi.ModTime(), mtime; !libfs.TimeEqual(g, e) { 2018 t.Errorf("wrong mtime: %v !~= %v", g, e) 2019 } 2020 syncFilename(t, p) 2021 } 2022 2023 func TestSetattrFileMtimeNow(t *testing.T) { 2024 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2025 defer testCleanupDelayer(ctx, t) 2026 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2027 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2028 mnt, _, cancelFn := makeFS(ctx, t, config) 2029 defer mnt.Close() 2030 defer cancelFn() 2031 2032 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2033 const input = "hello, world\n" 2034 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 2035 t.Fatal(err) 2036 } 2037 syncFilename(t, p) 2038 2039 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 2040 // KBFS does not respect atime (which is ok), but we need to give 2041 // something to the syscall. 2042 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 2043 if err := os.Chtimes(p, atime, mtime); err != nil { 2044 t.Fatal(err) 2045 } 2046 2047 // cause mtime to be set to now 2048 if err := unix.Utimes(p, nil); err != nil { 2049 t.Fatalf("touch failed: %v", err) 2050 } 2051 now := time.Now() 2052 2053 fi, err := ioutil.Lstat(p) 2054 if err != nil { 2055 t.Fatal(err) 2056 } 2057 if g, o := fi.ModTime(), mtime; !g.After(o) { 2058 t.Errorf("mtime did not progress: %v <= %v", g, o) 2059 } 2060 if g, e := fi.ModTime(), now; !timeEqualFuzzy(g, e, 1*time.Second) { 2061 t.Errorf("mtime is wrong: %v !~= %v", g, e) 2062 } 2063 } 2064 2065 func TestSetattrDirMtime(t *testing.T) { 2066 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2067 defer testCleanupDelayer(ctx, t) 2068 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2069 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2070 mnt, _, cancelFn := makeFS(ctx, t, config) 2071 defer mnt.Close() 2072 defer cancelFn() 2073 2074 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 2075 if err := ioutil.Mkdir(p, 0755); err != nil { 2076 t.Fatal(err) 2077 } 2078 2079 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 2080 // KBFS does not respect atime (which is ok), but we need to give 2081 // something to the syscall. 2082 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 2083 if err := os.Chtimes(p, atime, mtime); err != nil { 2084 t.Fatal(err) 2085 } 2086 2087 fi, err := ioutil.Lstat(p) 2088 if err != nil { 2089 t.Fatal(err) 2090 } 2091 if g, e := fi.ModTime(), mtime; !libfs.TimeEqual(g, e) { 2092 t.Errorf("wrong mtime: %v !~= %v", g, e) 2093 } 2094 } 2095 2096 func TestSetattrDirMtimeNow(t *testing.T) { 2097 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2098 defer testCleanupDelayer(ctx, t) 2099 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2100 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2101 mnt, _, cancelFn := makeFS(ctx, t, config) 2102 defer mnt.Close() 2103 defer cancelFn() 2104 2105 p := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 2106 if err := ioutil.Mkdir(p, 0755); err != nil { 2107 t.Fatal(err) 2108 } 2109 2110 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 2111 // KBFS does not respect atime (which is ok), but we need to give 2112 // something to the syscall. 2113 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 2114 if err := os.Chtimes(p, atime, mtime); err != nil { 2115 t.Fatal(err) 2116 } 2117 2118 // cause mtime to be set to now 2119 if err := unix.Utimes(p, nil); err != nil { 2120 t.Fatalf("touch failed: %v", err) 2121 } 2122 now := time.Now() 2123 2124 fi, err := ioutil.Lstat(p) 2125 if err != nil { 2126 t.Fatal(err) 2127 } 2128 if g, o := fi.ModTime(), mtime; !g.After(o) { 2129 t.Errorf("mtime did not progress: %v <= %v", g, o) 2130 } 2131 if g, e := fi.ModTime(), now; !timeEqualFuzzy(g, e, 1*time.Second) { 2132 t.Errorf("mtime is wrong: %v !~= %v", g, e) 2133 } 2134 } 2135 2136 func TestFsync(t *testing.T) { 2137 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2138 defer testCleanupDelayer(ctx, t) 2139 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2140 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2141 mnt, _, cancelFn := makeFS(ctx, t, config) 2142 defer mnt.Close() 2143 defer cancelFn() 2144 2145 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2146 f, err := os.Create(p) 2147 if err != nil { 2148 t.Fatal(err) 2149 } 2150 // Call in a closure since `f` is overridden below. 2151 defer func() { syncAndClose(t, f) }() 2152 const input = "hello, world\n" 2153 if _, err := io.WriteString(f, input); err != nil { 2154 t.Fatalf("write error: %v", err) 2155 } 2156 if err := f.Sync(); err != nil { 2157 t.Fatalf("fsync error: %v", err) 2158 } 2159 if err := f.Close(); err != nil { 2160 t.Fatalf("close error: %v", err) 2161 } 2162 f = nil 2163 } 2164 2165 func TestReaddirMyPublic(t *testing.T) { 2166 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2167 defer testCleanupDelayer(ctx, t) 2168 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2169 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2170 mnt, _, cancelFn := makeFS(ctx, t, config) 2171 defer mnt.Close() 2172 defer cancelFn() 2173 2174 files := map[string]fileInfoCheck{ 2175 "one": nil, 2176 "two": nil, 2177 } 2178 for filename := range files { 2179 p := path.Join(mnt.Dir, PublicName, "jdoe", filename) 2180 if err := ioutil.WriteFile( 2181 p, []byte("data for "+filename), 0644); err != nil { 2182 t.Fatal(err) 2183 } 2184 syncFilename(t, p) 2185 } 2186 2187 checkDir(t, path.Join(mnt.Dir, PublicName, "jdoe"), files) 2188 } 2189 2190 func TestReaddirOtherFolderAsReader(t *testing.T) { 2191 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2192 defer testCleanupDelayer(ctx, t) 2193 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2194 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2195 func() { 2196 mnt, _, cancelFn := makeFS(ctx, t, config) 2197 defer mnt.Close() 2198 defer cancelFn() 2199 2200 // cause the folder to exist 2201 p := path.Join(mnt.Dir, PrivateName, "jdoe#wsmith", "myfile") 2202 if err := ioutil.WriteFile( 2203 p, []byte("data for myfile"), 0644); err != nil { 2204 t.Fatal(err) 2205 } 2206 syncFilename(t, p) 2207 }() 2208 2209 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2210 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2211 mnt, _, cancelFn := makeFS(ctx, t, c2) 2212 defer mnt.Close() 2213 defer cancelFn() 2214 2215 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe#wsmith"), map[string]fileInfoCheck{ 2216 "myfile": nil, 2217 }) 2218 } 2219 2220 func TestReaddirMissingOtherFolderAsReader(t *testing.T) { 2221 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2222 defer testCleanupDelayer(ctx, t) 2223 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2224 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2225 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2226 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2227 mnt, _, cancelFn := makeFS(ctx, t, c2) 2228 defer mnt.Close() 2229 defer cancelFn() 2230 2231 // Check that folder that doesn't exist yet looks empty 2232 checkDir(t, path.Join(mnt.Dir, PrivateName, "jdoe#wsmith"), 2233 map[string]fileInfoCheck{}) 2234 } 2235 2236 func TestLookupMissingOtherFolderAsReader(t *testing.T) { 2237 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2238 defer testCleanupDelayer(ctx, t) 2239 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2240 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2241 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2242 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2243 mnt, _, cancelFn := makeFS(ctx, t, c2) 2244 defer mnt.Close() 2245 defer cancelFn() 2246 2247 p := path.Join(mnt.Dir, PrivateName, "jdoe#wsmith", "foo") 2248 if _, err := ioutil.Stat(p); !ioutil.IsNotExist(err) { 2249 t.Errorf("Expected ENOENT, but got: %v", err) 2250 } 2251 } 2252 2253 func TestStatOtherFolder(t *testing.T) { 2254 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2255 defer testCleanupDelayer(ctx, t) 2256 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2257 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2258 func() { 2259 mnt, _, cancelFn := makeFS(ctx, t, config) 2260 defer mnt.Close() 2261 defer cancelFn() 2262 2263 // cause the folder to exist 2264 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2265 if err := ioutil.WriteFile( 2266 p, []byte("data for myfile"), 0644); err != nil { 2267 t.Fatal(err) 2268 } 2269 syncFilename(t, p) 2270 }() 2271 2272 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2273 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2274 mnt, _, cancelFn := makeFS(ctx, t, c2) 2275 defer mnt.Close() 2276 defer cancelFn() 2277 2278 switch _, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 2279 case *os.PathError: 2280 if g, e := err.Err, syscall.EACCES; g != e { 2281 t.Fatalf("wrong error: %v != %v", g, e) 2282 } 2283 default: 2284 t.Fatalf("expected a PathError, got %T: %v", err, err) 2285 } 2286 } 2287 2288 func TestStatOtherFolderFirstUse(t *testing.T) { 2289 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2290 defer testCleanupDelayer(ctx, t) 2291 // This triggers a different error than with the warmup. 2292 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2293 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2294 2295 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2296 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2297 mnt, _, cancelFn := makeFS(ctx, t, c2) 2298 defer mnt.Close() 2299 defer cancelFn() 2300 2301 switch _, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 2302 case *os.PathError: 2303 if g, e := err.Err, syscall.EACCES; g != e { 2304 t.Fatalf("wrong error: %v != %v", g, e) 2305 } 2306 default: 2307 t.Fatalf("expected a PathError, got %T: %v", err, err) 2308 } 2309 } 2310 2311 func TestStatOtherFolderPublic(t *testing.T) { 2312 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2313 defer testCleanupDelayer(ctx, t) 2314 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2315 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2316 func() { 2317 mnt, _, cancelFn := makeFS(ctx, t, config) 2318 defer mnt.Close() 2319 defer cancelFn() 2320 2321 // cause the folder to exist 2322 p := path.Join(mnt.Dir, PublicName, "jdoe", "myfile") 2323 if err := ioutil.WriteFile( 2324 p, []byte("data for myfile"), 0644); err != nil { 2325 t.Fatal(err) 2326 } 2327 syncFilename(t, p) 2328 }() 2329 2330 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2331 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2332 mnt, _, cancelFn := makeFS(ctx, t, c2) 2333 defer mnt.Close() 2334 defer cancelFn() 2335 2336 fi, err := ioutil.Lstat(path.Join(mnt.Dir, PublicName, "jdoe")) 2337 if err != nil { 2338 t.Fatal(err) 2339 } 2340 // TODO figure out right modes, note owner is the person running 2341 // fuse, not the person owning the folder 2342 if g, e := fi.Mode().String(), `dr-x------`; g != e { 2343 t.Errorf("wrong mode for folder: %q != %q", g, e) 2344 } 2345 } 2346 2347 func TestReadPublicFile(t *testing.T) { 2348 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2349 defer testCleanupDelayer(ctx, t) 2350 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2351 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2352 const input = "hello, world\n" 2353 func() { 2354 mnt, _, cancelFn := makeFS(ctx, t, config) 2355 defer mnt.Close() 2356 defer cancelFn() 2357 2358 // cause the folder to exist 2359 p := path.Join(mnt.Dir, PublicName, "jdoe", "myfile") 2360 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 2361 t.Fatal(err) 2362 } 2363 syncFilename(t, p) 2364 }() 2365 2366 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2367 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2368 mnt, _, cancelFn := makeFS(ctx, t, c2) 2369 defer mnt.Close() 2370 defer cancelFn() 2371 2372 buf, err := ioutil.ReadFile(path.Join(mnt.Dir, PublicName, "jdoe", "myfile")) 2373 if err != nil { 2374 t.Fatal(err) 2375 } 2376 if g, e := string(buf), input; g != e { 2377 t.Errorf("bad file contents: %q != %q", g, e) 2378 } 2379 } 2380 2381 func TestReaddirOtherFolderPublicAsAnyone(t *testing.T) { 2382 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2383 defer testCleanupDelayer(ctx, t) 2384 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2385 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2386 func() { 2387 mnt, _, cancelFn := makeFS(ctx, t, config) 2388 defer mnt.Close() 2389 defer cancelFn() 2390 2391 // cause the folder to exist 2392 p := path.Join(mnt.Dir, PublicName, "jdoe", "myfile") 2393 if err := ioutil.WriteFile( 2394 p, []byte("data for myfile"), 0644); err != nil { 2395 t.Fatal(err) 2396 } 2397 syncFilename(t, p) 2398 }() 2399 2400 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2401 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2402 mnt, _, cancelFn := makeFS(ctx, t, c2) 2403 defer mnt.Close() 2404 defer cancelFn() 2405 2406 checkDir(t, path.Join(mnt.Dir, PublicName, "jdoe"), map[string]fileInfoCheck{ 2407 "myfile": nil, 2408 }) 2409 } 2410 2411 func TestReaddirMissingFolderPublicAsAnyone(t *testing.T) { 2412 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2413 defer testCleanupDelayer(ctx, t) 2414 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2415 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2416 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2417 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2418 mnt, _, cancelFn := makeFS(ctx, t, c2) 2419 defer mnt.Close() 2420 defer cancelFn() 2421 2422 // Make sure a public folder, not yet created by its writer, looks empty. 2423 checkDir(t, path.Join(mnt.Dir, PublicName, "jdoe"), 2424 map[string]fileInfoCheck{}) 2425 } 2426 2427 func TestReaddirOtherFolderAsAnyone(t *testing.T) { 2428 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2429 defer testCleanupDelayer(ctx, t) 2430 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2431 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2432 func() { 2433 mnt, _, cancelFn := makeFS(ctx, t, config) 2434 defer mnt.Close() 2435 defer cancelFn() 2436 2437 // cause the folder to exist 2438 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2439 if err := ioutil.WriteFile( 2440 p, []byte("data for myfile"), 0644); err != nil { 2441 t.Fatal(err) 2442 } 2443 syncFilename(t, p) 2444 }() 2445 2446 c2 := libkbfs.ConfigAsUser(config, "wsmith") 2447 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 2448 mnt, _, cancelFn := makeFS(ctx, t, c2) 2449 defer mnt.Close() 2450 defer cancelFn() 2451 2452 switch _, err := ioutil.ReadDir(path.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 2453 case *os.PathError: 2454 if g, e := err.Err, syscall.EACCES; g != e { 2455 t.Fatalf("wrong error: %v != %v", g, e) 2456 } 2457 default: 2458 t.Fatalf("expected a PathError, got %T: %v", err, err) 2459 } 2460 } 2461 2462 func syncFolderToServerHelper(t *testing.T, tlf string, ty tlf.Type, fs *FS) { 2463 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2464 defer testCleanupDelayer(ctx, t) 2465 root := libkbfs.GetRootNodeOrBust(ctx, t, fs.config, tlf, ty) 2466 err := fs.config.KBFSOps().SyncFromServer(ctx, 2467 root.GetFolderBranch(), nil) 2468 if err != nil { 2469 t.Fatalf("Couldn't sync from server: %v", err) 2470 } 2471 fs.NotificationGroupWait() 2472 } 2473 2474 func syncFolderToServer(t *testing.T, name string, fs *FS) { 2475 syncFolderToServerHelper(t, name, tlf.Private, fs) 2476 } 2477 2478 func syncPublicFolderToServer(t *testing.T, name string, fs *FS) { 2479 syncFolderToServerHelper(t, name, tlf.Public, fs) 2480 } 2481 2482 func TestInvalidateDataOnWrite(t *testing.T) { 2483 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2484 defer testCleanupDelayer(ctx, t) 2485 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2486 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2487 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2488 defer mnt1.Close() 2489 defer cancelFn1() 2490 config2 := libkbfs.ConfigAsUser(config, "jdoe") 2491 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2492 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 2493 defer mnt2.Close() 2494 defer cancelFn2() 2495 2496 if !mnt2.Conn.Protocol().HasInvalidate() { 2497 t.Skip("Old FUSE protocol") 2498 } 2499 2500 const input1 = "input round one" 2501 p := path.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 2502 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2503 t.Fatal(err) 2504 } 2505 syncFilename(t, p) 2506 2507 syncFolderToServer(t, "jdoe", fs2) 2508 2509 f, err := os.Open(path.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 2510 if err != nil { 2511 t.Fatal(err) 2512 } 2513 defer syncAndClose(t, f) 2514 2515 { 2516 buf := make([]byte, 4096) 2517 n, err := f.ReadAt(buf, 0) 2518 if err != nil && err != io.EOF { 2519 t.Fatal(err) 2520 } 2521 if g, e := string(buf[:n]), input1; g != e { 2522 t.Errorf("wrong content: %q != %q", g, e) 2523 } 2524 } 2525 2526 const input2 = "second round of content" 2527 if err := ioutil.WriteFile(p, []byte(input2), 0644); err != nil { 2528 t.Fatal(err) 2529 } 2530 syncFilename(t, p) 2531 2532 syncFolderToServer(t, "jdoe", fs2) 2533 2534 { 2535 buf := make([]byte, 4096) 2536 n, err := f.ReadAt(buf, 0) 2537 if err != nil && err != io.EOF { 2538 t.Fatal(err) 2539 } 2540 if g, e := string(buf[:n]), input2; g != e { 2541 t.Errorf("wrong content: %q != %q", g, e) 2542 } 2543 } 2544 } 2545 2546 func TestInvalidatePublicDataOnWrite(t *testing.T) { 2547 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2548 defer testCleanupDelayer(ctx, t) 2549 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2550 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2551 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2552 defer mnt1.Close() 2553 defer cancelFn1() 2554 config2 := libkbfs.ConfigAsUser(config, "jdoe") 2555 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2556 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 2557 defer mnt2.Close() 2558 defer cancelFn2() 2559 2560 if !mnt2.Conn.Protocol().HasInvalidate() { 2561 t.Skip("Old FUSE protocol") 2562 } 2563 2564 const input1 = "input round one" 2565 p := path.Join(mnt1.Dir, PublicName, "jdoe", "myfile") 2566 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2567 t.Fatal(err) 2568 } 2569 syncFilename(t, p) 2570 2571 syncPublicFolderToServer(t, "jdoe", fs2) 2572 2573 f, err := os.Open(path.Join(mnt2.Dir, PublicName, "jdoe", "myfile")) 2574 if err != nil { 2575 t.Fatal(err) 2576 } 2577 defer syncAndClose(t, f) 2578 2579 { 2580 buf := make([]byte, 4096) 2581 n, err := f.ReadAt(buf, 0) 2582 if err != nil && err != io.EOF { 2583 t.Fatal(err) 2584 } 2585 if g, e := string(buf[:n]), input1; g != e { 2586 t.Errorf("wrong content: %q != %q", g, e) 2587 } 2588 } 2589 2590 const input2 = "second round of content" 2591 if err := ioutil.WriteFile(p, []byte(input2), 0644); err != nil { 2592 t.Fatal(err) 2593 } 2594 syncFilename(t, p) 2595 2596 syncPublicFolderToServer(t, "jdoe", fs2) 2597 2598 { 2599 buf := make([]byte, 4096) 2600 n, err := f.ReadAt(buf, 0) 2601 if err != nil && err != io.EOF { 2602 t.Fatal(err) 2603 } 2604 if g, e := string(buf[:n]), input2; g != e { 2605 t.Errorf("wrong content: %q != %q", g, e) 2606 } 2607 } 2608 } 2609 2610 func TestInvalidateDataOnTruncate(t *testing.T) { 2611 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2612 defer testCleanupDelayer(ctx, t) 2613 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2614 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2615 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2616 defer mnt1.Close() 2617 defer cancelFn1() 2618 config2 := libkbfs.ConfigAsUser(config, "jdoe") 2619 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2620 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 2621 defer mnt2.Close() 2622 defer cancelFn2() 2623 2624 if !mnt2.Conn.Protocol().HasInvalidate() { 2625 t.Skip("Old FUSE protocol") 2626 } 2627 2628 const input1 = "input round one" 2629 p := path.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 2630 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2631 t.Fatal(err) 2632 } 2633 syncFilename(t, p) 2634 2635 syncFolderToServer(t, "jdoe", fs2) 2636 2637 f, err := os.Open(path.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 2638 if err != nil { 2639 t.Fatal(err) 2640 } 2641 defer syncAndClose(t, f) 2642 2643 { 2644 buf := make([]byte, 4096) 2645 n, err := f.ReadAt(buf, 0) 2646 if err != nil && err != io.EOF { 2647 t.Fatal(err) 2648 } 2649 if g, e := string(buf[:n]), input1; g != e { 2650 t.Errorf("wrong content: %q != %q", g, e) 2651 } 2652 } 2653 2654 const newSize = 3 2655 if err := os.Truncate(p, newSize); err != nil { 2656 t.Fatal(err) 2657 } 2658 syncFilename(t, p) 2659 2660 syncFolderToServer(t, "jdoe", fs2) 2661 2662 { 2663 buf := make([]byte, 4096) 2664 n, err := f.ReadAt(buf, 0) 2665 if err != nil && err != io.EOF { 2666 t.Fatal(err) 2667 } 2668 if g, e := string(buf[:n]), input1[:newSize]; g != e { 2669 t.Errorf("wrong content: %q != %q", g, e) 2670 } 2671 } 2672 } 2673 2674 func TestInvalidateDataOnLocalWrite(t *testing.T) { 2675 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2676 defer testCleanupDelayer(ctx, t) 2677 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2678 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2679 mnt, fs, cancelFn := makeFS(ctx, t, config) 2680 defer mnt.Close() 2681 defer cancelFn() 2682 2683 if !mnt.Conn.Protocol().HasInvalidate() { 2684 t.Skip("Old FUSE protocol") 2685 } 2686 2687 const input1 = "input round one" 2688 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2689 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2690 t.Fatal(err) 2691 } 2692 syncFilename(t, p) 2693 2694 f, err := os.Open(path.Join(mnt.Dir, PrivateName, "jdoe", "myfile")) 2695 if err != nil { 2696 t.Fatal(err) 2697 } 2698 defer syncAndClose(t, f) 2699 2700 { 2701 buf := make([]byte, 4096) 2702 n, err := f.ReadAt(buf, 0) 2703 if err != nil && err != io.EOF { 2704 t.Fatal(err) 2705 } 2706 if g, e := string(buf[:n]), input1; g != e { 2707 t.Errorf("wrong content: %q != %q", g, e) 2708 } 2709 } 2710 2711 const input2 = "second round of content" 2712 { 2713 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2714 defer testCleanupDelayer(ctx, t) 2715 2716 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config, "jdoe", tlf.Private) 2717 ops := config.KBFSOps() 2718 myfile, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName("myfile")) 2719 if err != nil { 2720 t.Fatal(err) 2721 } 2722 if err := ops.Write(ctx, myfile, []byte(input2), 0); err != nil { 2723 t.Fatal(err) 2724 } 2725 } 2726 2727 // The Write above is a local change, and thus we can just do a 2728 // local wait without syncing to the server. 2729 fs.NotificationGroupWait() 2730 2731 { 2732 buf := make([]byte, 4096) 2733 n, err := f.ReadAt(buf, 0) 2734 if err != nil && err != io.EOF { 2735 t.Fatal(err) 2736 } 2737 if g, e := string(buf[:n]), input2; g != e { 2738 t.Errorf("wrong content: %q != %q", g, e) 2739 } 2740 } 2741 } 2742 2743 func TestInvalidateEntryOnDelete(t *testing.T) { 2744 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2745 defer testCleanupDelayer(ctx, t) 2746 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2747 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2748 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2749 defer mnt1.Close() 2750 defer cancelFn1() 2751 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config) 2752 defer mnt2.Close() 2753 defer cancelFn2() 2754 2755 if !mnt2.Conn.Protocol().HasInvalidate() { 2756 t.Skip("Old FUSE protocol") 2757 } 2758 2759 const input1 = "input round one" 2760 p := path.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 2761 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2762 t.Fatal(err) 2763 } 2764 syncFilename(t, p) 2765 2766 syncFolderToServer(t, "jdoe", fs2) 2767 2768 buf, err := ioutil.ReadFile(path.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 2769 if err != nil { 2770 t.Fatal(err) 2771 } 2772 if g, e := string(buf), input1; g != e { 2773 t.Errorf("wrong content: %q != %q", g, e) 2774 } 2775 2776 if err := ioutil.Remove(path.Join(mnt1.Dir, PrivateName, "jdoe", "myfile")); err != nil { 2777 t.Fatal(err) 2778 } 2779 2780 syncFolderToServer(t, "jdoe", fs2) 2781 2782 if buf, err := ioutil.ReadFile(path.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")); !ioutil.IsNotExist(err) { 2783 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2784 } 2785 } 2786 2787 func testForErrorText(t *testing.T, path string, expectedErr error, 2788 fileType string) { 2789 buf, err := ioutil.ReadFile(path) 2790 if err != nil { 2791 t.Fatalf("Bad error reading %s error file: %v", path, err) 2792 } 2793 2794 var errors []libfs.JSONReportedError 2795 err = json.Unmarshal(buf, &errors) 2796 if err != nil { 2797 t.Fatalf("Couldn't unmarshal error file: %v. Full contents: %s", 2798 err, string(buf)) 2799 } 2800 2801 found := false 2802 for _, e := range errors { 2803 if e.Error == expectedErr.Error() { 2804 found = true 2805 break 2806 } 2807 } 2808 2809 if !found { 2810 t.Errorf("%s error file did not contain the error %s. "+ 2811 "Full contents: %s", fileType, expectedErr, buf) 2812 } 2813 } 2814 2815 func TestErrorFile(t *testing.T) { 2816 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2817 defer testCleanupDelayer(ctx, t) 2818 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2819 config.SetReporter(libkbfs.NewReporterSimple(config.Clock(), 0)) 2820 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2821 mnt, _, cancelFn := makeFS(ctx, t, config) 2822 defer mnt.Close() 2823 defer cancelFn() 2824 2825 libfs.AddRootWrapper(config) 2826 2827 // cause an error by stating a non-existent user 2828 _, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName, "janedoe")) 2829 if err == nil { 2830 t.Fatal("Stat of non-existent user worked!") 2831 } 2832 2833 // Make sure the root error file reads as expected 2834 expectedErr := fuse.ENOENT 2835 2836 // test both the root error file and one in a directory 2837 testForErrorText(t, path.Join(mnt.Dir, libfs.ErrorFileName), 2838 expectedErr, "root") 2839 testForErrorText(t, path.Join(mnt.Dir, PublicName, libfs.ErrorFileName), 2840 expectedErr, "root") 2841 testForErrorText(t, path.Join(mnt.Dir, PrivateName, libfs.ErrorFileName), 2842 expectedErr, "root") 2843 2844 // Create public and private jdoe TLFs. 2845 const b = "hello world" 2846 p := path.Join(mnt.Dir, PublicName, "jdoe", "myfile") 2847 if err := ioutil.WriteFile(p, []byte(b), 0644); err != nil { 2848 t.Fatal(err) 2849 } 2850 syncFilename(t, p) 2851 p = path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2852 if err := ioutil.WriteFile(p, []byte(b), 0644); err != nil { 2853 t.Fatal(err) 2854 } 2855 syncFilename(t, p) 2856 2857 testForErrorText( 2858 t, path.Join(mnt.Dir, PublicName, "jdoe", libfs.ErrorFileName), 2859 expectedErr, "dir") 2860 testForErrorText( 2861 t, path.Join(mnt.Dir, PrivateName, "jdoe", libfs.ErrorFileName), 2862 expectedErr, "dir") 2863 } 2864 2865 func TestInvalidateAcrossMounts(t *testing.T) { 2866 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2867 defer testCleanupDelayer(ctx, t) 2868 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2869 "user2") 2870 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2871 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2872 defer mnt1.Close() 2873 defer cancelFn1() 2874 2875 config2 := libkbfs.ConfigAsUser(config1, "user2") 2876 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2877 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 2878 defer mnt2.Close() 2879 defer cancelFn2() 2880 2881 if !mnt2.Conn.Protocol().HasInvalidate() { 2882 t.Skip("Old FUSE protocol") 2883 } 2884 2885 // user 1 writes one file to root and one to a sub directory 2886 const input1 = "input round one" 2887 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2888 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2889 t.Fatal(err) 2890 } 2891 syncFilename(t, myfile1) 2892 mydir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 2893 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 2894 t.Fatal(err) 2895 } 2896 mydira1 := path.Join(mydir1, "a") 2897 if err := ioutil.WriteFile(mydira1, []byte(input1), 0644); err != nil { 2898 t.Fatal(err) 2899 } 2900 syncFilename(t, mydira1) 2901 2902 syncFolderToServer(t, "user1,user2", fs2) 2903 2904 myfile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2905 buf, err := ioutil.ReadFile(myfile2) 2906 if err != nil { 2907 t.Fatal(err) 2908 } 2909 if g, e := string(buf), input1; g != e { 2910 t.Errorf("wrong content: %q != %q", g, e) 2911 } 2912 2913 mydir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir") 2914 mydira2 := path.Join(mydir2, "a") 2915 buf, err = ioutil.ReadFile(mydira2) 2916 if err != nil { 2917 t.Fatal(err) 2918 } 2919 if g, e := string(buf), input1; g != e { 2920 t.Errorf("wrong content: %q != %q", g, e) 2921 } 2922 2923 // now remove the first file, and rename the second 2924 if err := ioutil.Remove(myfile1); err != nil { 2925 t.Fatal(err) 2926 } 2927 mydirb1 := path.Join(mydir1, "b") 2928 if err := ioutil.Rename(mydira1, mydirb1); err != nil { 2929 t.Fatal(err) 2930 } 2931 syncAll(t, "user1,user2", tlf.Private, fs1) 2932 2933 syncFolderToServer(t, "user1,user2", fs2) 2934 2935 // check everything from user 2's perspective 2936 if buf, err := ioutil.ReadFile(myfile2); !ioutil.IsNotExist(err) { 2937 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2938 } 2939 if buf, err := ioutil.ReadFile(mydira2); !ioutil.IsNotExist(err) { 2940 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2941 } 2942 2943 checkDir(t, mydir2, map[string]fileInfoCheck{ 2944 "b": func(fi os.FileInfo) error { 2945 return mustBeFileWithSize(fi, int64(len(input1))) 2946 }, 2947 }) 2948 2949 mydirb2 := path.Join(mydir2, "b") 2950 buf, err = ioutil.ReadFile(mydirb2) 2951 if err != nil { 2952 t.Fatal(err) 2953 } 2954 if g, e := string(buf), input1; g != e { 2955 t.Errorf("wrong content: %q != %q", g, e) 2956 } 2957 } 2958 2959 func TestInvalidateAppendAcrossMounts(t *testing.T) { 2960 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2961 defer testCleanupDelayer(ctx, t) 2962 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2963 "user2") 2964 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2965 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 2966 defer mnt1.Close() 2967 defer cancelFn1() 2968 2969 config2 := libkbfs.ConfigAsUser(config1, "user2") 2970 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2971 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 2972 defer mnt2.Close() 2973 defer cancelFn2() 2974 2975 if !mnt2.Conn.Protocol().HasInvalidate() { 2976 t.Skip("Old FUSE protocol") 2977 } 2978 2979 // user 1 writes one file to root and one to a sub directory 2980 const input1 = "input round one" 2981 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2982 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2983 t.Fatal(err) 2984 } 2985 syncFilename(t, myfile1) 2986 syncFolderToServer(t, "user1,user2", fs2) 2987 myfile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2988 buf, err := ioutil.ReadFile(myfile2) 2989 if err != nil { 2990 t.Fatal(err) 2991 } 2992 if g, e := string(buf), input1; g != e { 2993 t.Errorf("wrong content: %q != %q", g, e) 2994 } 2995 2996 // user 1 append using libkbfs, to ensure that it doesn't flush 2997 // the whole page. 2998 const input2 = "input round two" 2999 { 3000 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3001 defer testCleanupDelayer(ctx, t) 3002 3003 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config1, "user1,user2", tlf.Private) 3004 3005 ops := config1.KBFSOps() 3006 myfile, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName("myfile")) 3007 if err != nil { 3008 t.Fatal(err) 3009 } 3010 if err := ops.Write( 3011 ctx, myfile, []byte(input2), int64(len(input1))); err != nil { 3012 t.Fatal(err) 3013 } 3014 if err := ops.SyncAll(ctx, myfile.GetFolderBranch()); err != nil { 3015 t.Fatal(err) 3016 } 3017 } 3018 3019 syncFolderToServer(t, "user1,user2", fs2) 3020 3021 // check everything from user 2's perspective 3022 buf, err = ioutil.ReadFile(myfile2) 3023 if err != nil { 3024 t.Fatal(err) 3025 } 3026 if g, e := string(buf), input1+input2; g != e { 3027 t.Errorf("wrong content: %q != %q", g, e) 3028 } 3029 } 3030 3031 func TestInvalidateRenameToUncachedDir(t *testing.T) { 3032 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3033 defer testCleanupDelayer(ctx, t) 3034 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 3035 "user2") 3036 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3037 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 3038 defer mnt1.Close() 3039 defer cancelFn1() 3040 3041 config2 := libkbfs.ConfigAsUser(config1, "user2") 3042 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3043 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3044 defer mnt2.Close() 3045 defer cancelFn2() 3046 3047 if !mnt2.Conn.Protocol().HasInvalidate() { 3048 t.Skip("Old FUSE protocol") 3049 } 3050 3051 // user 1 writes one file to root and one to a sub directory 3052 const input1 = "input round one" 3053 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 3054 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 3055 t.Fatal(err) 3056 } 3057 syncFilename(t, myfile1) 3058 mydir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 3059 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 3060 t.Fatal(err) 3061 } 3062 mydirfile1 := path.Join(mydir1, "myfile") 3063 3064 syncFolderToServer(t, "user1,user2", fs2) 3065 myfile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 3066 f, err := os.OpenFile(myfile2, os.O_RDWR, 0644) 3067 if err != nil { 3068 t.Fatal(err) 3069 } 3070 // Call in a closure since `f` is overridden below. 3071 defer func() { syncAndClose(t, f) }() 3072 3073 { 3074 buf := make([]byte, 4096) 3075 n, err := f.ReadAt(buf, 0) 3076 if err != nil && err != io.EOF { 3077 t.Fatal(err) 3078 } 3079 if g, e := string(buf[:n]), input1; g != e { 3080 t.Errorf("wrong content: %q != %q", g, e) 3081 } 3082 } 3083 3084 // now rename the second into a directory that user 2 hasn't seen 3085 if err := ioutil.Rename(myfile1, mydirfile1); err != nil { 3086 t.Fatal(err) 3087 } 3088 syncAll(t, "user1,user2", tlf.Private, fs1) 3089 3090 syncFolderToServer(t, "user1,user2", fs2) 3091 3092 // user 2 should be able to write to its open file, and user 1 3093 // will see the change 3094 const input2 = "input round two" 3095 { 3096 n, err := f.WriteAt([]byte(input2), 0) 3097 if err != nil || n != len(input2) { 3098 t.Fatal(err) 3099 } 3100 } 3101 syncAndClose(t, f) 3102 f = nil 3103 3104 syncFolderToServer(t, "user1,user2", fs1) 3105 3106 buf, err := ioutil.ReadFile(mydirfile1) 3107 if err != nil { 3108 t.Fatal(err) 3109 } 3110 if g, e := string(buf), input2; g != e { 3111 t.Errorf("wrong content: %q != %q", g, e) 3112 } 3113 } 3114 3115 func TestStatusFile(t *testing.T) { 3116 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3117 defer testCleanupDelayer(ctx, t) 3118 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 3119 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 3120 mnt, _, cancelFn := makeFS(ctx, t, config) 3121 defer mnt.Close() 3122 defer cancelFn() 3123 3124 libfs.AddRootWrapper(config) 3125 3126 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config, "jdoe", tlf.Public) 3127 mydir := path.Join(mnt.Dir, PublicName, "jdoe", "mydir") 3128 err := ioutil.Mkdir(mydir, 0755) 3129 require.NoError(t, err) 3130 3131 ops := config.KBFSOps() 3132 status, _, err := ops.FolderStatus(ctx, jdoe.GetFolderBranch()) 3133 require.NoError(t, err) 3134 3135 checkStatus := func(dir string) { 3136 // Simply make sure the status in the file matches what we'd 3137 // expect. Checking the exact content should be left for tests 3138 // within libkbfs. 3139 buf, err := ioutil.ReadFile(path.Join(dir, libfs.StatusFileName)) 3140 require.NoError(t, err) 3141 3142 var bufStatus libkbfs.FolderBranchStatus 3143 err = json.Unmarshal(buf, &bufStatus) 3144 require.NoError(t, err) 3145 3146 // Use a fuzzy check on the timestamps, since it could include 3147 // monotonic clock stuff. 3148 require.True(t, timeEqualFuzzy( 3149 status.LocalTimestamp, bufStatus.LocalTimestamp, time.Millisecond)) 3150 status.LocalTimestamp = bufStatus.LocalTimestamp 3151 3152 // It's safe to compare the path slices with DeepEqual since 3153 // they will all be null for this test (nothing is dirtied). 3154 require.True(t, reflect.DeepEqual(status, bufStatus)) 3155 } 3156 checkStatus(path.Join(mnt.Dir, PublicName, "jdoe")) 3157 checkStatus(mydir) 3158 } 3159 3160 // TODO: remove once we have automatic conflict resolution tests 3161 func TestUnstageFile(t *testing.T) { 3162 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3163 defer testCleanupDelayer(ctx, t) 3164 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 3165 "user2") 3166 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3167 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 3168 defer mnt1.Close() 3169 defer cancelFn1() 3170 3171 config2 := libkbfs.ConfigAsUser(config1, "user2") 3172 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3173 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3174 defer mnt2.Close() 3175 defer cancelFn2() 3176 3177 if !mnt2.Conn.Protocol().HasInvalidate() { 3178 t.Skip("Old FUSE protocol") 3179 } 3180 3181 // both users read the root dir first 3182 myroot1 := path.Join(mnt1.Dir, PrivateName, "user1,user2") 3183 myroot2 := path.Join(mnt2.Dir, PrivateName, "user1,user2") 3184 checkDir(t, myroot1, map[string]fileInfoCheck{}) 3185 checkDir(t, myroot2, map[string]fileInfoCheck{}) 3186 3187 // turn updates off for user 2 3188 rootNode2 := libkbfs.GetRootNodeOrBust(ctx, t, config2, "user1,user2", tlf.Private) 3189 _, err := libkbfs.DisableUpdatesForTesting(config2, 3190 rootNode2.GetFolderBranch()) 3191 if err != nil { 3192 t.Fatalf("Couldn't pause user 2 updates") 3193 } 3194 err = libkbfs.DisableCRForTesting(config2, rootNode2.GetFolderBranch()) 3195 if err != nil { 3196 t.Fatalf("Couldn't disable user 2 CR") 3197 } 3198 3199 // user1 writes a file and makes a few directories 3200 const input1 = "input round one" 3201 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 3202 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 3203 t.Fatal(err) 3204 } 3205 syncFilename(t, myfile1) 3206 mydir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 3207 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 3208 t.Fatal(err) 3209 } 3210 mysubdir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir", 3211 "mysubdir") 3212 if err := ioutil.Mkdir(mysubdir1, 0755); err != nil { 3213 t.Fatal(err) 3214 } 3215 syncAll(t, "user1,user2", tlf.Private, fs1) 3216 3217 // user2 does similar 3218 const input2 = "input round two" 3219 myfile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 3220 if err := ioutil.WriteFile(myfile2, []byte(input2), 0644); err != nil { 3221 t.Fatal(err) 3222 } 3223 syncFilename(t, myfile2) 3224 mydir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir") 3225 if err := ioutil.Mkdir(mydir2, 0755); err != nil { 3226 t.Fatal(err) 3227 } 3228 myothersubdir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir", 3229 "myothersubdir") 3230 if err := ioutil.Mkdir(myothersubdir2, 0755); err != nil { 3231 t.Fatal(err) 3232 } 3233 syncAll(t, "user1,user2", tlf.Private, fs2) 3234 3235 // verify that they don't see each other's files 3236 checkDir(t, mydir1, map[string]fileInfoCheck{ 3237 "mysubdir": mustBeDir, 3238 }) 3239 checkDir(t, mydir2, map[string]fileInfoCheck{ 3240 "myothersubdir": mustBeDir, 3241 }) 3242 3243 // now unstage user 2 and they should see the same stuff 3244 unstageFile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3245 libfs.UnstageFileName) 3246 if err := ioutil.WriteFile(unstageFile2, []byte{1}, 0222); err != nil { 3247 t.Fatal(err) 3248 } 3249 3250 syncFolderToServer(t, "user1,user2", fs2) 3251 3252 // They should see identical folders now 3253 checkDir(t, mydir1, map[string]fileInfoCheck{ 3254 "mysubdir": mustBeDir, 3255 }) 3256 checkDir(t, mydir2, map[string]fileInfoCheck{ 3257 "mysubdir": mustBeDir, 3258 }) 3259 3260 buf, err := ioutil.ReadFile(myfile1) 3261 if err != nil { 3262 t.Fatal(err) 3263 } 3264 if g, e := string(buf), input1; g != e { 3265 t.Errorf("wrong content: %q != %q", g, e) 3266 } 3267 buf, err = ioutil.ReadFile(myfile2) 3268 if err != nil { 3269 t.Fatal(err) 3270 } 3271 if g, e := string(buf), input1; g != e { 3272 t.Errorf("wrong content: %q != %q", g, e) 3273 } 3274 } 3275 3276 func TestSimpleCRNoConflict(t *testing.T) { 3277 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3278 defer testCleanupDelayer(ctx, t) 3279 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 3280 "user2") 3281 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 3282 defer mnt1.Close() 3283 defer cancelFn1() 3284 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3285 3286 config2 := libkbfs.ConfigAsUser(config1, "user2") 3287 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3288 defer mnt2.Close() 3289 defer cancelFn2() 3290 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3291 3292 if !mnt2.Conn.Protocol().HasInvalidate() { 3293 t.Skip("Old FUSE protocol") 3294 } 3295 3296 root1 := path.Join(mnt1.Dir, PrivateName, "user1,user2") 3297 root2 := path.Join(mnt2.Dir, PrivateName, "user1,user2") 3298 // Please create TLF here first 3299 d1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "D") 3300 d2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "E") 3301 if err := ioutil.Mkdir(d1, 0755); err != nil { 3302 t.Fatal("Mkdir failed") 3303 } 3304 syncAll(t, "user1,user2", tlf.Private, fs1) 3305 syncFolderToServer(t, "user1,user2", fs2) 3306 if err := ioutil.Mkdir(d2, 0755); err != nil { 3307 t.Fatal("Mkdir failed") 3308 } 3309 syncAll(t, "user1,user2", tlf.Private, fs2) 3310 syncFolderToServer(t, "user1,user2", fs1) 3311 3312 // disable updates for user 2 3313 disableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3314 libfs.DisableUpdatesFileName) 3315 if err := ioutil.WriteFile(disableUpdatesFile, 3316 []byte("off"), 0644); err != nil { 3317 t.Fatal(err) 3318 } 3319 3320 // user1 writes a file and makes a few directories 3321 const input1 = "input round one" 3322 file1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "file1") 3323 if err := ioutil.WriteFile(file1, []byte(input1), 0644); err != nil { 3324 t.Fatal(err) 3325 } 3326 syncFilename(t, file1) 3327 dir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "dir") 3328 if err := ioutil.Mkdir(dir1, 0755); err != nil { 3329 t.Fatal(err) 3330 } 3331 subdir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "dir", "subdir1") 3332 if err := ioutil.Mkdir(subdir1, 0755); err != nil { 3333 t.Fatal(err) 3334 } 3335 syncAll(t, "user1,user2", tlf.Private, fs1) 3336 3337 // user2 does similar 3338 const input2 = "input round two two two" 3339 file2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "file2") 3340 if err := ioutil.WriteFile(file2, []byte(input2), 0644); err != nil { 3341 t.Fatal(err) 3342 } 3343 syncFilename(t, file2) 3344 dir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "dir") 3345 if err := ioutil.Mkdir(dir2, 0755); err != nil { 3346 t.Fatal(err) 3347 } 3348 subdir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "dir", "subdir2") 3349 if err := ioutil.Mkdir(subdir2, 0755); err != nil { 3350 t.Fatal(err) 3351 } 3352 syncAll(t, "user1,user2", tlf.Private, fs2) 3353 3354 // verify that they don't see each other's files 3355 checkDir(t, root1, map[string]fileInfoCheck{ 3356 "file1": func(fi os.FileInfo) error { 3357 return mustBeFileWithSize(fi, int64(len(input1))) 3358 }, 3359 "dir": mustBeDir, 3360 "D": mustBeDir, 3361 "E": mustBeDir, 3362 }) 3363 checkDir(t, dir1, map[string]fileInfoCheck{ 3364 "subdir1": mustBeDir, 3365 }) 3366 checkDir(t, root2, map[string]fileInfoCheck{ 3367 "file2": func(fi os.FileInfo) error { 3368 return mustBeFileWithSize(fi, int64(len(input2))) 3369 }, 3370 "dir": mustBeDir, 3371 "D": mustBeDir, 3372 "E": mustBeDir, 3373 }) 3374 checkDir(t, dir2, map[string]fileInfoCheck{ 3375 "subdir2": mustBeDir, 3376 }) 3377 3378 // now re-enable user 2 updates and CR, and the merge should happen 3379 enableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3380 libfs.EnableUpdatesFileName) 3381 if err := ioutil.WriteFile(enableUpdatesFile, 3382 []byte("on"), 0644); err != nil { 3383 t.Fatal(err) 3384 } 3385 3386 syncFolderToServer(t, "user1,user2", fs2) 3387 syncFolderToServer(t, "user1,user2", fs1) 3388 3389 // They should see identical folders now (conflict-free merge) 3390 checkDir(t, root1, map[string]fileInfoCheck{ 3391 "file1": func(fi os.FileInfo) error { 3392 return mustBeFileWithSize(fi, int64(len(input1))) 3393 }, 3394 "file2": func(fi os.FileInfo) error { 3395 return mustBeFileWithSize(fi, int64(len(input2))) 3396 }, 3397 "dir": mustBeDir, 3398 "D": mustBeDir, 3399 "E": mustBeDir, 3400 }) 3401 checkDir(t, dir1, map[string]fileInfoCheck{ 3402 "subdir1": mustBeDir, 3403 "subdir2": mustBeDir, 3404 }) 3405 checkDir(t, root2, map[string]fileInfoCheck{ 3406 "file1": func(fi os.FileInfo) error { 3407 return mustBeFileWithSize(fi, int64(len(input1))) 3408 }, 3409 "file2": func(fi os.FileInfo) error { 3410 return mustBeFileWithSize(fi, int64(len(input2))) 3411 }, 3412 "dir": mustBeDir, 3413 "D": mustBeDir, 3414 "E": mustBeDir, 3415 }) 3416 checkDir(t, dir2, map[string]fileInfoCheck{ 3417 "subdir1": mustBeDir, 3418 "subdir2": mustBeDir, 3419 }) 3420 3421 buf, err := ioutil.ReadFile(file1) 3422 if err != nil { 3423 t.Fatal(err) 3424 } 3425 if g, e := string(buf), input1; g != e { 3426 t.Errorf("wrong content: %q != %q", g, e) 3427 } 3428 file2u1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "file2") 3429 buf, err = ioutil.ReadFile(file2u1) 3430 if err != nil { 3431 t.Fatal(err) 3432 } 3433 if g, e := string(buf), input2; g != e { 3434 t.Errorf("wrong content: %q != %q", g, e) 3435 } 3436 3437 file1u2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "file1") 3438 buf, err = ioutil.ReadFile(file1u2) 3439 if err != nil { 3440 t.Fatal(err) 3441 } 3442 if g, e := string(buf), input1; g != e { 3443 t.Errorf("wrong content: %q != %q", g, e) 3444 } 3445 buf, err = ioutil.ReadFile(file2) 3446 if err != nil { 3447 t.Fatal(err) 3448 } 3449 if g, e := string(buf), input2; g != e { 3450 t.Errorf("wrong content: %q != %q", g, e) 3451 } 3452 } 3453 3454 func TestSimpleCRConflictOnOpenFiles(t *testing.T) { 3455 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3456 defer testCleanupDelayer(ctx, t) 3457 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 3458 "user2") 3459 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 3460 defer mnt1.Close() 3461 defer cancelFn1() 3462 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3463 3464 config2 := libkbfs.ConfigAsUser(config1, "user2") 3465 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3466 defer mnt2.Close() 3467 defer cancelFn2() 3468 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3469 3470 if !mnt2.Conn.Protocol().HasInvalidate() { 3471 t.Skip("Old FUSE protocol") 3472 } 3473 3474 now := time.Now() 3475 var clock clocktest.TestClock 3476 clock.Set(now) 3477 config2.SetClock(&clock) 3478 3479 root1 := path.Join(mnt1.Dir, PrivateName, "user1,user2") 3480 root2 := path.Join(mnt2.Dir, PrivateName, "user1,user2") 3481 3482 // both users should mutate the dir first 3483 d1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "D") 3484 d2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "E") 3485 if err := ioutil.Mkdir(d1, 0755); err != nil { 3486 t.Fatal("Mkdir failed") 3487 } 3488 syncFolderToServer(t, "user1,user2", fs2) 3489 if err := ioutil.Mkdir(d2, 0755); err != nil { 3490 t.Fatal("Mkdir failed") 3491 } 3492 syncFolderToServer(t, "user1,user2", fs1) 3493 3494 // disable updates for user 2 3495 disableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3496 libfs.DisableUpdatesFileName) 3497 if err := ioutil.WriteFile(disableUpdatesFile, 3498 []byte("off"), 0644); err != nil { 3499 t.Fatal(err) 3500 } 3501 3502 // user1 creates and writes a file 3503 file1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "f") 3504 f1, err := os.Create(file1) 3505 if err != nil { 3506 t.Fatal(err) 3507 } 3508 defer syncAndClose(t, f1) 3509 3510 const input1 = "hello" 3511 { 3512 n, err := f1.WriteAt([]byte(input1), 0) 3513 if err != nil || n != len(input1) { 3514 t.Fatal(err) 3515 } 3516 if err := f1.Sync(); err != nil { 3517 t.Fatal(err) 3518 } 3519 } 3520 3521 // user2 creates and writes a file 3522 file2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "f") 3523 f2, err := os.Create(file2) 3524 if err != nil { 3525 t.Fatal(err) 3526 } 3527 defer syncAndClose(t, f2) 3528 3529 const input2 = "ohell" 3530 { 3531 n, err := f2.WriteAt([]byte(input2), 0) 3532 if err != nil || n != len(input2) { 3533 t.Fatal(err) 3534 } 3535 if err := f2.Sync(); err != nil { 3536 t.Fatal(err) 3537 } 3538 } 3539 3540 // now re-enable user 2 updates and CR, and the merge should happen 3541 enableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3542 libfs.EnableUpdatesFileName) 3543 if err := ioutil.WriteFile(enableUpdatesFile, 3544 []byte("on"), 0644); err != nil { 3545 t.Fatal(err) 3546 } 3547 3548 syncFolderToServer(t, "user1,user2", fs2) 3549 syncFolderToServer(t, "user1,user2", fs1) 3550 3551 // They should both be able to read their past writes. 3552 { 3553 buf := make([]byte, len(input1)) 3554 n, err := f1.ReadAt(buf, 0) 3555 if err != nil || n != len(input1) { 3556 t.Fatal(err) 3557 } 3558 if g, e := string(buf), input1; g != e { 3559 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3560 } 3561 } 3562 { 3563 buf := make([]byte, len(input2)) 3564 n, err := f2.ReadAt(buf, 0) 3565 if err != nil || n != len(input2) { 3566 t.Fatal(err) 3567 } 3568 if g, e := string(buf), input2; g != e { 3569 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3570 } 3571 } 3572 3573 // They should see the conflict. 3574 cre := libkbfs.WriterDeviceDateConflictRenamer{} 3575 checkDir(t, root1, map[string]fileInfoCheck{ 3576 "f": func(fi os.FileInfo) error { 3577 return mustBeFileWithSize(fi, int64(len(input1))) 3578 }, 3579 cre.ConflictRenameHelper(now, "user2", "dev1", "f"): func(fi os.FileInfo) error { 3580 return mustBeFileWithSize(fi, int64(len(input2))) 3581 }, 3582 "D": mustBeDir, 3583 "E": mustBeDir, 3584 }) 3585 checkDir(t, root2, map[string]fileInfoCheck{ 3586 "f": func(fi os.FileInfo) error { 3587 return mustBeFileWithSize(fi, int64(len(input1))) 3588 }, 3589 cre.ConflictRenameHelper(now, "user2", "dev1", "f"): func(fi os.FileInfo) error { 3590 return mustBeFileWithSize(fi, int64(len(input2))) 3591 }, 3592 "D": mustBeDir, 3593 "E": mustBeDir, 3594 }) 3595 3596 input3 := " world" 3597 { 3598 n, err := f1.WriteAt([]byte(input3), int64(len(input1))) 3599 if err != nil || n != len(input3) { 3600 t.Fatal(err) 3601 } 3602 if err := f1.Sync(); err != nil { 3603 t.Fatal(err) 3604 } 3605 } 3606 3607 syncFolderToServer(t, "user1,user2", fs2) 3608 3609 input4 := " dlrow" 3610 { 3611 n, err := f2.WriteAt([]byte(input4), int64(len(input2))) 3612 if err != nil || n != len(input4) { 3613 t.Fatal(err) 3614 } 3615 if err := f2.Sync(); err != nil { 3616 t.Fatal(err) 3617 } 3618 } 3619 3620 syncFolderToServer(t, "user1,user2", fs1) 3621 3622 buf, err := ioutil.ReadFile(file1) 3623 if err != nil { 3624 t.Fatal(err) 3625 } 3626 if g, e := string(buf), input1+input3; g != e { 3627 t.Errorf("wrong content: %q != %q", g, e) 3628 } 3629 buf, err = ioutil.ReadFile(file2) 3630 if err != nil { 3631 t.Fatal(err) 3632 } 3633 if g, e := string(buf), input1+input3; g != e { 3634 t.Errorf("wrong content: %q != %q", g, e) 3635 } 3636 3637 filec1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", cre.ConflictRenameHelper(now, "user2", "dev1", "f")) 3638 filec2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", cre.ConflictRenameHelper(now, "user2", "dev1", "f")) 3639 buf, err = ioutil.ReadFile(filec1) 3640 if err != nil { 3641 t.Fatal(err) 3642 } 3643 if g, e := string(buf), input2+input4; g != e { 3644 t.Errorf("wrong content: %q != %q", g, e) 3645 } 3646 buf, err = ioutil.ReadFile(filec2) 3647 if err != nil { 3648 t.Fatal(err) 3649 } 3650 if g, e := string(buf), input2+input4; g != e { 3651 t.Errorf("wrong content: %q != %q", g, e) 3652 } 3653 } 3654 3655 func TestSimpleCRConflictOnOpenMergedFile(t *testing.T) { 3656 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3657 defer testCleanupDelayer(ctx, t) 3658 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 3659 "user2") 3660 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 3661 defer mnt1.Close() 3662 defer cancelFn1() 3663 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3664 3665 config2 := libkbfs.ConfigAsUser(config1, "user2") 3666 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3667 defer mnt2.Close() 3668 defer cancelFn2() 3669 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3670 3671 if !mnt2.Conn.Protocol().HasInvalidate() { 3672 t.Skip("Old FUSE protocol") 3673 } 3674 3675 now := time.Now() 3676 var clock clocktest.TestClock 3677 clock.Set(now) 3678 config2.SetClock(&clock) 3679 3680 root1 := path.Join(mnt1.Dir, PrivateName, "user1,user2") 3681 root2 := path.Join(mnt2.Dir, PrivateName, "user1,user2") 3682 // both users should mutate the dir first 3683 d1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "D") 3684 d2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "E") 3685 if err := ioutil.Mkdir(d1, 0755); err != nil { 3686 t.Fatal("Mkdir failed") 3687 } 3688 syncFolderToServer(t, "user1,user2", fs2) 3689 if err := ioutil.Mkdir(d2, 0755); err != nil { 3690 t.Fatal("Mkdir failed") 3691 } 3692 syncFolderToServer(t, "user1,user2", fs1) 3693 3694 // disable updates for user 2 3695 disableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3696 libfs.DisableUpdatesFileName) 3697 if err := ioutil.WriteFile(disableUpdatesFile, 3698 []byte("off"), 0644); err != nil { 3699 t.Fatal(err) 3700 } 3701 3702 // user1 creates and writes a file 3703 file1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "f") 3704 f1, err := os.Create(file1) 3705 if err != nil { 3706 t.Fatal(err) 3707 } 3708 defer syncAndClose(t, f1) 3709 3710 const input1 = "hello" 3711 { 3712 n, err := f1.WriteAt([]byte(input1), 0) 3713 if err != nil || n != len(input1) { 3714 t.Fatal(err) 3715 } 3716 if err := f1.Sync(); err != nil { 3717 t.Fatal(err) 3718 } 3719 } 3720 3721 // user2 creates a directory and writes a file to it 3722 dir2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "f") 3723 if err := ioutil.Mkdir(dir2, 0755); err != nil { 3724 t.Fatal(err) 3725 } 3726 file2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "f", "foo") 3727 f2, err := os.Create(file2) 3728 if err != nil { 3729 t.Fatal(err) 3730 } 3731 defer syncAndClose(t, f2) 3732 3733 const input2 = "ohell" 3734 { 3735 n, err := f2.WriteAt([]byte(input2), 0) 3736 if err != nil || n != len(input2) { 3737 t.Fatal(err) 3738 } 3739 if err := f2.Sync(); err != nil { 3740 t.Fatal(err) 3741 } 3742 } 3743 3744 // now re-enable user 2 updates and CR, and the merge should happen 3745 enableUpdatesFile := path.Join(mnt2.Dir, PrivateName, "user1,user2", 3746 libfs.EnableUpdatesFileName) 3747 if err := ioutil.WriteFile(enableUpdatesFile, 3748 []byte("on"), 0644); err != nil { 3749 t.Fatal(err) 3750 } 3751 3752 syncFolderToServer(t, "user1,user2", fs2) 3753 syncFolderToServer(t, "user1,user2", fs1) 3754 3755 // They should both be able to read their past writes. 3756 { 3757 buf := make([]byte, len(input1)) 3758 n, err := f1.ReadAt(buf, 0) 3759 if err != nil || n != len(input1) { 3760 t.Fatal(err) 3761 } 3762 if g, e := string(buf), input1; g != e { 3763 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3764 } 3765 } 3766 { 3767 buf := make([]byte, len(input2)) 3768 n, err := f2.ReadAt(buf, 0) 3769 if err != nil || n != len(input2) { 3770 t.Fatal(err) 3771 } 3772 if g, e := string(buf), input2; g != e { 3773 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3774 } 3775 } 3776 3777 // They should see the conflict. 3778 cre := libkbfs.WriterDeviceDateConflictRenamer{} 3779 fcr := cre.ConflictRenameHelper(now, "user1", "dev1", "f") 3780 checkDir(t, root1, map[string]fileInfoCheck{ 3781 fcr: func(fi os.FileInfo) error { 3782 return mustBeFileWithSize(fi, int64(len(input1))) 3783 }, 3784 "f": mustBeDir, 3785 "D": mustBeDir, 3786 "E": mustBeDir, 3787 }) 3788 checkDir(t, root2, map[string]fileInfoCheck{ 3789 fcr: func(fi os.FileInfo) error { 3790 return mustBeFileWithSize(fi, int64(len(input1))) 3791 }, 3792 "f": mustBeDir, 3793 "D": mustBeDir, 3794 "E": mustBeDir, 3795 }) 3796 3797 input3 := " world" 3798 { 3799 n, err := f1.WriteAt([]byte(input3), int64(len(input1))) 3800 if err != nil || n != len(input3) { 3801 t.Fatal(err) 3802 } 3803 if err := f1.Sync(); err != nil { 3804 t.Fatal(err) 3805 } 3806 } 3807 3808 syncFolderToServer(t, "user1,user2", fs2) 3809 3810 input4 := " dlrow" 3811 { 3812 n, err := f2.WriteAt([]byte(input4), int64(len(input2))) 3813 if err != nil || n != len(input4) { 3814 t.Fatal(err) 3815 } 3816 if err := f2.Sync(); err != nil { 3817 t.Fatal(err) 3818 } 3819 } 3820 3821 syncFolderToServer(t, "user1,user2", fs1) 3822 3823 file2u1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "f", "foo") 3824 buf, err := ioutil.ReadFile(file2u1) 3825 if err != nil { 3826 t.Fatal(err) 3827 } 3828 if g, e := string(buf), input2+input4; g != e { 3829 t.Errorf("wrong content: %q != %q", g, e) 3830 } 3831 buf, err = ioutil.ReadFile(file2) 3832 if err != nil { 3833 t.Fatal(err) 3834 } 3835 if g, e := string(buf), input2+input4; g != e { 3836 t.Errorf("wrong content: %q != %q", g, e) 3837 } 3838 3839 filec1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", fcr) 3840 filec2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", fcr) 3841 buf, err = ioutil.ReadFile(filec1) 3842 if err != nil { 3843 t.Fatal(err) 3844 } 3845 if g, e := string(buf), input1+input3; g != e { 3846 t.Errorf("wrong content: %q != %q", g, e) 3847 } 3848 buf, err = ioutil.ReadFile(filec2) 3849 if err != nil { 3850 t.Fatal(err) 3851 } 3852 if g, e := string(buf), input1+input3; g != e { 3853 t.Errorf("wrong content: %q != %q", g, e) 3854 } 3855 } 3856 3857 func TestKbfsFileInfo(t *testing.T) { 3858 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3859 defer testCleanupDelayer(ctx, t) 3860 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", "user2") 3861 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 3862 defer mnt1.Close() 3863 defer cancelFn1() 3864 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3865 3866 config2 := libkbfs.ConfigAsUser(config1, "user2") 3867 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3868 defer mnt2.Close() 3869 defer cancelFn2() 3870 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3871 3872 // Turn off the prefetcher to avoid races when reading the file info file. 3873 ch := config2.BlockOps().TogglePrefetcher(false) 3874 select { 3875 case <-ch: 3876 case <-ctx.Done(): 3877 t.Fatal(ctx.Err()) 3878 } 3879 3880 mydir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 3881 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 3882 t.Fatal(err) 3883 } 3884 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir", "myfile") 3885 if err := ioutil.WriteFile(myfile1, []byte("foo"), 0644); err != nil { 3886 t.Fatal(err) 3887 } 3888 syncFilename(t, myfile1) 3889 syncFolderToServer(t, "user1,user2", fs2) 3890 fi2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir", libfs.FileInfoPrefix+"myfile") 3891 bs, err := ioutil.ReadFile(fi2) 3892 if err != nil { 3893 t.Fatal(err) 3894 } 3895 var dst libkbfs.NodeMetadata 3896 err = json.Unmarshal(bs, &dst) 3897 if err != nil { 3898 t.Fatal(err) 3899 } 3900 if dst.LastWriterUnverified != kbname.NormalizedUsername("user1") { 3901 t.Fatalf("Expected user1, %v raw %X", dst, bs) 3902 } 3903 } 3904 3905 func TestDirSyncAll(t *testing.T) { 3906 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3907 defer testCleanupDelayer(ctx, t) 3908 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", "user2") 3909 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 3910 defer mnt1.Close() 3911 defer cancelFn1() 3912 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3913 3914 config2 := libkbfs.ConfigAsUser(config1, "user2") 3915 mnt2, fs2, cancelFn2 := makeFS(ctx, t, config2) 3916 defer mnt2.Close() 3917 defer cancelFn2() 3918 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3919 3920 mydir1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 3921 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 3922 t.Fatal(err) 3923 } 3924 myfile1 := path.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir", "myfile") 3925 data := []byte("foo") 3926 if err := ioutil.WriteFile(myfile1, data, 0644); err != nil { 3927 t.Fatal(err) 3928 } 3929 3930 d, err := os.Open(mydir1) 3931 if err != nil { 3932 t.Fatal(err) 3933 } 3934 defer d.Close() 3935 err = d.Sync() 3936 if err != nil { 3937 t.Fatal(err) 3938 } 3939 3940 syncFolderToServer(t, "user1,user2", fs2) 3941 myfile2 := path.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir", "myfile") 3942 gotData, err := ioutil.ReadFile(myfile2) 3943 if err != nil { 3944 t.Fatal(err) 3945 } 3946 if !bytes.Equal(data, gotData) { 3947 t.Fatalf("Expected=%v, got=%v", data, gotData) 3948 } 3949 } 3950 3951 // Regression test for KBFS-2853. 3952 func TestInodes(t *testing.T) { 3953 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3954 defer testCleanupDelayer(ctx, t) 3955 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 3956 mnt, _, cancelFn := makeFS(ctx, t, config) 3957 defer mnt.Close() 3958 defer cancelFn() 3959 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 3960 3961 p := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 3962 if err := ioutil.WriteFile(p, []byte("fake binary"), 0755); err != nil { 3963 t.Fatal(err) 3964 } 3965 syncFilename(t, p) 3966 3967 getInode := func(p string) uint64 { 3968 fi, err := ioutil.Lstat(p) 3969 if err != nil { 3970 t.Fatal(err) 3971 } 3972 stat, ok := fi.Sys().(*syscall.Stat_t) 3973 if !ok { 3974 t.Fatalf("Not a syscall.Stat_t") 3975 } 3976 return stat.Ino 3977 } 3978 inode := getInode(p) 3979 3980 t.Log("Rename file and make sure inode hasn't changed.") 3981 p2 := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile2") 3982 if err := ioutil.Rename(p, p2); err != nil { 3983 t.Fatal(err) 3984 } 3985 syncFilename(t, p2) 3986 3987 inode2 := getInode(p2) 3988 if inode != inode2 { 3989 t.Fatalf("Inode changed after rename: %d vs %d", inode, inode2) 3990 } 3991 3992 t.Log("A new file with the previous name should get a new inode") 3993 3994 if err := ioutil.WriteFile(p, []byte("more fake data"), 0755); err != nil { 3995 t.Fatal(err) 3996 } 3997 syncFilename(t, p) 3998 3999 inode3 := getInode(p) 4000 if inode == inode3 { 4001 t.Fatal("New and old files have the same inode") 4002 } 4003 } 4004 4005 func TestHardLinkNotSupported(t *testing.T) { 4006 ctx := libcontext.BackgroundContextWithCancellationDelayer() 4007 defer testCleanupDelayer(ctx, t) 4008 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 4009 mnt, _, cancelFn := makeFS(ctx, t, config) 4010 defer mnt.Close() 4011 defer cancelFn() 4012 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 4013 4014 checkLinkErr := func(old, new string, checkPermErr bool) { 4015 err := os.Link(old, new) 4016 linkErr, ok := errors.Cause(err).(*os.LinkError) 4017 require.True(t, ok) 4018 if checkPermErr && runtime.GOOS == "darwin" { 4019 // On macOS, in directories without the write bit set like 4020 // /keybase and /keybase/private, the `Link` call gets an 4021 // `EPERM` error back from the `Access()` Fuse request, 4022 // and never even tries calling `Link()`. 4023 require.Equal(t, syscall.EPERM, linkErr.Err) 4024 } else { 4025 require.Equal(t, syscall.ENOTSUP, linkErr.Err) 4026 } 4027 } 4028 4029 t.Log("Test hardlink in root of TLF") 4030 old := path.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 4031 err := ioutil.WriteFile(old, []byte("hello"), 0755) 4032 require.NoError(t, err) 4033 syncFilename(t, old) 4034 new := path.Join(mnt.Dir, PrivateName, "jdoe", "hardlink") 4035 checkLinkErr(old, new, false) 4036 4037 t.Log("Test hardlink in subdir of TLF") 4038 mydir := path.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 4039 err = ioutil.Mkdir(mydir, 0755) 4040 require.NoError(t, err) 4041 old2 := path.Join(mydir, "myfile") 4042 err = ioutil.WriteFile(old2, []byte("hello"), 0755) 4043 require.NoError(t, err) 4044 syncFilename(t, old2) 4045 new2 := path.Join(mydir, "hardlink") 4046 checkLinkErr(old2, new2, false) 4047 4048 t.Log("Test hardlink in folder list") 4049 old3 := path.Join(mnt.Dir, PrivateName, ".kbfs_status") 4050 new3 := path.Join(mnt.Dir, PrivateName, "hardlink") 4051 checkLinkErr(old3, new3, true) 4052 4053 t.Log("Test hardlink in root") 4054 old4 := path.Join(mnt.Dir, ".kbfs_status") 4055 new4 := path.Join(mnt.Dir, "hardlink") 4056 checkLinkErr(old4, new4, true) 4057 } 4058 4059 func TestOpenFileCount(t *testing.T) { 4060 ctx := libcontext.BackgroundContextWithCancellationDelayer() 4061 defer testCleanupDelayer(ctx, t) 4062 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 4063 mnt, _, cancelFn := makeFS(ctx, t, config) 4064 defer mnt.Close() 4065 defer cancelFn() 4066 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 4067 4068 p := path.Join(mnt.Dir, libfs.OpenFileCountFileName) 4069 checkCount := func(expected int64) { 4070 f, err := os.Open(p) 4071 require.NoError(t, err) 4072 defer f.Close() 4073 4074 b, err := ioutil.ReadAll(f) 4075 require.NoError(t, err) 4076 4077 i, err := strconv.ParseInt(string(b), 10, 64) 4078 require.NoError(t, err) 4079 require.Equal(t, expected, i) 4080 } 4081 4082 checkCount(0) 4083 4084 _, err := ioutil.Lstat(path.Join(mnt.Dir, PrivateName)) 4085 require.NoError(t, err) 4086 checkCount(1) 4087 4088 _, err = ioutil.Lstat(path.Join(mnt.Dir, PublicName)) 4089 require.NoError(t, err) 4090 checkCount(2) 4091 4092 _, err = ioutil.Lstat(path.Join(mnt.Dir, PrivateName)) 4093 require.NoError(t, err) 4094 checkCount(2) 4095 4096 err = ioutil.Mkdir( 4097 path.Join(mnt.Dir, PrivateName, "jdoe", "d"), os.ModeDir) 4098 require.NoError(t, err) 4099 checkCount(4) 4100 } 4101 4102 func TestUpdateHistoryFile(t *testing.T) { 4103 ctx := libcontext.BackgroundContextWithCancellationDelayer() 4104 defer testCleanupDelayer(ctx, t) 4105 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 4106 mnt, _, cancelFn := makeFS(ctx, t, config) 4107 defer mnt.Close() 4108 defer cancelFn() 4109 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 4110 4111 libfs.AddRootWrapper(config) 4112 4113 t.Log("Make several revisions") 4114 p := path.Join(mnt.Dir, PrivateName, "jdoe") 4115 for i := 0; i < 10; i++ { 4116 file := path.Join(p, fmt.Sprintf("foo-%d", i)) 4117 f, err := os.Create(file) 4118 require.NoError(t, err) 4119 syncAndClose(t, f) 4120 } 4121 4122 t.Log("Read a revision range") 4123 histPrefix := path.Join(p, libfs.UpdateHistoryFileName) 4124 fRange, err := os.Open(histPrefix + ".3-5") 4125 require.NoError(t, err) 4126 defer fRange.Close() 4127 b, err := ioutil.ReadAll(fRange) 4128 require.NoError(t, err) 4129 var histRange libkbfs.TLFUpdateHistory 4130 err = json.Unmarshal(b, &histRange) 4131 require.NoError(t, err) 4132 require.Len(t, histRange.Updates, 3) 4133 4134 t.Log("Read a single revision") 4135 fSingle, err := os.Open(histPrefix + ".7") 4136 require.NoError(t, err) 4137 defer fSingle.Close() 4138 b, err = ioutil.ReadAll(fSingle) 4139 require.NoError(t, err) 4140 var histSingle libkbfs.TLFUpdateHistory 4141 err = json.Unmarshal(b, &histSingle) 4142 require.NoError(t, err) 4143 require.Len(t, histSingle.Updates, 1) 4144 4145 t.Log("Read the entire history") 4146 fAll, err := os.Open(histPrefix) 4147 require.NoError(t, err) 4148 defer fAll.Close() 4149 b, err = ioutil.ReadAll(fAll) 4150 require.NoError(t, err) 4151 var histAll libkbfs.TLFUpdateHistory 4152 err = json.Unmarshal(b, &histAll) 4153 require.NoError(t, err) 4154 require.Len(t, histAll.Updates, 11) 4155 }