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