github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libdokan/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 libdokan 9 10 import ( 11 "encoding/json" 12 "fmt" 13 "io" 14 "os" 15 "path/filepath" 16 "reflect" 17 "strings" 18 "sync" 19 "syscall" 20 "testing" 21 "time" 22 23 "github.com/keybase/client/go/kbfs/dokan" 24 "github.com/keybase/client/go/kbfs/ioutil" 25 "github.com/keybase/client/go/kbfs/libcontext" 26 "github.com/keybase/client/go/kbfs/libfs" 27 "github.com/keybase/client/go/kbfs/libkbfs" 28 "github.com/keybase/client/go/kbfs/test/clocktest" 29 "github.com/keybase/client/go/kbfs/tlf" 30 kbname "github.com/keybase/client/go/kbun" 31 "github.com/keybase/client/go/logger" 32 "github.com/pkg/errors" 33 "github.com/stretchr/testify/require" 34 "golang.org/x/net/context" 35 ) 36 37 type compatMount struct { 38 *dokan.MountHandle 39 } 40 41 func (c *compatMount) Close() { 42 c.MountHandle.Close() 43 getDriveLetterLock(c.Dir[0]).Unlock() 44 } 45 46 var driveLetterLocks ['Z' - 'A']sync.Mutex 47 48 func getDriveLetterLock(driveLetter byte) *sync.Mutex { 49 if driveLetter >= 'a' && driveLetter <= 'z' { 50 driveLetter -= 'a' - 'A' 51 } 52 if driveLetter >= 'A' && driveLetter <= 'Z' { 53 return &driveLetterLocks[driveLetter-'A'] 54 } 55 return nil 56 } 57 58 func makeFS(ctx context.Context, t testing.TB, config *libkbfs.ConfigLocal) ( 59 *compatMount, *FS, func()) { 60 return makeFSE(ctx, t, config, 'T') 61 } 62 63 func makeFSE(ctx context.Context, t testing.TB, config *libkbfs.ConfigLocal, 64 driveLetter byte) (*compatMount, *FS, func()) { 65 makeSuccess := false 66 lock := getDriveLetterLock(driveLetter) 67 lock.Lock() 68 defer func() { 69 if !makeSuccess { 70 lock.Unlock() 71 } else { 72 time.Sleep(5 * time.Second) 73 } 74 }() 75 76 ctx, cancelFn := context.WithCancel(ctx) 77 filesys, err := NewFS(ctx, config, logger.NewTestLogger(t)) 78 if err != nil { 79 t.Fatalf("NewFS failed: %q", err.Error()) 80 } 81 82 mnt, err := dokan.Mount(&dokan.Config{ 83 FileSystem: filesys, 84 Path: string([]byte{driveLetter, ':', '\\'}), 85 MountFlags: DefaultMountFlags, 86 }) 87 if err != nil { 88 t.Fatal(err) 89 } 90 // Caller will unlock lock via cm.Close(). 91 cm := &compatMount{MountHandle: mnt} 92 makeSuccess = true 93 return cm, filesys, func() { 94 cancelFn() 95 } 96 } 97 98 type fileInfoCheck func(fi os.FileInfo) error 99 100 func mustBeFileWithSize(fi os.FileInfo, size int64) error { 101 if fi.Size() != size { 102 return fmt.Errorf("Bad file size: %d", fi.Size()) 103 } 104 return nil 105 } 106 107 func mustBeDir(fi os.FileInfo) error { 108 if !fi.IsDir() { 109 return fmt.Errorf("not a directory: %v", fi) 110 } 111 return nil 112 } 113 114 func checkDir(t testing.TB, dir string, want map[string]fileInfoCheck) { 115 // make a copy of want, to be safe 116 { 117 tmp := make(map[string]fileInfoCheck, len(want)) 118 for k, v := range want { 119 tmp[k] = v 120 } 121 want = tmp 122 } 123 124 fis, err := ioutil.ReadDir(dir) 125 if err != nil { 126 t.Fatal(err) 127 } 128 for _, fi := range fis { 129 if check, ok := want[fi.Name()]; ok { 130 delete(want, fi.Name()) 131 if check != nil { 132 if err := check(fi); err != nil { 133 t.Errorf("check failed: %v: %v", fi.Name(), err) 134 } 135 } 136 continue 137 } 138 t.Errorf("unexpected direntry: %q size=%v mode=%v", fi.Name(), fi.Size(), fi.Mode()) 139 } 140 for filename := range want { 141 t.Errorf("never saw file: %v", filename) 142 } 143 } 144 145 // timeEqualFuzzy returns whether a is b+-skew. 146 func timeEqualFuzzy(a, b time.Time, skew time.Duration) bool { 147 b1 := b.Add(-skew) 148 b2 := b.Add(skew) 149 return !a.Before(b1) && !a.After(b2) 150 } 151 152 func testCleanupDelayer(ctx context.Context, t *testing.T) { 153 err := libcontext.CleanupCancellationDelayer(ctx) 154 require.NoError(t, err) 155 } 156 157 func TestStatRoot(t *testing.T) { 158 ctx := libcontext.BackgroundContextWithCancellationDelayer() 159 defer testCleanupDelayer(ctx, t) 160 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 161 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 162 mnt, _, cancelFn := makeFS(ctx, t, config) 163 defer mnt.Close() 164 defer cancelFn() 165 166 fi, err := ioutil.Lstat(mnt.Dir) 167 if err != nil { 168 t.Fatal(err) 169 } 170 if !fi.IsDir() { 171 t.Errorf("root.IsDir fails") 172 } 173 } 174 175 func TestStatPrivate(t *testing.T) { 176 ctx := libcontext.BackgroundContextWithCancellationDelayer() 177 defer testCleanupDelayer(ctx, t) 178 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 179 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 180 mnt, _, cancelFn := makeFS(ctx, t, config) 181 defer mnt.Close() 182 defer cancelFn() 183 184 fi, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName)) 185 if err != nil { 186 t.Fatal(err) 187 } 188 if !fi.IsDir() { 189 t.Errorf("IsDir failed for folder: %v", fi) 190 } 191 } 192 193 func TestStatPublic(t *testing.T) { 194 ctx := libcontext.BackgroundContextWithCancellationDelayer() 195 defer testCleanupDelayer(ctx, t) 196 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 197 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 198 mnt, _, cancelFn := makeFS(ctx, t, config) 199 defer mnt.Close() 200 defer cancelFn() 201 202 fi, err := ioutil.Lstat(filepath.Join(mnt.Dir, PublicName)) 203 if err != nil { 204 t.Fatal(err) 205 } 206 if !fi.IsDir() { 207 t.Errorf("IsDir failed for folder: %v", fi) 208 } 209 } 210 211 func TestStatMyFolder(t *testing.T) { 212 ctx := libcontext.BackgroundContextWithCancellationDelayer() 213 defer testCleanupDelayer(ctx, t) 214 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 215 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 216 mnt, _, cancelFn := makeFS(ctx, t, config) 217 defer mnt.Close() 218 defer cancelFn() 219 220 fi, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName, "jdoe")) 221 if err != nil { 222 t.Fatal(err) 223 } 224 if !fi.IsDir() { 225 t.Errorf("IsDir failed for folder: %v", fi) 226 } 227 } 228 229 func TestStatNonexistentFolder(t *testing.T) { 230 ctx := libcontext.BackgroundContextWithCancellationDelayer() 231 defer testCleanupDelayer(ctx, t) 232 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 233 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 234 mnt, _, cancelFn := makeFS(ctx, t, config) 235 defer mnt.Close() 236 defer cancelFn() 237 238 if _, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName, "does-not-exist")); !ioutil.IsNotExist(err) { 239 t.Fatalf("expected ENOENT: %v", err) 240 } 241 } 242 243 func TestStatAlias(t *testing.T) { 244 ctx := libcontext.BackgroundContextWithCancellationDelayer() 245 defer testCleanupDelayer(ctx, t) 246 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 247 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 248 mnt, _, cancelFn := makeFS(ctx, t, config) 249 defer mnt.Close() 250 defer cancelFn() 251 252 p := filepath.Join(mnt.Dir, PrivateName, "jdoe,jdoe") 253 fi, err := ioutil.Lstat(p) 254 if err != nil { 255 t.Fatal(err) 256 } 257 // FIXME go 1.12 changed symlink detection in ways that don't work with Dokan. 258 if g := fi.Mode().String(); g != `Lrw-rw-rw-` && g != `drwxrwxrwx` { 259 t.Errorf("wrong mode for alias : %q", g) 260 } 261 // TODO Readlink support. 262 /* 263 target, err := os.Readlink(p) 264 if err != nil { 265 t.Fatal(err) 266 } 267 if g, e := target, "jdoe"; g != e { 268 t.Errorf("wrong alias symlink target: %q != %q", g, e) 269 } 270 */ 271 } 272 273 func TestStatMyPublic(t *testing.T) { 274 ctx := libcontext.BackgroundContextWithCancellationDelayer() 275 defer testCleanupDelayer(ctx, t) 276 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 277 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 278 mnt, _, cancelFn := makeFS(ctx, t, config) 279 defer mnt.Close() 280 defer cancelFn() 281 282 fi, err := ioutil.Lstat(filepath.Join(mnt.Dir, PublicName, "jdoe")) 283 if err != nil { 284 t.Fatal(err) 285 } 286 if !fi.IsDir() { 287 t.Errorf("IsDir failed for folder: %v", fi) 288 } 289 } 290 291 func TestReaddirRoot(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 mnt, _, cancelFn := makeFS(ctx, t, config) 297 defer mnt.Close() 298 defer cancelFn() 299 300 checkDir(t, mnt.Dir, map[string]fileInfoCheck{ 301 PrivateName: mustBeDir, 302 PublicName: mustBeDir, 303 TeamName: mustBeDir, 304 }) 305 } 306 307 func TestReaddirPrivate(t *testing.T) { 308 ctx := libcontext.BackgroundContextWithCancellationDelayer() 309 defer testCleanupDelayer(ctx, t) 310 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 311 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 312 mnt, _, cancelFn := makeFS(ctx, t, config) 313 defer mnt.Close() 314 defer cancelFn() 315 316 { 317 ctx := libcontext.BackgroundContextWithCancellationDelayer() 318 319 defer testCleanupDelayer(ctx, t) 320 // Force FakeMDServer to have some TlfIDs it can present to us 321 // as favorites. Don't go through VFS to avoid caching causing 322 // false positives. 323 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 324 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 325 } 326 327 checkDir(t, filepath.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 328 "jdoe,janedoe": mustBeDir, 329 "jdoe": mustBeDir, // default home directory 330 }) 331 } 332 333 func TestReaddirPublic(t *testing.T) { 334 ctx := libcontext.BackgroundContextWithCancellationDelayer() 335 defer testCleanupDelayer(ctx, t) 336 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 337 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 338 mnt, _, cancelFn := makeFS(ctx, t, config) 339 defer mnt.Close() 340 defer cancelFn() 341 342 { 343 ctx := libcontext.BackgroundContextWithCancellationDelayer() 344 defer testCleanupDelayer(ctx, t) 345 // Force FakeMDServer to have some TlfIDs it can present to us 346 // as favorites. Don't go through VFS to avoid caching causing 347 // false positives. 348 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 349 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 350 } 351 352 checkDir(t, filepath.Join(mnt.Dir, PublicName), map[string]fileInfoCheck{ 353 "jdoe,janedoe": mustBeDir, 354 "jdoe": mustBeDir, // default personal public directory 355 }) 356 } 357 358 func TestReaddirMyFolderEmpty(t *testing.T) { 359 ctx := libcontext.BackgroundContextWithCancellationDelayer() 360 defer testCleanupDelayer(ctx, t) 361 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 362 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 363 mnt, _, cancelFn := makeFS(ctx, t, config) 364 defer mnt.Close() 365 defer cancelFn() 366 367 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 368 } 369 370 func syncAll(t *testing.T, tlf string, ty tlf.Type, fs *FS) { 371 // golang doesn't let us sync on a directory handle, so if we need 372 // to sync all without a file, go through libkbfs directly. 373 ctx := libcontext.BackgroundContextWithCancellationDelayer() 374 defer testCleanupDelayer(ctx, t) 375 root := libkbfs.GetRootNodeOrBust(ctx, t, fs.config, tlf, ty) 376 err := fs.config.KBFSOps().SyncAll(ctx, root.GetFolderBranch()) 377 if err != nil { 378 t.Fatalf("Couldn't sync all: %v", err) 379 } 380 } 381 382 func syncAndClose(t *testing.T, f *os.File) { 383 if f == nil { 384 return 385 } 386 err := f.Sync() 387 if err != nil { 388 t.Fatal(err) 389 } 390 f.Close() 391 } 392 393 func syncFilename(t *testing.T, name string) { 394 f, err := os.OpenFile(name, os.O_WRONLY, 0644) 395 if err != nil { 396 t.Fatal(err) 397 } 398 syncAndClose(t, f) 399 } 400 401 func TestReaddirMyFolderWithFiles(t *testing.T) { 402 ctx := libcontext.BackgroundContextWithCancellationDelayer() 403 defer testCleanupDelayer(ctx, t) 404 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 405 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 406 mnt, _, cancelFn := makeFS(ctx, t, config) 407 defer mnt.Close() 408 defer cancelFn() 409 410 files := map[string]fileInfoCheck{ 411 "one": nil, 412 "two": nil, 413 "foo‰5cbar": nil, 414 } 415 for filename, check := range files { 416 if check != nil { 417 // only set up the files 418 continue 419 } 420 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", filename) 421 if err := ioutil.WriteFile( 422 p, []byte("data for "+filename), 0644); err != nil { 423 t.Fatal(err) 424 } 425 syncFilename(t, p) 426 } 427 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), files) 428 } 429 430 func TestReaddirMyFolderWithSpecialCharactersInFileName(t *testing.T) { 431 ctx := libcontext.BackgroundContextWithCancellationDelayer() 432 defer testCleanupDelayer(ctx, t) 433 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 434 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 435 mnt, _, cancelFn := makeFS(ctx, t, config) 436 defer mnt.Close() 437 defer cancelFn() 438 439 windowsFilename := "foo‰5cbar" 440 kbfsFilename := `foo\bar` 441 442 // Create through dokan and check through dokan. 443 { 444 files := map[string]fileInfoCheck{ 445 windowsFilename: nil, 446 } 447 for filename, check := range files { 448 if check != nil { 449 // only set up the files 450 continue 451 } 452 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", filename) 453 if err := ioutil.WriteFile( 454 p, []byte("data for "+filename), 0644); err != nil { 455 t.Fatal(err) 456 } 457 syncFilename(t, p) 458 } 459 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), files) 460 } 461 462 // Check through KBFSOps 463 { 464 jdoe := libkbfs.GetRootNodeOrBust(ctx, 465 t, config, "jdoe", tlf.Private) 466 ops := config.KBFSOps() 467 _, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName(kbfsFilename)) 468 if err != nil { 469 t.Fatal(err) 470 } 471 } 472 } 473 474 func testOneCreateThenRead(t *testing.T, p string) { 475 f, err := os.Create(p) 476 if err != nil { 477 t.Fatal(err) 478 } 479 // Call in a closure since `f` is overridden below. 480 defer func() { syncAndClose(t, f) }() 481 const input = "hello, world\n" 482 if _, err := io.WriteString(f, input); err != nil { 483 t.Fatalf("write error: %v", err) 484 } 485 syncAndClose(t, f) 486 f = nil 487 488 buf, err := ioutil.ReadFile(p) 489 if err != nil { 490 t.Fatalf("read error: %v", err) 491 } 492 if g, e := string(buf), input; g != e { 493 t.Errorf("bad file contents: %q != %q", g, e) 494 } 495 } 496 497 func TestCreateThenRead(t *testing.T) { 498 ctx := libcontext.BackgroundContextWithCancellationDelayer() 499 defer testCleanupDelayer(ctx, t) 500 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 501 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 502 mnt, _, cancelFn := makeFS(ctx, t, config) 503 defer mnt.Close() 504 defer cancelFn() 505 506 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 507 testOneCreateThenRead(t, p) 508 } 509 510 // Tests that writing and reading multiple files works, implicitly 511 // exercising any block pointer reference counting code (since the 512 // initial created files will have identical empty blocks to start 513 // with). 514 func TestMultipleCreateThenRead(t *testing.T) { 515 ctx := libcontext.BackgroundContextWithCancellationDelayer() 516 defer testCleanupDelayer(ctx, t) 517 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 518 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 519 mnt, _, cancelFn := makeFS(ctx, t, config) 520 defer mnt.Close() 521 defer cancelFn() 522 523 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile1") 524 testOneCreateThenRead(t, p1) 525 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile2") 526 testOneCreateThenRead(t, p2) 527 } 528 529 func TestReadUnflushed(t *testing.T) { 530 ctx := libcontext.BackgroundContextWithCancellationDelayer() 531 defer testCleanupDelayer(ctx, t) 532 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 533 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 534 mnt, _, cancelFn := makeFS(ctx, t, config) 535 defer mnt.Close() 536 defer cancelFn() 537 538 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 539 f, err := os.Create(p) 540 if err != nil { 541 t.Fatal(err) 542 } 543 defer syncAndClose(t, f) 544 const input = "hello, world\n" 545 if _, err := io.WriteString(f, input); err != nil { 546 t.Fatalf("write error: %v", err) 547 } 548 // explicitly no close here 549 550 buf, err := ioutil.ReadFile(p) 551 if err != nil { 552 t.Fatalf("read error: %v", err) 553 } 554 if g, e := string(buf), input; g != e { 555 t.Errorf("bad file contents: %q != %q", g, e) 556 } 557 } 558 559 func TestMountAgain(t *testing.T) { 560 ctx := libcontext.BackgroundContextWithCancellationDelayer() 561 defer testCleanupDelayer(ctx, t) 562 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 563 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 564 565 const input = "hello, world\n" 566 const filename = "myfile" 567 func() { 568 mnt, _, cancelFn := makeFS(ctx, t, config) 569 defer mnt.Close() 570 defer cancelFn() 571 572 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", filename) 573 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 574 t.Fatal(err) 575 } 576 syncFilename(t, p) 577 }() 578 579 func() { 580 mnt, _, cancelFn := makeFS(ctx, t, config) 581 defer mnt.Close() 582 defer cancelFn() 583 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", filename) 584 buf, err := ioutil.ReadFile(p) 585 if err != nil { 586 t.Fatalf("read error: %v", err) 587 } 588 if g, e := string(buf), input; g != e { 589 t.Errorf("bad file contents: %q != %q", g, e) 590 } 591 }() 592 } 593 594 func TestMkdir(t *testing.T) { 595 ctx := libcontext.BackgroundContextWithCancellationDelayer() 596 defer testCleanupDelayer(ctx, t) 597 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 598 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 599 mnt, _, cancelFn := makeFS(ctx, t, config) 600 defer mnt.Close() 601 defer cancelFn() 602 603 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 604 if err := ioutil.Mkdir(p, 0755); err != nil { 605 t.Fatal(err) 606 } 607 fi, err := ioutil.Lstat(p) 608 if err != nil { 609 t.Fatal(err) 610 } 611 if g, e := fi.Mode().String(), `drwxrwxrwx`; g != e { 612 t.Errorf("wrong mode for subdir: %q != %q", g, e) 613 } 614 } 615 616 func TestMkdirNewFolder(t *testing.T) { 617 ctx := libcontext.BackgroundContextWithCancellationDelayer() 618 defer testCleanupDelayer(ctx, t) 619 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 620 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 621 mnt, _, cancelFn := makeFS(ctx, t, config) 622 defer mnt.Close() 623 defer cancelFn() 624 625 for _, q := range []string{"New Folder", "New folder"} { 626 p := filepath.Join(mnt.Dir, PrivateName, q) 627 _, err := ioutil.Lstat(p) 628 if err == nil { 629 t.Fatal("Non-existent new folder existed!") 630 } 631 if err = ioutil.Mkdir(p, 0755); err != nil { 632 t.Fatal(err) 633 } 634 fi, err := ioutil.Lstat(p) 635 if err != nil { 636 t.Fatal(err) 637 } 638 if g, err := fi.Mode().String(), `drwxrwxrwx`; g != err { 639 t.Errorf("wrong mode for subdir: %q != %q", g, err) 640 } 641 } 642 } 643 644 func TestMkdirAndCreateDeep(t *testing.T) { 645 ctx := libcontext.BackgroundContextWithCancellationDelayer() 646 defer testCleanupDelayer(ctx, t) 647 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 648 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 649 const input = "hello, world\n" 650 651 func() { 652 mnt, _, cancelFn := makeFS(ctx, t, config) 653 defer mnt.Close() 654 defer cancelFn() 655 656 one := filepath.Join(mnt.Dir, PrivateName, "jdoe", "one") 657 if err := ioutil.Mkdir(one, 0755); err != nil { 658 t.Fatal(err) 659 } 660 two := filepath.Join(one, "two") 661 if err := ioutil.Mkdir(two, 0755); err != nil { 662 t.Fatal(err) 663 } 664 three := filepath.Join(two, "three") 665 if err := ioutil.WriteFile(three, []byte(input), 0644); err != nil { 666 t.Fatal(err) 667 } 668 syncFilename(t, three) 669 }() 670 671 // unmount to flush cache 672 func() { 673 mnt, _, cancelFn := makeFS(ctx, t, config) 674 defer mnt.Close() 675 defer cancelFn() 676 677 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "one", "two", "three") 678 buf, err := ioutil.ReadFile(p) 679 if err != nil { 680 t.Fatalf("read error: %v", err) 681 } 682 if g, e := string(buf), input; g != e { 683 t.Errorf("bad file contents: %q != %q", g, e) 684 } 685 }() 686 } 687 688 func TestSymlink(t *testing.T) { 689 ctx := libcontext.BackgroundContextWithCancellationDelayer() 690 defer testCleanupDelayer(ctx, t) 691 t.Skip("Symlink creation not supported on Windows - TODO!") 692 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 693 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 694 695 func() { 696 mnt, _, cancelFn := makeFS(ctx, t, config) 697 defer mnt.Close() 698 defer cancelFn() 699 700 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mylink") 701 if err := os.Symlink("myfile", p); err != nil { 702 t.Fatal(err) 703 } 704 }() 705 706 // unmount to flush cache 707 func() { 708 mnt, _, cancelFn := makeFS(ctx, t, config) 709 defer mnt.Close() 710 defer cancelFn() 711 712 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mylink") 713 target, err := os.Readlink(p) 714 if err != nil { 715 t.Fatal(err) 716 } 717 if g, e := target, "myfile"; g != e { 718 t.Errorf("bad symlink target: %q != %q", g, e) 719 } 720 }() 721 } 722 723 func TestRename(t *testing.T) { 724 ctx := libcontext.BackgroundContextWithCancellationDelayer() 725 defer testCleanupDelayer(ctx, t) 726 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 727 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 728 mnt, _, cancelFn := makeFS(ctx, t, config) 729 defer mnt.Close() 730 defer cancelFn() 731 732 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "old") 733 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "new") 734 const input = "hello, world\n" 735 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 736 t.Fatal(err) 737 } 738 syncFilename(t, p1) 739 if err := ioutil.Rename(p1, p2); err != nil { 740 t.Fatal(err) 741 } 742 743 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 744 "new": func(fi os.FileInfo) error { 745 return mustBeFileWithSize(fi, int64(len(input))) 746 }, 747 }) 748 749 buf, err := ioutil.ReadFile(p2) 750 if err != nil { 751 t.Errorf("read error: %v", err) 752 } 753 if g, e := string(buf), input; g != e { 754 t.Errorf("bad file contents: %q != %q", g, e) 755 } 756 757 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 758 t.Errorf("old name still exists: %v", err) 759 } 760 } 761 762 func TestRenameOverwrite(t *testing.T) { 763 ctx := libcontext.BackgroundContextWithCancellationDelayer() 764 defer testCleanupDelayer(ctx, t) 765 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 766 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 767 mnt, _, cancelFn := makeFS(ctx, t, config) 768 defer mnt.Close() 769 defer cancelFn() 770 771 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "old") 772 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "new") 773 const input = "hello, world\n" 774 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 775 t.Fatal(err) 776 } 777 syncFilename(t, p1) 778 if err := ioutil.WriteFile(p2, []byte("loser\n"), 0644); err != nil { 779 t.Fatal(err) 780 } 781 syncFilename(t, p2) 782 783 if err := ioutil.Rename(p1, p2); err != nil { 784 t.Fatal(err) 785 } 786 787 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 788 "new": nil, 789 }) 790 791 buf, err := ioutil.ReadFile(p2) 792 if err != nil { 793 t.Errorf("read error: %v", err) 794 } 795 if g, e := string(buf), input; g != e { 796 t.Errorf("bad file contents: %q != %q", g, e) 797 } 798 799 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 800 t.Errorf("old name still exists: %v", err) 801 } 802 } 803 804 func TestRenameCrossDir(t *testing.T) { 805 ctx := libcontext.BackgroundContextWithCancellationDelayer() 806 defer testCleanupDelayer(ctx, t) 807 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 808 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 809 mnt, _, cancelFn := makeFS(ctx, t, config) 810 defer mnt.Close() 811 defer cancelFn() 812 813 if err := ioutil.Mkdir(filepath.Join(mnt.Dir, PrivateName, "jdoe", "one"), 0755); err != nil { 814 t.Fatal(err) 815 } 816 if err := ioutil.Mkdir(filepath.Join(mnt.Dir, PrivateName, "jdoe", "two"), 0755); err != nil { 817 t.Fatal(err) 818 } 819 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "one", "old") 820 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "two", "new") 821 const input = "hello, world\n" 822 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 823 t.Fatal(err) 824 } 825 syncFilename(t, p1) 826 827 if err := ioutil.Rename(p1, p2); err != nil { 828 t.Fatal(err) 829 } 830 831 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe", "one"), map[string]fileInfoCheck{}) 832 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe", "two"), map[string]fileInfoCheck{ 833 "new": nil, 834 }) 835 836 buf, err := ioutil.ReadFile(p2) 837 if err != nil { 838 t.Errorf("read error: %v", err) 839 } 840 if g, e := string(buf), input; g != e { 841 t.Errorf("bad file contents: %q != %q", g, e) 842 } 843 844 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 845 t.Errorf("old name still exists: %v", err) 846 } 847 } 848 849 func TestRenameCrossFolder(t *testing.T) { 850 ctx := libcontext.BackgroundContextWithCancellationDelayer() 851 defer testCleanupDelayer(ctx, t) 852 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 853 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 854 mnt, _, cancelFn := makeFS(ctx, t, config) 855 defer mnt.Close() 856 defer cancelFn() 857 858 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "old") 859 p2 := filepath.Join(mnt.Dir, PrivateName, "wsmith,jdoe", "new") 860 const input = "hello, world\n" 861 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 862 t.Fatal(err) 863 } 864 syncFilename(t, p1) 865 866 err := ioutil.Rename(p1, p2) 867 if err == nil { 868 t.Fatalf("expected an error from rename: %v", err) 869 } 870 lerr, ok := errors.Cause(err).(*os.LinkError) 871 if !ok { 872 t.Fatalf("expected a LinkError from rename: %v", err) 873 } 874 if g, e := lerr.Op, "rename"; g != e { 875 t.Errorf("wrong LinkError.Op: %q != %q", g, e) 876 } 877 if g, e := lerr.Old, p1; g != e { 878 t.Errorf("wrong LinkError.Old: %q != %q", g, e) 879 } 880 if g, e := lerr.New, p2; g != e { 881 t.Errorf("wrong LinkError.New: %q != %q", g, e) 882 } 883 884 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 885 "old": nil, 886 }) 887 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "wsmith,jdoe"), map[string]fileInfoCheck{}) 888 889 buf, err := ioutil.ReadFile(p1) 890 if err != nil { 891 t.Errorf("read error: %v", err) 892 } 893 if g, e := string(buf), input; g != e { 894 t.Errorf("bad file contents: %q != %q", g, e) 895 } 896 897 if _, err := ioutil.ReadFile(p2); !ioutil.IsNotExist(err) { 898 t.Errorf("new name exists even on error: %v", err) 899 } 900 } 901 902 func TestWriteThenRename(t *testing.T) { 903 ctx := libcontext.BackgroundContextWithCancellationDelayer() 904 defer testCleanupDelayer(ctx, t) 905 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 906 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 907 mnt, _, cancelFn := makeFS(ctx, t, config) 908 defer mnt.Close() 909 defer cancelFn() 910 911 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "old") 912 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "new") 913 914 f, err := Create(p1) 915 if err != nil { 916 t.Fatalf("cannot create file: %v", err) 917 } 918 defer syncAndClose(t, f) 919 920 // write to the file 921 const input = "hello, world\n" 922 if _, err := f.Write([]byte(input)); err != nil { 923 t.Fatalf("cannot write: %v", err) 924 } 925 926 // now rename the file while it's still open 927 if err := ioutil.Rename(p1, p2); err != nil { 928 t.Fatal(err) 929 } 930 931 // check that the new path has the right length still 932 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{ 933 "new": func(fi os.FileInfo) error { 934 return mustBeFileWithSize(fi, int64(len(input))) 935 }, 936 }) 937 938 // write again to the same file 939 const input2 = "goodbye, world\n" 940 if _, err := f.Write([]byte(input2)); err != nil { 941 t.Fatalf("cannot write after rename: %v", err) 942 } 943 944 buf, err := ioutil.ReadFile(p2) 945 if err != nil { 946 t.Errorf("read error: %v", err) 947 } 948 if g, e := string(buf), input+input2; g != e { 949 t.Errorf("bad file contents: %q != %q", g, e) 950 } 951 952 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 953 t.Errorf("old name still exists: %v", err) 954 } 955 956 } 957 958 func TestWriteThenRenameCrossDir(t *testing.T) { 959 ctx := libcontext.BackgroundContextWithCancellationDelayer() 960 defer testCleanupDelayer(ctx, t) 961 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 962 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 963 mnt, _, cancelFn := makeFS(ctx, t, config) 964 defer mnt.Close() 965 defer cancelFn() 966 967 if err := ioutil.Mkdir(filepath.Join(mnt.Dir, PrivateName, "jdoe", "one"), 0755); err != nil { 968 t.Fatal(err) 969 } 970 if err := ioutil.Mkdir(filepath.Join(mnt.Dir, PrivateName, "jdoe", "two"), 0755); err != nil { 971 t.Fatal(err) 972 } 973 p1 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "one", "old") 974 p2 := filepath.Join(mnt.Dir, PrivateName, "jdoe", "two", "new") 975 976 f, err := Create(p1) 977 if err != nil { 978 t.Fatalf("cannot create file: %v", err) 979 } 980 // Call in a closure since `f` is overridden below. 981 defer syncAndClose(t, f) 982 983 // write to the file 984 const input = "hello, world\n" 985 if _, err := f.Write([]byte(input)); err != nil { 986 t.Fatalf("cannot write: %v", err) 987 } 988 989 // now rename the file while it's still open 990 if err := ioutil.Rename(p1, p2); err != nil { 991 t.Fatal(err) 992 } 993 994 // check that the new path has the right length still 995 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe", "two"), map[string]fileInfoCheck{ 996 "new": func(fi os.FileInfo) error { 997 return mustBeFileWithSize(fi, int64(len(input))) 998 }, 999 }) 1000 1001 // write again to the same file 1002 const input2 = "goodbye, world\n" 1003 if _, err := f.Write([]byte(input2)); err != nil { 1004 t.Fatalf("cannot write after rename: %v", err) 1005 } 1006 1007 buf, err := ioutil.ReadFile(p2) 1008 if err != nil { 1009 t.Errorf("read error: %v", err) 1010 } 1011 if g, e := string(buf), input+input2; g != e { 1012 t.Errorf("bad file contents: %q != %q", g, e) 1013 } 1014 1015 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 1016 t.Errorf("old name still exists: %v", err) 1017 } 1018 1019 } 1020 1021 func TestRemoveFile(t *testing.T) { 1022 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1023 defer testCleanupDelayer(ctx, t) 1024 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1025 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1026 mnt, _, cancelFn := makeFS(ctx, t, config) 1027 defer mnt.Close() 1028 defer cancelFn() 1029 1030 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1031 const input = "hello, world\n" 1032 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1033 t.Fatal(err) 1034 } 1035 syncFilename(t, p) 1036 1037 if err := ioutil.Remove(p); err != nil { 1038 t.Fatal(err) 1039 } 1040 1041 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1042 1043 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1044 t.Errorf("file still exists: %v", err) 1045 } 1046 1047 } 1048 1049 func TestRemoveDir(t *testing.T) { 1050 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1051 defer testCleanupDelayer(ctx, t) 1052 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1053 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1054 mnt, _, cancelFn := makeFS(ctx, t, config) 1055 defer mnt.Close() 1056 defer cancelFn() 1057 1058 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1059 if err := ioutil.Mkdir(p, 0755); err != nil { 1060 t.Fatal(err) 1061 } 1062 1063 if err := syscall.Rmdir(p); err != nil { 1064 t.Fatal(err) 1065 } 1066 1067 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1068 1069 if _, err := ioutil.Stat(p); !ioutil.IsNotExist(err) { 1070 t.Errorf("file still exists: %v", err) 1071 } 1072 1073 } 1074 1075 func TestRemoveDirNotEmpty(t *testing.T) { 1076 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1077 defer testCleanupDelayer(ctx, t) 1078 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1079 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1080 mnt, _, cancelFn := makeFS(ctx, t, config) 1081 defer mnt.Close() 1082 defer cancelFn() 1083 1084 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1085 if err := ioutil.Mkdir(p, 0755); err != nil { 1086 t.Fatal(err) 1087 } 1088 pFile := filepath.Join(p, "myfile") 1089 if err := ioutil.WriteFile(pFile, []byte("i'm important"), 0644); err != nil { 1090 t.Fatal(err) 1091 } 1092 syncFilename(t, pFile) 1093 1094 err := syscall.Rmdir(p) 1095 if err == nil { 1096 t.Fatalf("no error from rmdir") 1097 } 1098 1099 if _, err := ioutil.ReadFile(pFile); err != nil { 1100 t.Errorf("file was lost: %v", err) 1101 } 1102 1103 } 1104 1105 func TestRemoveFileWhileOpenWriting(t *testing.T) { 1106 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1107 defer testCleanupDelayer(ctx, t) 1108 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1109 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1110 mnt, _, cancelFn := makeFS(ctx, t, config) 1111 defer mnt.Close() 1112 defer cancelFn() 1113 1114 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1115 f, err := Create(p) 1116 if err != nil { 1117 t.Fatalf("cannot create file: %v", err) 1118 } 1119 // Call in a closure since `f` is overridden below. 1120 defer func() { syncAndClose(t, f) }() 1121 1122 if err := ioutil.Remove(p); err != nil { 1123 t.Fatalf("cannot delete file: %v", err) 1124 } 1125 1126 // this must not resurrect a deleted file 1127 const input = "hello, world\n" 1128 if _, err := f.Write([]byte(input)); err != nil { 1129 t.Fatalf("cannot write: %v", err) 1130 } 1131 syncAndClose(t, f) 1132 f = nil 1133 1134 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe"), map[string]fileInfoCheck{}) 1135 1136 if _, err := ioutil.ReadFile(p); !ioutil.IsNotExist(err) { 1137 t.Errorf("file still exists: %v", err) 1138 } 1139 1140 } 1141 1142 func TestRemoveFileWhileOpenReading(t *testing.T) { 1143 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1144 defer testCleanupDelayer(ctx, t) 1145 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1146 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1147 mnt, _, cancelFn := makeFS(ctx, t, config) 1148 defer mnt.Close() 1149 defer cancelFn() 1150 1151 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1152 const input = "hello, world\n" 1153 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1154 t.Fatal(err) 1155 } 1156 syncFilename(t, p) 1157 1158 f, err := Open(p) 1159 if err != nil { 1160 t.Fatalf("cannot open file: %v", err) 1161 } 1162 defer f.Close() 1163 1164 if err := ioutil.Remove(p); err != nil { 1165 t.Fatalf("cannot delete file: %v", err) 1166 } 1167 1168 buf, err := ioutil.ReadAll(f) 1169 if err != nil { 1170 t.Fatalf("cannot read unlinked file: %v", err) 1171 } 1172 if g, e := string(buf), input; g != e { 1173 t.Errorf("read wrong content: %q != %q", g, e) 1174 } 1175 1176 if err := f.Close(); err != nil { 1177 t.Fatalf("error on close: %v", err) 1178 } 1179 1180 checkDir(t, filepath.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 1188 func TestRemoveFileWhileOpenReadingAcrossMounts(t *testing.T) { 1189 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1190 defer testCleanupDelayer(ctx, t) 1191 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 1192 "user2") 1193 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 1194 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 1195 defer mnt1.Close() 1196 defer cancelFn1() 1197 1198 config2 := libkbfs.ConfigAsUser(config1, "user2") 1199 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 1200 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 1201 defer mnt2.Close() 1202 defer cancelFn2() 1203 1204 p1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 1205 const input = "hello, world\n" 1206 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 1207 t.Fatal(err) 1208 } 1209 syncFilename(t, p1) 1210 1211 f, err := os.Open(p1) 1212 if err != nil { 1213 t.Fatalf("cannot open file: %v", err) 1214 } 1215 defer f.Close() 1216 1217 syncFolderToServer(t, "user1,user2", fs2) 1218 1219 p2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 1220 if err := ioutil.Remove(p2); err != nil { 1221 t.Fatalf("cannot delete file: %v", err) 1222 } 1223 syncAll(t, "user1,user2", tlf.Private, fs2) 1224 1225 syncFolderToServer(t, "user1,user2", fs1) 1226 1227 buf, err := ioutil.ReadAll(f) 1228 if err != nil { 1229 t.Fatalf("cannot read unlinked file: %v", err) 1230 } 1231 if g, e := string(buf), input; g != e { 1232 t.Errorf("read wrong content: %q != %q", g, e) 1233 } 1234 1235 if err := f.Close(); err != nil { 1236 t.Fatalf("error on close: %v", err) 1237 } 1238 1239 checkDir(t, filepath.Join(mnt1.Dir, PrivateName, "user1,user2"), 1240 map[string]fileInfoCheck{}) 1241 1242 if _, err := ioutil.ReadFile(p1); !ioutil.IsNotExist(err) { 1243 t.Errorf("file still exists: %v", err) 1244 } 1245 } 1246 1247 func TestRenameOverFileWhileOpenReadingAcrossMounts(t *testing.T) { 1248 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1249 defer testCleanupDelayer(ctx, t) 1250 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 1251 "user2") 1252 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 1253 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 1254 defer mnt1.Close() 1255 defer cancelFn1() 1256 1257 config2 := libkbfs.ConfigAsUser(config1, "user2") 1258 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 1259 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 1260 defer mnt2.Close() 1261 defer cancelFn2() 1262 1263 p1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 1264 const input = "hello, world\n" 1265 if err := ioutil.WriteFile(p1, []byte(input), 0644); err != nil { 1266 t.Fatal(err) 1267 } 1268 syncFilename(t, p1) 1269 1270 p1Other := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "other") 1271 const inputOther = "hello, other\n" 1272 if err := ioutil.WriteFile(p1Other, []byte(inputOther), 0644); err != nil { 1273 t.Fatal(err) 1274 } 1275 syncFilename(t, p1Other) 1276 1277 f, err := os.Open(p1) 1278 if err != nil { 1279 t.Fatalf("cannot open file: %v", err) 1280 } 1281 defer f.Close() 1282 1283 syncFolderToServer(t, "user1,user2", fs2) 1284 1285 p2Other := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "other") 1286 p2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 1287 if err := ioutil.Rename(p2Other, p2); err != nil { 1288 t.Fatalf("cannot rename file: %v", err) 1289 } 1290 syncAll(t, "user1,user2", tlf.Private, fs2) 1291 1292 syncFolderToServer(t, "user1,user2", fs1) 1293 1294 buf, err := ioutil.ReadAll(f) 1295 if err != nil { 1296 t.Fatalf("cannot read unlinked file: %v", err) 1297 } 1298 if g, e := string(buf), input; g != e { 1299 t.Errorf("read wrong content: %q != %q", g, e) 1300 } 1301 1302 if err := f.Close(); err != nil { 1303 t.Fatalf("error on close: %v", err) 1304 } 1305 1306 checkDir(t, filepath.Join(mnt1.Dir, PrivateName, "user1,user2"), 1307 map[string]fileInfoCheck{ 1308 "myfile": nil, 1309 }) 1310 1311 if _, err := ioutil.ReadFile(p1Other); !ioutil.IsNotExist(err) { 1312 t.Errorf("other file still exists: %v", err) 1313 } 1314 1315 buf, err = ioutil.ReadFile(p1) 1316 if err != nil { 1317 t.Errorf("read error: %v", err) 1318 } 1319 if g, e := string(buf), inputOther; g != e { 1320 t.Errorf("bad file contents: %q != %q", g, e) 1321 } 1322 } 1323 1324 func TestTruncateGrow(t *testing.T) { 1325 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1326 defer testCleanupDelayer(ctx, t) 1327 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1328 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1329 mnt, _, cancelFn := makeFS(ctx, t, config) 1330 defer mnt.Close() 1331 defer cancelFn() 1332 1333 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1334 const input = "hello, world\n" 1335 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1336 t.Fatal(err) 1337 } 1338 syncFilename(t, p) 1339 1340 const newSize = 100 1341 if err := os.Truncate(p, newSize); err != nil { 1342 t.Fatal(err) 1343 } 1344 syncFilename(t, p) 1345 1346 fi, err := ioutil.Lstat(p) 1347 if err != nil { 1348 t.Fatal(err) 1349 } 1350 if g, e := fi.Size(), int64(newSize); g != e { 1351 t.Errorf("wrong size: %v != %v", g, e) 1352 } 1353 1354 buf, err := ioutil.ReadFile(p) 1355 if err != nil { 1356 t.Fatalf("cannot read unlinked file: %v", err) 1357 } 1358 if g, e := string(buf), input+strings.Repeat("\x00", newSize-len(input)); g != e { 1359 t.Errorf("read wrong content: %q != %q", g, e) 1360 } 1361 1362 } 1363 1364 func TestTruncateShrink(t *testing.T) { 1365 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1366 defer testCleanupDelayer(ctx, t) 1367 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1368 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1369 mnt, _, cancelFn := makeFS(ctx, t, config) 1370 defer mnt.Close() 1371 defer cancelFn() 1372 1373 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1374 const input = "hello, world\n" 1375 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1376 t.Fatal(err) 1377 } 1378 syncFilename(t, p) 1379 1380 const newSize = 4 1381 if err := os.Truncate(p, newSize); err != nil { 1382 t.Fatal(err) 1383 } 1384 syncFilename(t, p) 1385 1386 fi, err := ioutil.Lstat(p) 1387 if err != nil { 1388 t.Fatal(err) 1389 } 1390 if g, e := fi.Size(), int64(newSize); g != e { 1391 t.Errorf("wrong size: %v != %v", g, e) 1392 } 1393 1394 buf, err := ioutil.ReadFile(p) 1395 if err != nil { 1396 t.Fatalf("cannot read unlinked file: %v", err) 1397 } 1398 if g, e := string(buf), input[:newSize]; g != e { 1399 t.Errorf("read wrong content: %q != %q", g, e) 1400 } 1401 1402 } 1403 1404 func TestSetattrFileMtime(t *testing.T) { 1405 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1406 defer testCleanupDelayer(ctx, t) 1407 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1408 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1409 mnt, _, cancelFn := makeFS(ctx, t, config) 1410 defer mnt.Close() 1411 defer cancelFn() 1412 1413 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1414 const input = "hello, world\n" 1415 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1416 t.Fatal(err) 1417 } 1418 syncFilename(t, p) 1419 1420 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 1421 // KBFS does not respect atime (which is ok), but we need to give 1422 // something to the syscall. 1423 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 1424 if err := os.Chtimes(p, atime, mtime); err != nil { 1425 t.Fatal(err) 1426 } 1427 1428 fi, err := ioutil.Lstat(p) 1429 if err != nil { 1430 t.Fatal(err) 1431 } 1432 // Fuzzy because the conversion between various time formats is lossy. 1433 if g, e := fi.ModTime(), mtime; !timeEqualFuzzy(g, e, time.Millisecond) { 1434 t.Errorf("wrong mtime: %v !~= %v", g, e) 1435 } 1436 1437 } 1438 1439 func TestSetattrFileMtimeNow(t *testing.T) { 1440 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1441 defer testCleanupDelayer(ctx, t) 1442 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1443 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1444 mnt, _, cancelFn := makeFS(ctx, t, config) 1445 defer mnt.Close() 1446 defer cancelFn() 1447 1448 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1449 const input = "hello, world\n" 1450 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1451 t.Fatal(err) 1452 } 1453 syncFilename(t, p) 1454 1455 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 1456 // KBFS does not respect atime (which is ok), but we need to give 1457 // something to the syscall. 1458 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 1459 if err := os.Chtimes(p, atime, mtime); err != nil { 1460 t.Fatal(err) 1461 } 1462 1463 // cause mtime to be set to now 1464 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1465 t.Fatal(err) 1466 } 1467 syncFilename(t, p) 1468 now := time.Now() 1469 1470 fi, err := ioutil.Lstat(p) 1471 if err != nil { 1472 t.Fatal(err) 1473 } 1474 if g, o := fi.ModTime(), mtime; !g.After(o) { 1475 t.Errorf("mtime did not progress: %v <= %v", g, o) 1476 } 1477 if g, e := fi.ModTime(), now; !timeEqualFuzzy(g, e, 1*time.Second) { 1478 t.Errorf("mtime is wrong: %v !~= %v", g, e) 1479 } 1480 1481 } 1482 1483 func TestSetattrDirMtime(t *testing.T) { 1484 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1485 defer testCleanupDelayer(ctx, t) 1486 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1487 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1488 mnt, _, cancelFn := makeFS(ctx, t, config) 1489 defer mnt.Close() 1490 defer cancelFn() 1491 1492 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1493 if err := ioutil.Mkdir(p, 0755); err != nil { 1494 t.Fatal(err) 1495 } 1496 1497 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 1498 // KBFS does not respect atime (which is ok), but we need to give 1499 // something to the syscall. 1500 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 1501 if err := os.Chtimes(p, atime, mtime); err != nil { 1502 t.Fatal(err) 1503 } 1504 1505 fi, err := ioutil.Lstat(p) 1506 if err != nil { 1507 t.Fatal(err) 1508 } 1509 // Fuzzy because the conversion between various time formats is lossy. 1510 if g, e := fi.ModTime(), mtime; !timeEqualFuzzy(g, e, time.Millisecond) { 1511 t.Errorf("wrong mtime: %v !~= %v", g, e) 1512 } 1513 1514 } 1515 1516 func TestSetattrDirMtimeNow(t *testing.T) { 1517 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1518 defer testCleanupDelayer(ctx, t) 1519 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1520 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1521 mnt, _, cancelFn := makeFS(ctx, t, config) 1522 defer mnt.Close() 1523 defer cancelFn() 1524 1525 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "mydir") 1526 if err := ioutil.Mkdir(p, 0755); err != nil { 1527 t.Fatal(err) 1528 } 1529 1530 mtime := time.Date(2015, 1, 2, 3, 4, 5, 6, time.Local) 1531 // KBFS does not respect atime (which is ok), but we need to give 1532 // something to the syscall. 1533 atime := time.Date(2015, 7, 8, 9, 10, 11, 12, time.Local) 1534 if err := os.Chtimes(p, atime, mtime); err != nil { 1535 t.Fatal(err) 1536 } 1537 1538 // TODO setmtime to now, no Utimes on Windows. 1539 /* 1540 if err := unix.Utimes(p, nil); err != nil { 1541 t.Fatalf("touch failed: %v", err) 1542 } 1543 now := time.Now() 1544 1545 fi, err := ioutil.Lstat(p) 1546 if err != nil { 1547 t.Fatal(err) 1548 } 1549 if g, o := fi.ModTime(), mtime; !g.After(o) { 1550 t.Errorf("mtime did not progress: %v <= %v", g, o) 1551 } 1552 if g, e := fi.ModTime(), now; !timeEqualFuzzy(g, e, 1*time.Second) { 1553 t.Errorf("mtime is wrong: %v !~= %v", g, e) 1554 } 1555 1556 */ 1557 } 1558 1559 func TestFsync(t *testing.T) { 1560 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1561 defer testCleanupDelayer(ctx, t) 1562 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1563 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1564 mnt, _, cancelFn := makeFS(ctx, t, config) 1565 defer mnt.Close() 1566 defer cancelFn() 1567 1568 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1569 f, err := os.Create(p) 1570 if err != nil { 1571 t.Fatal(err) 1572 } 1573 // Call in a closure since `f` is overridden below. 1574 defer func() { syncAndClose(t, f) }() 1575 const input = "hello, world\n" 1576 if _, err := io.WriteString(f, input); err != nil { 1577 t.Fatalf("write error: %v", err) 1578 } 1579 if err := f.Sync(); err != nil { 1580 t.Fatalf("fsync error: %v", err) 1581 } 1582 if err := f.Close(); err != nil { 1583 t.Fatalf("close error: %v", err) 1584 } 1585 f = nil 1586 } 1587 1588 func TestReaddirPrivateDeleteAndReaddFavorite(t *testing.T) { 1589 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1590 defer testCleanupDelayer(ctx, t) 1591 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "janedoe") 1592 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1593 mnt, _, cancelFn := makeFS(ctx, t, config) 1594 defer mnt.Close() 1595 defer cancelFn() 1596 1597 { 1598 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1599 defer testCleanupDelayer(ctx, t) 1600 // Force FakeMDServer to have some TlfIDs it can present to us 1601 // as favorites. Don't go through VFS to avoid caching causing 1602 // false positives. 1603 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Private) 1604 libkbfs.GetRootNodeOrBust(ctx, t, config, "janedoe,jdoe", tlf.Public) 1605 } 1606 1607 err := ioutil.Remove(filepath.Join(mnt.Dir, PrivateName, "jdoe,janedoe")) 1608 if err != nil { 1609 t.Fatalf("Removing favorite failed: %v", err) 1610 } 1611 1612 checkDir(t, filepath.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 1613 "jdoe": mustBeDir, // default home directory 1614 }) 1615 1616 // Re-add the favorite by doing a readdir 1617 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe,janedoe"), 1618 map[string]fileInfoCheck{}) 1619 1620 checkDir(t, filepath.Join(mnt.Dir, PrivateName), map[string]fileInfoCheck{ 1621 "jdoe,janedoe": mustBeDir, 1622 "jdoe": mustBeDir, // default home directory 1623 }) 1624 } 1625 1626 func TestReaddirMyPublic(t *testing.T) { 1627 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1628 defer testCleanupDelayer(ctx, t) 1629 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 1630 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1631 mnt, _, cancelFn := makeFS(ctx, t, config) 1632 defer mnt.Close() 1633 defer cancelFn() 1634 1635 files := map[string]fileInfoCheck{ 1636 "one": nil, 1637 "two": nil, 1638 } 1639 for filename := range files { 1640 p := filepath.Join(mnt.Dir, PublicName, "jdoe", filename) 1641 if err := ioutil.WriteFile( 1642 p, []byte("data for "+filename), 0644); err != nil { 1643 t.Fatal(err) 1644 } 1645 syncFilename(t, p) 1646 } 1647 1648 checkDir(t, filepath.Join(mnt.Dir, PublicName, "jdoe"), files) 1649 } 1650 1651 func TestReaddirOtherFolderAsReader(t *testing.T) { 1652 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1653 defer testCleanupDelayer(ctx, t) 1654 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1655 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1656 func() { 1657 mnt, _, cancelFn := makeFS(ctx, t, config) 1658 defer mnt.Close() 1659 defer cancelFn() 1660 1661 // cause the folder to exist 1662 p := filepath.Join(mnt.Dir, PrivateName, "jdoe#wsmith", "myfile") 1663 if err := ioutil.WriteFile( 1664 p, []byte("data for myfile"), 0644); err != nil { 1665 t.Fatal(err) 1666 } 1667 syncFilename(t, p) 1668 }() 1669 1670 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1671 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1672 mnt, _, cancelFn := makeFS(ctx, t, c2) 1673 defer mnt.Close() 1674 defer cancelFn() 1675 1676 checkDir(t, filepath.Join(mnt.Dir, PrivateName, "jdoe#wsmith"), map[string]fileInfoCheck{ 1677 "myfile": nil, 1678 }) 1679 } 1680 1681 func TestStatOtherFolder(t *testing.T) { 1682 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1683 defer testCleanupDelayer(ctx, t) 1684 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1685 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1686 func() { 1687 mnt, _, cancelFn := makeFS(ctx, t, config) 1688 defer mnt.Close() 1689 defer cancelFn() 1690 1691 // cause the folder to exist 1692 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1693 if err := ioutil.WriteFile( 1694 p, []byte("data for myfile"), 0644); err != nil { 1695 t.Fatal(err) 1696 } 1697 syncFilename(t, p) 1698 }() 1699 1700 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1701 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1702 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1703 defer mnt.Close() 1704 defer cancelFn() 1705 1706 switch _, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 1707 case *os.PathError: 1708 default: 1709 t.Fatalf("expected a PathError, got %T: %v", err, err) 1710 } 1711 1712 } 1713 1714 func TestStatOtherFolderFirstUse(t *testing.T) { 1715 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1716 defer testCleanupDelayer(ctx, t) 1717 // This triggers a different error than with the warmup. 1718 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1719 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1720 1721 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1722 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1723 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1724 defer mnt.Close() 1725 defer cancelFn() 1726 1727 switch _, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 1728 case *os.PathError: 1729 default: 1730 t.Fatalf("expected a PathError, got %T: %v", err, err) 1731 } 1732 1733 } 1734 1735 func TestStatOtherFolderPublic(t *testing.T) { 1736 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1737 defer testCleanupDelayer(ctx, t) 1738 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1739 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1740 func() { 1741 mnt, _, cancelFn := makeFS(ctx, t, config) 1742 defer mnt.Close() 1743 defer cancelFn() 1744 1745 // cause the folder to exist 1746 p := filepath.Join(mnt.Dir, PublicName, "jdoe", "myfile") 1747 if err := ioutil.WriteFile( 1748 p, []byte("data for myfile"), 0644); err != nil { 1749 t.Fatal(err) 1750 } 1751 syncFilename(t, p) 1752 }() 1753 1754 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1755 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1756 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1757 defer mnt.Close() 1758 defer cancelFn() 1759 1760 fi, err := ioutil.Lstat(filepath.Join(mnt.Dir, PublicName, "jdoe")) 1761 if err != nil { 1762 t.Fatal(err) 1763 } 1764 // TODO figure out right modes, note owner is the person running 1765 // fuse, not the person owning the folder 1766 if g, e := fi.Mode().String(), `drwxrwxrwx`; g != e { 1767 t.Errorf("wrong mode for folder: %q != %q", g, e) 1768 } 1769 1770 } 1771 1772 func TestReadPublicFile(t *testing.T) { 1773 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1774 defer testCleanupDelayer(ctx, t) 1775 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1776 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1777 const input = "hello, world\n" 1778 func() { 1779 mnt, _, cancelFn := makeFS(ctx, t, config) 1780 defer mnt.Close() 1781 defer cancelFn() 1782 1783 // cause the folder to exist 1784 p := filepath.Join(mnt.Dir, PublicName, "jdoe", "myfile") 1785 if err := ioutil.WriteFile(p, []byte(input), 0644); err != nil { 1786 t.Fatal(err) 1787 } 1788 syncFilename(t, p) 1789 }() 1790 1791 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1792 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1793 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1794 defer mnt.Close() 1795 defer cancelFn() 1796 1797 buf, err := ioutil.ReadFile(filepath.Join(mnt.Dir, PublicName, "jdoe", "myfile")) 1798 if err != nil { 1799 t.Fatal(err) 1800 } 1801 if g, e := string(buf), input; g != e { 1802 t.Errorf("bad file contents: %q != %q", g, e) 1803 } 1804 1805 } 1806 1807 func TestReaddirOtherFolderPublicAsAnyone(t *testing.T) { 1808 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1809 defer testCleanupDelayer(ctx, t) 1810 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1811 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1812 func() { 1813 mnt, _, cancelFn := makeFS(ctx, t, config) 1814 defer mnt.Close() 1815 defer cancelFn() 1816 1817 // cause the folder to exist 1818 p := filepath.Join(mnt.Dir, PublicName, "jdoe", "myfile") 1819 if err := ioutil.WriteFile( 1820 p, []byte("data for myfile"), 0644); err != nil { 1821 t.Fatal(err) 1822 } 1823 syncFilename(t, p) 1824 }() 1825 1826 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1827 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1828 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1829 defer mnt.Close() 1830 defer cancelFn() 1831 1832 checkDir(t, filepath.Join(mnt.Dir, PublicName, "jdoe"), map[string]fileInfoCheck{ 1833 "myfile": nil, 1834 }) 1835 1836 } 1837 1838 func TestReaddirOtherFolderAsAnyone(t *testing.T) { 1839 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1840 defer testCleanupDelayer(ctx, t) 1841 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1842 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1843 func() { 1844 mnt, _, cancelFn := makeFS(ctx, t, config) 1845 defer mnt.Close() 1846 defer cancelFn() 1847 1848 // cause the folder to exist 1849 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 1850 if err := ioutil.WriteFile( 1851 p, []byte("data for myfile"), 0644); err != nil { 1852 t.Fatal(err) 1853 } 1854 syncFilename(t, p) 1855 }() 1856 1857 c2 := libkbfs.ConfigAsUser(config, "wsmith") 1858 defer libkbfs.CheckConfigAndShutdown(ctx, t, c2) 1859 mnt, _, cancelFn := makeFSE(ctx, t, c2, 'U') 1860 defer mnt.Close() 1861 defer cancelFn() 1862 1863 switch _, err := ioutil.ReadDir(filepath.Join(mnt.Dir, PrivateName, "jdoe")); err := errors.Cause(err).(type) { 1864 case *os.PathError: 1865 default: 1866 t.Fatalf("expected a PathError, got %T: %v", err, err) 1867 } 1868 1869 } 1870 1871 func syncFolderToServerHelper(t *testing.T, tlf string, ty tlf.Type, fs *FS) { 1872 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1873 defer testCleanupDelayer(ctx, t) 1874 root := libkbfs.GetRootNodeOrBust(ctx, t, fs.config, tlf, ty) 1875 err := fs.config.KBFSOps().SyncFromServer( 1876 ctx, root.GetFolderBranch(), nil) 1877 if err != nil { 1878 t.Fatalf("Couldn't sync from server: %v", err) 1879 } 1880 } 1881 1882 func syncFolderToServer(t *testing.T, name string, fs *FS) { 1883 syncFolderToServerHelper(t, name, tlf.Private, fs) 1884 } 1885 1886 func syncPublicFolderToServer(t *testing.T, name string, fs *FS) { 1887 syncFolderToServerHelper(t, name, tlf.Public, fs) 1888 } 1889 1890 func TestInvalidateDataOnWrite(t *testing.T) { 1891 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1892 defer testCleanupDelayer(ctx, t) 1893 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1894 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1895 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 1896 defer mnt1.Close() 1897 defer cancelFn1() 1898 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config, 'U') 1899 defer mnt2.Close() 1900 defer cancelFn2() 1901 1902 const input1 = "input round one" 1903 p := filepath.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 1904 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 1905 t.Fatal(err) 1906 } 1907 syncFilename(t, p) 1908 1909 syncFolderToServer(t, "jdoe", fs2) 1910 f, err := os.Open(filepath.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 1911 if err != nil { 1912 t.Fatal(err) 1913 } 1914 defer f.Close() 1915 1916 { 1917 buf := make([]byte, 4096) 1918 n, err := f.ReadAt(buf, 0) 1919 if err != nil && err != io.EOF { 1920 t.Fatal(err) 1921 } 1922 if g, e := string(buf[:n]), input1; g != e { 1923 t.Errorf("wrong content: %q != %q", g, e) 1924 } 1925 } 1926 1927 const input2 = "second round of content" 1928 if err := ioutil.WriteFile(p, []byte(input2), 0644); err != nil { 1929 t.Fatal(err) 1930 } 1931 syncFilename(t, p) 1932 1933 syncFolderToServer(t, "jdoe", fs2) 1934 1935 { 1936 buf := make([]byte, 4096) 1937 n, err := f.ReadAt(buf, 0) 1938 if err != nil && err != io.EOF { 1939 t.Fatal(err) 1940 } 1941 if g, e := string(buf[:n]), input2; g != e { 1942 t.Errorf("wrong content: %q != %q", g, e) 1943 } 1944 } 1945 1946 } 1947 1948 func TestInvalidatePublicDataOnWrite(t *testing.T) { 1949 ctx := libcontext.BackgroundContextWithCancellationDelayer() 1950 defer testCleanupDelayer(ctx, t) 1951 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 1952 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 1953 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 1954 defer mnt1.Close() 1955 defer cancelFn1() 1956 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config, 'U') 1957 defer mnt2.Close() 1958 defer cancelFn2() 1959 1960 const input1 = "input round one" 1961 p := filepath.Join(mnt1.Dir, PublicName, "jdoe", "myfile") 1962 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 1963 t.Fatal(err) 1964 } 1965 syncFilename(t, p) 1966 1967 syncPublicFolderToServer(t, "jdoe", fs2) 1968 f, err := os.Open(filepath.Join(mnt2.Dir, PublicName, "jdoe", "myfile")) 1969 if err != nil { 1970 t.Fatal(err) 1971 } 1972 defer f.Close() 1973 1974 { 1975 buf := make([]byte, 4096) 1976 n, err := f.ReadAt(buf, 0) 1977 if err != nil && err != io.EOF { 1978 t.Fatal(err) 1979 } 1980 if g, e := string(buf[:n]), input1; g != e { 1981 t.Errorf("wrong content: %q != %q", g, e) 1982 } 1983 } 1984 1985 const input2 = "second round of content" 1986 if err := ioutil.WriteFile(p, []byte(input2), 0644); err != nil { 1987 t.Fatal(err) 1988 } 1989 syncFilename(t, p) 1990 1991 syncPublicFolderToServer(t, "jdoe", fs2) 1992 1993 { 1994 buf := make([]byte, 4096) 1995 n, err := f.ReadAt(buf, 0) 1996 if err != nil && err != io.EOF { 1997 t.Fatal(err) 1998 } 1999 if g, e := string(buf[:n]), input2; g != e { 2000 t.Errorf("wrong content: %q != %q", g, e) 2001 } 2002 } 2003 2004 } 2005 2006 func TestInvalidateDataOnTruncate(t *testing.T) { 2007 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2008 defer testCleanupDelayer(ctx, t) 2009 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2010 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2011 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2012 defer mnt1.Close() 2013 defer cancelFn1() 2014 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config, 'U') 2015 defer mnt2.Close() 2016 defer cancelFn2() 2017 2018 const input1 = "input round one" 2019 p := filepath.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 2020 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2021 t.Fatal(err) 2022 } 2023 syncFilename(t, p) 2024 2025 syncFolderToServer(t, "jdoe", fs2) 2026 f, err := os.Open(filepath.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 2027 if err != nil { 2028 t.Fatal(err) 2029 } 2030 defer f.Close() 2031 2032 { 2033 buf := make([]byte, 4096) 2034 n, err := f.ReadAt(buf, 0) 2035 if err != nil && err != io.EOF { 2036 t.Fatal(err) 2037 } 2038 if g, e := string(buf[:n]), input1; g != e { 2039 t.Errorf("wrong content: %q != %q", g, e) 2040 } 2041 } 2042 2043 const newSize = 3 2044 if err := os.Truncate(p, newSize); err != nil { 2045 t.Fatal(err) 2046 } 2047 syncFilename(t, p) 2048 2049 syncFolderToServer(t, "jdoe", fs2) 2050 2051 { 2052 buf := make([]byte, 4096) 2053 n, err := f.ReadAt(buf, 0) 2054 if err != nil && err != io.EOF { 2055 t.Fatal(err) 2056 } 2057 if g, e := string(buf[:n]), input1[:newSize]; g != e { 2058 t.Errorf("wrong content: %q != %q", g, e) 2059 } 2060 } 2061 2062 } 2063 2064 func TestInvalidateDataOnLocalWrite(t *testing.T) { 2065 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2066 defer testCleanupDelayer(ctx, t) 2067 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2068 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2069 mnt, _, cancelFn := makeFS(ctx, t, config) 2070 defer mnt.Close() 2071 defer cancelFn() 2072 2073 const input1 = "input round one" 2074 p := filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2075 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2076 t.Fatal(err) 2077 } 2078 syncFilename(t, p) 2079 2080 f, err := os.Open(p) 2081 if err != nil { 2082 t.Fatal(err) 2083 } 2084 defer f.Close() 2085 2086 { 2087 buf := make([]byte, 4096) 2088 n, err := f.ReadAt(buf, 0) 2089 if err != nil && err != io.EOF { 2090 t.Fatal(err) 2091 } 2092 if g, e := string(buf[:n]), input1; g != e { 2093 t.Errorf("wrong content: %q != %q", g, e) 2094 } 2095 } 2096 2097 const input2 = "second round of content" 2098 defer syncFilename(t, p) 2099 { 2100 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2101 defer testCleanupDelayer(ctx, t) 2102 2103 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config, "jdoe", tlf.Private) 2104 2105 ops := config.KBFSOps() 2106 myfile, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName("myfile")) 2107 if err != nil { 2108 t.Fatal(err) 2109 } 2110 if err := ops.Write(ctx, myfile, []byte(input2), 0); err != nil { 2111 t.Fatal(err) 2112 } 2113 } 2114 2115 { 2116 buf := make([]byte, 4096) 2117 n, err := f.ReadAt(buf, 0) 2118 if err != nil && err != io.EOF { 2119 t.Fatal(err) 2120 } 2121 if g, e := string(buf[:n]), input2; g != e { 2122 t.Errorf("wrong content: %q != %q", g, e) 2123 } 2124 } 2125 2126 } 2127 2128 func TestInvalidateEntryOnDelete(t *testing.T) { 2129 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2130 defer testCleanupDelayer(ctx, t) 2131 config := libkbfs.MakeTestConfigOrBust(t, "jdoe", "wsmith") 2132 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2133 mnt1, _, cancelFn1 := makeFS(ctx, t, config) 2134 defer mnt1.Close() 2135 defer cancelFn1() 2136 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config, 'U') 2137 defer mnt2.Close() 2138 defer cancelFn2() 2139 2140 const input1 = "input round one" 2141 p := filepath.Join(mnt1.Dir, PrivateName, "jdoe", "myfile") 2142 if err := ioutil.WriteFile(p, []byte(input1), 0644); err != nil { 2143 t.Fatal(err) 2144 } 2145 syncFilename(t, p) 2146 2147 syncFolderToServer(t, "jdoe", fs2) 2148 buf, err := ioutil.ReadFile(filepath.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")) 2149 if err != nil { 2150 t.Fatal(err) 2151 } 2152 if g, e := string(buf), input1; g != e { 2153 t.Errorf("wrong content: %q != %q", g, e) 2154 } 2155 2156 if err := ioutil.Remove(filepath.Join(mnt1.Dir, PrivateName, "jdoe", "myfile")); err != nil { 2157 t.Fatal(err) 2158 } 2159 2160 syncFolderToServer(t, "jdoe", fs2) 2161 2162 if buf, err := ioutil.ReadFile(filepath.Join(mnt2.Dir, PrivateName, "jdoe", "myfile")); !ioutil.IsNotExist(err) { 2163 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2164 } 2165 2166 } 2167 2168 func testForErrorText(t *testing.T, path string, expectedErr error, 2169 fileType string) { 2170 buf, err := ioutil.ReadFile(path) 2171 if err != nil { 2172 t.Fatalf("Bad error reading %s error file: %v", err, fileType) 2173 } 2174 2175 var errors []libfs.JSONReportedError 2176 err = json.Unmarshal(buf, &errors) 2177 if err != nil { 2178 t.Fatalf("Couldn't unmarshal error file: %v. Full contents: %s", 2179 err, string(buf)) 2180 } 2181 2182 found := false 2183 for _, e := range errors { 2184 if e.Error == expectedErr.Error() { 2185 found = true 2186 break 2187 } 2188 } 2189 2190 if !found { 2191 t.Errorf("%s error file did not contain the error %s. "+ 2192 "Full contents: %s", fileType, expectedErr, buf) 2193 } 2194 } 2195 2196 func TestErrorFile(t *testing.T) { 2197 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2198 defer testCleanupDelayer(ctx, t) 2199 t.Skip("Non-existent users are allowed on windows.") 2200 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2201 config.SetReporter(libkbfs.NewReporterSimple(config.Clock(), 0)) 2202 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2203 mnt, _, cancelFn := makeFS(ctx, t, config) 2204 defer mnt.Close() 2205 defer cancelFn() 2206 2207 libfs.AddRootWrapper(config) 2208 2209 // cause an error by stating a non-existent user 2210 _, err := ioutil.Lstat(filepath.Join(mnt.Dir, PrivateName, "janedoe")) 2211 if err == nil { 2212 t.Fatal("Stat of non-existent user worked!") 2213 } 2214 2215 // Make sure the root error file reads as expected 2216 expectedErr := dokan.ErrObjectNameNotFound 2217 2218 // test both the root error file and one in a directory 2219 testForErrorText(t, filepath.Join(mnt.Dir, libfs.ErrorFileName), 2220 expectedErr, "root") 2221 testForErrorText(t, filepath.Join(mnt.Dir, PublicName, libfs.ErrorFileName), 2222 expectedErr, "root") 2223 testForErrorText( 2224 t, filepath.Join(mnt.Dir, PrivateName, libfs.ErrorFileName), 2225 expectedErr, "root") 2226 2227 // Create public and private jdoe TLFs. 2228 const b = "hello world" 2229 p := filepath.Join(mnt.Dir, PublicName, "jdoe", "myfile") 2230 if err := ioutil.WriteFile(p, []byte(b), 0644); err != nil { 2231 t.Fatal(err) 2232 } 2233 syncFilename(t, p) 2234 p = filepath.Join(mnt.Dir, PrivateName, "jdoe", "myfile") 2235 if err := ioutil.WriteFile(p, []byte(b), 0644); err != nil { 2236 t.Fatal(err) 2237 } 2238 syncFilename(t, p) 2239 2240 testForErrorText( 2241 t, filepath.Join(mnt.Dir, PublicName, "jdoe", libfs.ErrorFileName), 2242 expectedErr, "dir") 2243 testForErrorText( 2244 t, filepath.Join(mnt.Dir, PrivateName, "jdoe", libfs.ErrorFileName), 2245 expectedErr, "dir") 2246 } 2247 2248 func TestInvalidateAcrossMounts(t *testing.T) { 2249 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2250 defer testCleanupDelayer(ctx, t) 2251 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2252 "user2") 2253 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2254 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2255 defer mnt1.Close() 2256 defer cancelFn1() 2257 2258 config2 := libkbfs.ConfigAsUser(config1, "user2") 2259 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2260 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2261 defer mnt2.Close() 2262 defer cancelFn2() 2263 2264 // user 1 writes one file to root and one to a sub directory 2265 const input1 = "input round one" 2266 myfile1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2267 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2268 t.Fatal(err) 2269 } 2270 syncFilename(t, myfile1) 2271 mydir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 2272 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 2273 t.Fatal(err) 2274 } 2275 mydira1 := filepath.Join(mydir1, "a") 2276 if err := ioutil.WriteFile(mydira1, []byte(input1), 0644); err != nil { 2277 t.Fatal(err) 2278 } 2279 syncFilename(t, mydira1) 2280 syncFolderToServer(t, "user1,user2", fs2) 2281 myfile2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2282 buf, err := ioutil.ReadFile(myfile2) 2283 if err != nil { 2284 t.Fatal(err) 2285 } 2286 if g, e := string(buf), input1; g != e { 2287 t.Errorf("wrong content: %q != %q", g, e) 2288 } 2289 2290 mydir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir") 2291 mydira2 := filepath.Join(mydir2, "a") 2292 buf, err = ioutil.ReadFile(mydira2) 2293 if err != nil { 2294 t.Fatal(err) 2295 } 2296 if g, e := string(buf), input1; g != e { 2297 t.Errorf("wrong content: %q != %q", g, e) 2298 } 2299 2300 // now remove the first file, and rename the second 2301 if err := ioutil.Remove(myfile1); err != nil { 2302 t.Fatal(err) 2303 } 2304 mydirb1 := filepath.Join(mydir1, "b") 2305 if err := ioutil.Rename(mydira1, mydirb1); err != nil { 2306 t.Fatal(err) 2307 } 2308 syncAll(t, "user1,user2", tlf.Private, fs1) 2309 2310 syncFolderToServer(t, "user1,user2", fs2) 2311 2312 // check everything from user 2's perspective 2313 if buf, err := ioutil.ReadFile(myfile2); !ioutil.IsNotExist(err) { 2314 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2315 } 2316 if buf, err := ioutil.ReadFile(mydira2); !ioutil.IsNotExist(err) { 2317 t.Fatalf("expected ENOENT: %v: %q", err, buf) 2318 } 2319 2320 checkDir(t, mydir2, map[string]fileInfoCheck{ 2321 "b": func(fi os.FileInfo) error { 2322 return mustBeFileWithSize(fi, int64(len(input1))) 2323 }, 2324 }) 2325 2326 mydirb2 := filepath.Join(mydir2, "b") 2327 buf, err = ioutil.ReadFile(mydirb2) 2328 if err != nil { 2329 t.Fatal(err) 2330 } 2331 if g, e := string(buf), input1; g != e { 2332 t.Errorf("wrong content: %q != %q", g, e) 2333 } 2334 } 2335 2336 func TestInvalidateAppendAcrossMounts(t *testing.T) { 2337 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2338 defer testCleanupDelayer(ctx, t) 2339 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2340 "user2") 2341 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2342 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 2343 defer mnt1.Close() 2344 defer cancelFn1() 2345 2346 config2 := libkbfs.ConfigAsUser(config1, "user2") 2347 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2348 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2349 defer mnt2.Close() 2350 defer cancelFn2() 2351 2352 // user 1 writes one file to root and one to a sub directory 2353 const input1 = "input round one" 2354 myfile1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2355 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2356 t.Fatal(err) 2357 } 2358 syncFilename(t, myfile1) 2359 syncFolderToServer(t, "user1,user2", fs2) 2360 myfile2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2361 buf, err := ioutil.ReadFile(myfile2) 2362 if err != nil { 2363 t.Fatal(err) 2364 } 2365 if g, e := string(buf), input1; g != e { 2366 t.Errorf("wrong content: %q != %q", g, e) 2367 } 2368 2369 // user 1 append using libkbfs, to ensure that it doesn't flush 2370 // the whole page. 2371 const input2 = "input round two" 2372 { 2373 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2374 defer testCleanupDelayer(ctx, t) 2375 2376 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config1, "user1,user2", tlf.Private) 2377 2378 ops := config1.KBFSOps() 2379 myfile, _, err := ops.Lookup(ctx, jdoe, jdoe.ChildName("myfile")) 2380 if err != nil { 2381 t.Fatal(err) 2382 } 2383 if err := ops.Write( 2384 ctx, myfile, []byte(input2), int64(len(input1))); err != nil { 2385 t.Fatal(err) 2386 } 2387 if err := ops.SyncAll(ctx, myfile.GetFolderBranch()); err != nil { 2388 t.Fatal(err) 2389 } 2390 } 2391 2392 syncFolderToServer(t, "user1,user2", fs2) 2393 2394 // check everything from user 2's perspective 2395 buf, err = ioutil.ReadFile(myfile2) 2396 if err != nil { 2397 t.Fatal(err) 2398 } 2399 if g, e := string(buf), input1+input2; g != e { 2400 t.Errorf("wrong content: %q != %q", g, e) 2401 } 2402 } 2403 2404 func TestInvalidateRenameToUncachedDir(t *testing.T) { 2405 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2406 defer testCleanupDelayer(ctx, t) 2407 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2408 "user2") 2409 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2410 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2411 defer mnt1.Close() 2412 defer cancelFn1() 2413 2414 config2 := libkbfs.ConfigAsUser(config1, "user2") 2415 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2416 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2417 defer mnt2.Close() 2418 defer cancelFn2() 2419 2420 // user 1 writes one file to root and one to a sub directory 2421 const input1 = "input round one" 2422 myfile1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2423 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2424 t.Fatal(err) 2425 } 2426 syncFilename(t, myfile1) 2427 mydir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 2428 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 2429 t.Fatal(err) 2430 } 2431 mydirfile1 := filepath.Join(mydir1, "myfile") 2432 syncFolderToServer(t, "user1,user2", fs2) 2433 myfile2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2434 f, err := os.OpenFile(myfile2, os.O_RDWR, 0644) 2435 if err != nil { 2436 t.Fatal(err) 2437 } 2438 // Call in a closure since `f` is overridden below. 2439 defer func() { syncAndClose(t, f) }() 2440 2441 { 2442 buf := make([]byte, 4096) 2443 n, err := f.ReadAt(buf, 0) 2444 if err != nil && err != io.EOF { 2445 t.Fatal(err) 2446 } 2447 if g, e := string(buf[:n]), input1; g != e { 2448 t.Errorf("wrong content: %q != %q", g, e) 2449 } 2450 } 2451 2452 // now rename the second into a directory that user 2 hasn't seen 2453 if err := ioutil.Rename(myfile1, mydirfile1); err != nil { 2454 t.Fatal(err) 2455 } 2456 syncAll(t, "user1,user2", tlf.Private, fs1) 2457 2458 syncFolderToServer(t, "user1,user2", fs2) 2459 2460 // user 2 should be able to write to its open file, and user 1 2461 // will see the change 2462 const input2 = "input round two" 2463 { 2464 n, err := f.WriteAt([]byte(input2), 0) 2465 if err != nil || n != len(input2) { 2466 t.Fatal(err) 2467 } 2468 } 2469 syncAndClose(t, f) 2470 f = nil 2471 2472 syncFolderToServer(t, "user1,user2", fs1) 2473 2474 buf, err := ioutil.ReadFile(mydirfile1) 2475 if err != nil { 2476 t.Fatal(err) 2477 } 2478 if g, e := string(buf), input2; g != e { 2479 t.Errorf("wrong content: %q != %q", g, e) 2480 } 2481 2482 } 2483 2484 func TestStatusFile(t *testing.T) { 2485 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2486 defer testCleanupDelayer(ctx, t) 2487 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 2488 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 2489 mnt, _, cancelFn := makeFS(ctx, t, config) 2490 defer mnt.Close() 2491 defer cancelFn() 2492 2493 libfs.AddRootWrapper(config) 2494 2495 jdoe := libkbfs.GetRootNodeOrBust(ctx, t, config, "jdoe", tlf.Public) 2496 2497 ops := config.KBFSOps() 2498 status, _, err := ops.FolderStatus(ctx, jdoe.GetFolderBranch()) 2499 if err != nil { 2500 t.Fatalf("Couldn't get KBFS status: %v", err) 2501 } 2502 2503 // Simply make sure the status in the file matches what we'd 2504 // expect. Checking the exact content should be left for tests 2505 // within libkbfs. 2506 buf, err := ioutil.ReadFile(filepath.Join(mnt.Dir, PublicName, "jdoe", 2507 libfs.StatusFileName)) 2508 if err != nil { 2509 t.Fatalf("Couldn't read KBFS status file: %v", err) 2510 } 2511 2512 var bufStatus libkbfs.FolderBranchStatus 2513 err = json.Unmarshal(buf, &bufStatus) 2514 require.NoError(t, err) 2515 2516 // Use a fuzzy check on the timestamps, since it could include 2517 // monotonic clock stuff. 2518 if !timeEqualFuzzy( 2519 status.LocalTimestamp, bufStatus.LocalTimestamp, time.Millisecond) { 2520 t.Fatalf("Local timestamp (%s) didn't match expected timestamp %v", 2521 bufStatus.LocalTimestamp, status.LocalTimestamp) 2522 } 2523 status.LocalTimestamp = bufStatus.LocalTimestamp 2524 2525 // It's safe to compare the path slices with DeepEqual since they 2526 // will all be null for this test (nothing is dirtied). 2527 if !reflect.DeepEqual(status, bufStatus) { 2528 t.Fatalf("Status file contents (%s) didn't match expected status %v", 2529 buf, status) 2530 } 2531 2532 } 2533 2534 // TODO: remove once we have automatic conflict resolution tests 2535 func TestUnstageFile(t *testing.T) { 2536 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2537 defer testCleanupDelayer(ctx, t) 2538 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", "user2") 2539 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 2540 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2541 defer mnt1.Close() 2542 defer cancelFn1() 2543 2544 config2 := libkbfs.ConfigAsUser(config1, "user2") 2545 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 2546 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2547 defer mnt2.Close() 2548 defer cancelFn2() 2549 2550 // both users read the root dir first 2551 myroot1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2") 2552 myroot2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2") 2553 checkDir(t, myroot1, map[string]fileInfoCheck{}) 2554 checkDir(t, myroot2, map[string]fileInfoCheck{}) 2555 2556 // turn updates off for user 2 2557 rootNode2 := libkbfs.GetRootNodeOrBust(ctx, t, config2, "user1,user2", tlf.Private) 2558 _, err := libkbfs.DisableUpdatesForTesting(config2, 2559 rootNode2.GetFolderBranch()) 2560 if err != nil { 2561 t.Fatalf("Couldn't pause user 2 updates") 2562 } 2563 err = libkbfs.DisableCRForTesting(config2, rootNode2.GetFolderBranch()) 2564 if err != nil { 2565 t.Fatalf("Couldn't disable user 2 CR") 2566 } 2567 2568 // user1 writes a file and makes a few directories 2569 const input1 = "input round one" 2570 myfile1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "myfile") 2571 if err := ioutil.WriteFile(myfile1, []byte(input1), 0644); err != nil { 2572 t.Fatal(err) 2573 } 2574 syncFilename(t, myfile1) 2575 mydir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 2576 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 2577 t.Fatal(err) 2578 } 2579 mysubdir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir", 2580 "mysubdir") 2581 if err := ioutil.Mkdir(mysubdir1, 0755); err != nil { 2582 t.Fatal(err) 2583 } 2584 syncAll(t, "user1,user2", tlf.Private, fs1) 2585 2586 // user2 does similar 2587 const input2 = "input round two" 2588 myfile2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "myfile") 2589 if err := ioutil.WriteFile(myfile2, []byte(input2), 0644); err != nil { 2590 t.Fatal(err) 2591 } 2592 syncFilename(t, myfile2) 2593 mydir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir") 2594 if err := ioutil.Mkdir(mydir2, 0755); err != nil { 2595 t.Fatal(err) 2596 } 2597 myothersubdir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir", 2598 "myothersubdir") 2599 if err := ioutil.Mkdir(myothersubdir2, 0755); err != nil { 2600 t.Fatal(err) 2601 } 2602 syncAll(t, "user1,user2", tlf.Private, fs2) 2603 2604 // verify that they don't see each other's files 2605 checkDir(t, mydir1, map[string]fileInfoCheck{ 2606 "mysubdir": mustBeDir, 2607 }) 2608 checkDir(t, mydir2, map[string]fileInfoCheck{ 2609 "myothersubdir": mustBeDir, 2610 }) 2611 2612 // now unstage user 2 and they should see the same stuff 2613 unstageFile2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 2614 libfs.UnstageFileName) 2615 if err := ioutil.WriteFile(unstageFile2, []byte{1}, 0222); err != nil { 2616 t.Fatal(err) 2617 } 2618 2619 syncFolderToServer(t, "user1,user2", fs2) 2620 2621 // They should see identical folders now 2622 checkDir(t, mydir1, map[string]fileInfoCheck{ 2623 "mysubdir": mustBeDir, 2624 }) 2625 checkDir(t, mydir2, map[string]fileInfoCheck{ 2626 "mysubdir": mustBeDir, 2627 }) 2628 2629 buf, err := ioutil.ReadFile(myfile1) 2630 if err != nil { 2631 t.Fatal(err) 2632 } 2633 if g, e := string(buf), input1; g != e { 2634 t.Errorf("wrong content: %q != %q", g, e) 2635 } 2636 buf, err = ioutil.ReadFile(myfile2) 2637 if err != nil { 2638 t.Fatal(err) 2639 } 2640 if g, e := string(buf), input1; g != e { 2641 t.Errorf("wrong content: %q != %q", g, e) 2642 } 2643 } 2644 2645 func TestSimpleCRNoConflict(t *testing.T) { 2646 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2647 defer testCleanupDelayer(ctx, t) 2648 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", "user2") 2649 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2650 defer mnt1.Close() 2651 defer cancelFn1() 2652 2653 config2 := libkbfs.ConfigAsUser(config1, "user2") 2654 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2655 defer mnt2.Close() 2656 defer cancelFn2() 2657 2658 // both users read the root dir first 2659 root1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2") 2660 root2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2") 2661 checkDir(t, root1, map[string]fileInfoCheck{}) 2662 checkDir(t, root2, map[string]fileInfoCheck{}) 2663 2664 // disable updates for user 2 2665 disableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 2666 libfs.DisableUpdatesFileName) 2667 if err := ioutil.WriteFile(disableUpdatesFile, 2668 []byte("off"), 0644); err != nil { 2669 t.Fatal(err) 2670 } 2671 2672 // user1 writes a file and makes a few directories 2673 const input1 = "input round one" 2674 file1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "file1") 2675 if err := ioutil.WriteFile(file1, []byte(input1), 0644); err != nil { 2676 t.Fatal(err) 2677 } 2678 syncFilename(t, file1) 2679 dir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "dir") 2680 if err := ioutil.Mkdir(dir1, 0755); err != nil { 2681 t.Fatal(err) 2682 } 2683 subdir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "dir", "subdir1") 2684 if err := ioutil.Mkdir(subdir1, 0755); err != nil { 2685 t.Fatal(err) 2686 } 2687 syncAll(t, "user1,user2", tlf.Private, fs1) 2688 2689 // user2 does similar 2690 const input2 = "input round two two two" 2691 file2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "file2") 2692 if err := ioutil.WriteFile(file2, []byte(input2), 0644); err != nil { 2693 t.Fatal(err) 2694 } 2695 syncFilename(t, file2) 2696 dir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "dir") 2697 if err := ioutil.Mkdir(dir2, 0755); err != nil { 2698 t.Fatal(err) 2699 } 2700 subdir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "dir", "subdir2") 2701 if err := ioutil.Mkdir(subdir2, 0755); err != nil { 2702 t.Fatal(err) 2703 } 2704 syncAll(t, "user1,user2", tlf.Private, fs2) 2705 2706 // verify that they don't see each other's files 2707 checkDir(t, root1, map[string]fileInfoCheck{ 2708 "file1": func(fi os.FileInfo) error { 2709 return mustBeFileWithSize(fi, int64(len(input1))) 2710 }, 2711 "dir": mustBeDir, 2712 }) 2713 checkDir(t, dir1, map[string]fileInfoCheck{ 2714 "subdir1": mustBeDir, 2715 }) 2716 2717 checkDir(t, root2, map[string]fileInfoCheck{ 2718 "file2": func(fi os.FileInfo) error { 2719 return mustBeFileWithSize(fi, int64(len(input2))) 2720 }, 2721 "dir": mustBeDir, 2722 }) 2723 checkDir(t, dir2, map[string]fileInfoCheck{ 2724 "subdir2": mustBeDir, 2725 }) 2726 2727 // now re-enable user 2 updates and CR, and the merge should happen 2728 enableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 2729 libfs.EnableUpdatesFileName) 2730 if err := ioutil.WriteFile(enableUpdatesFile, 2731 []byte("on"), 0644); err != nil { 2732 t.Fatal(err) 2733 } 2734 2735 syncFolderToServer(t, "user1,user2", fs2) 2736 syncFolderToServer(t, "user1,user2", fs1) 2737 2738 // They should see identical folders now (conflict-free merge) 2739 checkDir(t, root1, map[string]fileInfoCheck{ 2740 "file1": func(fi os.FileInfo) error { 2741 return mustBeFileWithSize(fi, int64(len(input1))) 2742 }, 2743 "file2": func(fi os.FileInfo) error { 2744 return mustBeFileWithSize(fi, int64(len(input2))) 2745 }, 2746 "dir": mustBeDir, 2747 }) 2748 checkDir(t, dir1, map[string]fileInfoCheck{ 2749 "subdir1": mustBeDir, 2750 "subdir2": mustBeDir, 2751 }) 2752 checkDir(t, root2, map[string]fileInfoCheck{ 2753 "file1": func(fi os.FileInfo) error { 2754 return mustBeFileWithSize(fi, int64(len(input1))) 2755 }, 2756 "file2": func(fi os.FileInfo) error { 2757 return mustBeFileWithSize(fi, int64(len(input2))) 2758 }, 2759 "dir": mustBeDir, 2760 }) 2761 checkDir(t, dir2, map[string]fileInfoCheck{ 2762 "subdir1": mustBeDir, 2763 "subdir2": mustBeDir, 2764 }) 2765 2766 buf, err := ioutil.ReadFile(file1) 2767 if err != nil { 2768 t.Fatal(err) 2769 } 2770 if g, e := string(buf), input1; g != e { 2771 t.Errorf("wrong content: %q != %q", g, e) 2772 } 2773 file2u1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "file2") 2774 buf, err = ioutil.ReadFile(file2u1) 2775 if err != nil { 2776 t.Fatal(err) 2777 } 2778 if g, e := string(buf), input2; g != e { 2779 t.Errorf("wrong content: %q != %q", g, e) 2780 } 2781 2782 file1u2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "file1") 2783 buf, err = ioutil.ReadFile(file1u2) 2784 if err != nil { 2785 t.Fatal(err) 2786 } 2787 if g, e := string(buf), input1; g != e { 2788 t.Errorf("wrong content: %q != %q", g, e) 2789 } 2790 buf, err = ioutil.ReadFile(file2) 2791 if err != nil { 2792 t.Fatal(err) 2793 } 2794 if g, e := string(buf), input2; g != e { 2795 t.Errorf("wrong content: %q != %q", g, e) 2796 } 2797 } 2798 2799 func TestSimpleCRConflictOnOpenFiles(t *testing.T) { 2800 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2801 defer testCleanupDelayer(ctx, t) 2802 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2803 "user2") 2804 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2805 defer mnt1.Close() 2806 defer cancelFn1() 2807 2808 config2 := libkbfs.ConfigAsUser(config1, "user2") 2809 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2810 defer mnt2.Close() 2811 defer cancelFn2() 2812 2813 now := time.Now() 2814 var clock clocktest.TestClock 2815 clock.Set(now) 2816 config2.SetClock(&clock) 2817 2818 // both users read the root dir first 2819 root1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2") 2820 root2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2") 2821 checkDir(t, root1, map[string]fileInfoCheck{}) 2822 checkDir(t, root2, map[string]fileInfoCheck{}) 2823 2824 // disable updates for user 2 2825 disableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 2826 libfs.DisableUpdatesFileName) 2827 if err := ioutil.WriteFile(disableUpdatesFile, 2828 []byte("off"), 0644); err != nil { 2829 t.Fatal(err) 2830 } 2831 2832 // user1 creates and writes a file 2833 file1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "f") 2834 f1, err := os.Create(file1) 2835 if err != nil { 2836 t.Fatal(err) 2837 } 2838 defer syncAndClose(t, f1) 2839 2840 const input1 = "hello" 2841 { 2842 n, err := f1.WriteAt([]byte(input1), 0) 2843 if err != nil || n != len(input1) { 2844 t.Fatal(err) 2845 } 2846 if err := f1.Sync(); err != nil { 2847 t.Fatal(err) 2848 } 2849 } 2850 2851 // user2 creates and writes a file 2852 file2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "f") 2853 f2, err := os.Create(file2) 2854 if err != nil { 2855 t.Fatal(err) 2856 } 2857 defer syncAndClose(t, f2) 2858 2859 const input2 = "ohell" 2860 { 2861 n, err := f2.WriteAt([]byte(input2), 0) 2862 if err != nil || n != len(input2) { 2863 t.Fatal(err) 2864 } 2865 if err := f2.Sync(); err != nil { 2866 t.Fatal(err) 2867 } 2868 } 2869 2870 // now re-enable user 2 updates and CR, and the merge should happen 2871 enableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 2872 libfs.EnableUpdatesFileName) 2873 if err := ioutil.WriteFile(enableUpdatesFile, 2874 []byte("on"), 0644); err != nil { 2875 t.Fatal(err) 2876 } 2877 2878 syncFolderToServer(t, "user1,user2", fs2) 2879 syncFolderToServer(t, "user1,user2", fs1) 2880 2881 // They should both be able to read their past writes. 2882 { 2883 buf := make([]byte, len(input1)) 2884 n, err := f1.ReadAt(buf, 0) 2885 if err != nil || n != len(input1) { 2886 t.Fatal(err) 2887 } 2888 if g, e := string(buf), input1; g != e { 2889 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 2890 } 2891 } 2892 { 2893 buf := make([]byte, len(input2)) 2894 n, err := f2.ReadAt(buf, 0) 2895 if err != nil || n != len(input2) { 2896 t.Fatal(err) 2897 } 2898 if g, e := string(buf), input2; g != e { 2899 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 2900 } 2901 } 2902 2903 // They should see the conflict. 2904 cre := libkbfs.WriterDeviceDateConflictRenamer{} 2905 checkDir(t, root1, map[string]fileInfoCheck{ 2906 "f": func(fi os.FileInfo) error { 2907 return mustBeFileWithSize(fi, int64(len(input1))) 2908 }, 2909 cre.ConflictRenameHelper(now, "user2", "dev1", "f"): func(fi os.FileInfo) error { 2910 return mustBeFileWithSize(fi, int64(len(input2))) 2911 }, 2912 }) 2913 checkDir(t, root2, map[string]fileInfoCheck{ 2914 "f": func(fi os.FileInfo) error { 2915 return mustBeFileWithSize(fi, int64(len(input1))) 2916 }, 2917 cre.ConflictRenameHelper(now, "user2", "dev1", "f"): func(fi os.FileInfo) error { 2918 return mustBeFileWithSize(fi, int64(len(input2))) 2919 }, 2920 }) 2921 2922 input3 := " world" 2923 { 2924 n, err := f1.WriteAt([]byte(input3), int64(len(input1))) 2925 if err != nil || n != len(input3) { 2926 t.Fatal(err) 2927 } 2928 if err := f1.Sync(); err != nil { 2929 t.Fatal(err) 2930 } 2931 } 2932 2933 syncFolderToServer(t, "user1,user2", fs2) 2934 2935 input4 := " dlrow" 2936 { 2937 n, err := f2.WriteAt([]byte(input4), int64(len(input2))) 2938 if err != nil || n != len(input4) { 2939 t.Fatal(err) 2940 } 2941 if err := f2.Sync(); err != nil { 2942 t.Fatal(err) 2943 } 2944 } 2945 2946 syncFolderToServer(t, "user1,user2", fs1) 2947 2948 buf, err := ioutil.ReadFile(file1) 2949 if err != nil { 2950 t.Fatal(err) 2951 } 2952 if g, e := string(buf), input1+input3; g != e { 2953 t.Errorf("wrong content: %q != %q", g, e) 2954 } 2955 buf, err = ioutil.ReadFile(file2) 2956 if err != nil { 2957 t.Fatal(err) 2958 } 2959 if g, e := string(buf), input1+input3; g != e { 2960 t.Errorf("wrong content: %q != %q", g, e) 2961 } 2962 2963 // TODO: timestamps without ':', see KBFS-516 2964 /* 2965 filec1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", 2966 "f.conflict.user2."+nowString) 2967 filec2 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", 2968 "f.conflict.user2."+nowString) 2969 2970 buf, err = ioutil.ReadFile(filec1) 2971 if err != nil { 2972 t.Fatal(err) 2973 } 2974 t.Fatal("END END END") 2975 if g, e := string(buf), input2+input4; g != e { 2976 t.Errorf("wrong content: %q != %q", g, e) 2977 } 2978 buf, err = ioutil.ReadFile(filec2) 2979 if err != nil { 2980 t.Fatal(err) 2981 } 2982 if g, e := string(buf), input2+input4; g != e { 2983 t.Errorf("wrong content: %q != %q", g, e) 2984 } 2985 */ 2986 } 2987 2988 func TestSimpleCRConflictOnOpenMergedFile(t *testing.T) { 2989 ctx := libcontext.BackgroundContextWithCancellationDelayer() 2990 defer testCleanupDelayer(ctx, t) 2991 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", 2992 "user2") 2993 mnt1, fs1, cancelFn1 := makeFS(ctx, t, config1) 2994 defer mnt1.Close() 2995 defer cancelFn1() 2996 2997 config2 := libkbfs.ConfigAsUser(config1, "user2") 2998 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 2999 defer mnt2.Close() 3000 defer cancelFn2() 3001 3002 now := time.Now() 3003 var clock clocktest.TestClock 3004 clock.Set(now) 3005 config2.SetClock(&clock) 3006 3007 // both users read the root dir first 3008 root1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2") 3009 root2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2") 3010 checkDir(t, root1, map[string]fileInfoCheck{}) 3011 checkDir(t, root2, map[string]fileInfoCheck{}) 3012 3013 // disable updates for user 2 3014 disableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 3015 libfs.DisableUpdatesFileName) 3016 if err := ioutil.WriteFile(disableUpdatesFile, 3017 []byte("off"), 0644); err != nil { 3018 t.Fatal(err) 3019 } 3020 3021 // user1 creates and writes a file 3022 file1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "f") 3023 f1, err := os.Create(file1) 3024 if err != nil { 3025 t.Fatal(err) 3026 } 3027 defer syncAndClose(t, f1) 3028 3029 const input1 = "hello" 3030 { 3031 n, err := f1.WriteAt([]byte(input1), 0) 3032 if err != nil || n != len(input1) { 3033 t.Fatal(err) 3034 } 3035 if err := f1.Sync(); err != nil { 3036 t.Fatal(err) 3037 } 3038 } 3039 3040 // user2 creates a directory and writes a file to it 3041 dir2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "f") 3042 if err := ioutil.Mkdir(dir2, 0755); err != nil { 3043 t.Fatal(err) 3044 } 3045 file2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "f", "foo") 3046 f2, err := os.Create(file2) 3047 if err != nil { 3048 t.Fatal(err) 3049 } 3050 defer syncAndClose(t, f2) 3051 3052 const input2 = "ohell" 3053 { 3054 n, err := f2.WriteAt([]byte(input2), 0) 3055 if err != nil || n != len(input2) { 3056 t.Fatal(err) 3057 } 3058 if err := f2.Sync(); err != nil { 3059 t.Fatal(err) 3060 } 3061 } 3062 3063 // now re-enable user 2 updates and CR, and the merge should happen 3064 enableUpdatesFile := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 3065 libfs.EnableUpdatesFileName) 3066 if err := ioutil.WriteFile(enableUpdatesFile, 3067 []byte("on"), 0644); err != nil { 3068 t.Fatal(err) 3069 } 3070 3071 syncFolderToServer(t, "user1,user2", fs2) 3072 syncFolderToServer(t, "user1,user2", fs1) 3073 3074 // They should both be able to read their past writes. 3075 { 3076 buf := make([]byte, len(input1)) 3077 n, err := f1.ReadAt(buf, 0) 3078 if err != nil || n != len(input1) { 3079 t.Fatal(err) 3080 } 3081 if g, e := string(buf), input1; g != e { 3082 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3083 } 3084 } 3085 { 3086 buf := make([]byte, len(input2)) 3087 n, err := f2.ReadAt(buf, 0) 3088 if err != nil || n != len(input2) { 3089 t.Fatal(err) 3090 } 3091 if g, e := string(buf), input2; g != e { 3092 t.Errorf("Unexpected read on f2: %s vs %s", g, e) 3093 } 3094 } 3095 3096 // They should see the conflict. 3097 cre := libkbfs.WriterDeviceDateConflictRenamer{} 3098 checkDir(t, root1, map[string]fileInfoCheck{ 3099 cre.ConflictRenameHelper(now, "user1", "dev1", "f"): func(fi os.FileInfo) error { 3100 return mustBeFileWithSize(fi, int64(len(input1))) 3101 }, 3102 "f": mustBeDir, 3103 }) 3104 checkDir(t, root2, map[string]fileInfoCheck{ 3105 cre.ConflictRenameHelper(now, "user1", "dev1", "f"): func(fi os.FileInfo) error { 3106 return mustBeFileWithSize(fi, int64(len(input1))) 3107 }, 3108 "f": mustBeDir, 3109 }) 3110 3111 input3 := " world" 3112 { 3113 n, err := f1.WriteAt([]byte(input3), int64(len(input1))) 3114 if err != nil || n != len(input3) { 3115 t.Fatal(err) 3116 } 3117 if err := f1.Sync(); err != nil { 3118 t.Fatal(err) 3119 } 3120 } 3121 3122 syncFolderToServer(t, "user1,user2", fs2) 3123 3124 input4 := " dlrow" 3125 { 3126 n, err := f2.WriteAt([]byte(input4), int64(len(input2))) 3127 if err != nil || n != len(input4) { 3128 t.Fatal(err) 3129 } 3130 if err := f2.Sync(); err != nil { 3131 t.Fatal(err) 3132 } 3133 } 3134 3135 syncFolderToServer(t, "user1,user2", fs1) 3136 3137 file2u1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "f", "foo") 3138 buf, err := ioutil.ReadFile(file2u1) 3139 if err != nil { 3140 t.Fatal(err) 3141 } 3142 if g, e := string(buf), input2+input4; g != e { 3143 t.Errorf("wrong content: %q != %q", g, e) 3144 } 3145 buf, err = ioutil.ReadFile(file2) 3146 if err != nil { 3147 t.Fatal(err) 3148 } 3149 if g, e := string(buf), input2+input4; g != e { 3150 t.Errorf("wrong content: %q != %q", g, e) 3151 } 3152 3153 // TODO: timestamps without ':', see KBFS-516 3154 /* 3155 filec1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", 3156 "f.conflict.user1."+nowString) 3157 filec2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", 3158 "f.conflict.user1."+nowString) 3159 buf, err = ioutil.ReadFile(filec1) 3160 if err != nil { 3161 t.Fatal(err) 3162 } 3163 if g, e := string(buf), input1+input3; g != e { 3164 t.Errorf("wrong content: %q != %q", g, e) 3165 } 3166 buf, err = ioutil.ReadFile(filec2) 3167 if err != nil { 3168 t.Fatal(err) 3169 } 3170 if g, e := string(buf), input1+input3; g != e { 3171 t.Errorf("wrong content: %q != %q", g, e) 3172 } 3173 */ 3174 } 3175 3176 func TestKbfsFileInfo(t *testing.T) { 3177 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3178 defer testCleanupDelayer(ctx, t) 3179 config1 := libkbfs.MakeTestConfigOrBust(t, "user1", "user2") 3180 defer libkbfs.CheckConfigAndShutdown(ctx, t, config1) 3181 mnt1, _, cancelFn1 := makeFS(ctx, t, config1) 3182 defer mnt1.Close() 3183 defer cancelFn1() 3184 3185 config2 := libkbfs.ConfigAsUser(config1, "user2") 3186 defer libkbfs.CheckConfigAndShutdown(ctx, t, config2) 3187 mnt2, fs2, cancelFn2 := makeFSE(ctx, t, config2, 'U') 3188 defer mnt2.Close() 3189 defer cancelFn2() 3190 3191 // Turn off the prefetcher to avoid races when reading the file info file. 3192 ch := config2.BlockOps().TogglePrefetcher(false) 3193 select { 3194 case <-ch: 3195 case <-ctx.Done(): 3196 t.Fatal(ctx.Err()) 3197 } 3198 3199 mydir1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir") 3200 if err := ioutil.Mkdir(mydir1, 0755); err != nil { 3201 t.Fatal(err) 3202 } 3203 myfile1 := filepath.Join(mnt1.Dir, PrivateName, "user1,user2", "mydir", "myfile") 3204 if err := ioutil.WriteFile(myfile1, []byte("foo"), 0644); err != nil { 3205 t.Fatal(err) 3206 } 3207 syncFilename(t, myfile1) 3208 syncFolderToServer(t, "user1,user2", fs2) 3209 fi2 := filepath.Join(mnt2.Dir, PrivateName, "user1,user2", "mydir", libfs.FileInfoPrefix+"myfile") 3210 bs, err := ioutil.ReadFile(fi2) 3211 if err != nil { 3212 t.Fatal(err) 3213 } 3214 var dst libkbfs.NodeMetadata 3215 err = json.Unmarshal(bs, &dst) 3216 if err != nil { 3217 t.Fatal(err) 3218 } 3219 if dst.LastWriterUnverified != kbname.NormalizedUsername("user1") { 3220 t.Fatalf("Expected user1, %v raw %X", dst, bs) 3221 } 3222 } 3223 3224 func TestUpdateHistoryFile(t *testing.T) { 3225 ctx := libcontext.BackgroundContextWithCancellationDelayer() 3226 defer testCleanupDelayer(ctx, t) 3227 config := libkbfs.MakeTestConfigOrBust(t, "jdoe") 3228 mnt, _, cancelFn := makeFS(ctx, t, config) 3229 defer mnt.Close() 3230 defer cancelFn() 3231 defer libkbfs.CheckConfigAndShutdown(ctx, t, config) 3232 3233 libfs.AddRootWrapper(config) 3234 3235 t.Log("Make several revisions") 3236 p := filepath.Join(mnt.Dir, PrivateName, "jdoe") 3237 for i := 0; i < 10; i++ { 3238 file := filepath.Join(p, fmt.Sprintf("foo-%d", i)) 3239 f, err := os.Create(file) 3240 require.NoError(t, err) 3241 syncAndClose(t, f) 3242 } 3243 3244 t.Log("Read a revision range") 3245 histPrefix := filepath.Join(p, libfs.UpdateHistoryFileName) 3246 fRange, err := os.Open(histPrefix + ".3-5") 3247 require.NoError(t, err) 3248 defer fRange.Close() 3249 b, err := ioutil.ReadAll(fRange) 3250 require.NoError(t, err) 3251 var histRange libkbfs.TLFUpdateHistory 3252 err = json.Unmarshal(b, &histRange) 3253 require.NoError(t, err) 3254 require.Len(t, histRange.Updates, 3) 3255 3256 t.Log("Read a single revision") 3257 fSingle, err := os.Open(histPrefix + ".7") 3258 require.NoError(t, err) 3259 defer fSingle.Close() 3260 b, err = ioutil.ReadAll(fSingle) 3261 require.NoError(t, err) 3262 var histSingle libkbfs.TLFUpdateHistory 3263 err = json.Unmarshal(b, &histSingle) 3264 require.NoError(t, err) 3265 require.Len(t, histSingle.Updates, 1) 3266 3267 t.Log("Read the entire history") 3268 fAll, err := os.Open(histPrefix) 3269 require.NoError(t, err) 3270 defer fAll.Close() 3271 b, err = ioutil.ReadAll(fAll) 3272 require.NoError(t, err) 3273 var histAll libkbfs.TLFUpdateHistory 3274 err = json.Unmarshal(b, &histAll) 3275 require.NoError(t, err) 3276 require.Len(t, histAll.Updates, 11) 3277 }