github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/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  }