github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/p9test/client_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package p9test
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"math/rand"
    22  	"os"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"golang.org/x/sys/unix"
    30  	"github.com/SagerNet/gvisor/pkg/fd"
    31  	"github.com/SagerNet/gvisor/pkg/p9"
    32  	"github.com/SagerNet/gvisor/pkg/sync"
    33  )
    34  
    35  func TestPanic(t *testing.T) {
    36  	h, c := NewHarness(t)
    37  	defer h.Finish()
    38  
    39  	// Create a new root.
    40  	d := h.NewDirectory(nil)(nil)
    41  	defer d.Close() // Needed manually.
    42  	h.Attacher.EXPECT().Attach().Return(d, nil).Do(func() {
    43  		// Panic here, and ensure that we get back EFAULT.
    44  		panic("handler")
    45  	})
    46  
    47  	// Attach to the client.
    48  	if _, err := c.Attach("/"); err != unix.EFAULT {
    49  		t.Fatalf("got attach err %v, want EFAULT", err)
    50  	}
    51  }
    52  
    53  func TestAttachNoLeak(t *testing.T) {
    54  	h, c := NewHarness(t)
    55  	defer h.Finish()
    56  
    57  	// Create a new root.
    58  	d := h.NewDirectory(nil)(nil)
    59  	h.Attacher.EXPECT().Attach().Return(d, nil).Times(1)
    60  
    61  	// Attach to the client.
    62  	f, err := c.Attach("/")
    63  	if err != nil {
    64  		t.Fatalf("got attach err %v, want nil", err)
    65  	}
    66  
    67  	// Don't close the file. This should be closed automatically when the
    68  	// client disconnects. The mock asserts that everything is closed
    69  	// exactly once. This statement just removes the unused variable error.
    70  	_ = f
    71  }
    72  
    73  func TestBadAttach(t *testing.T) {
    74  	h, c := NewHarness(t)
    75  	defer h.Finish()
    76  
    77  	// Return an error on attach.
    78  	h.Attacher.EXPECT().Attach().Return(nil, unix.EINVAL).Times(1)
    79  
    80  	// Attach to the client.
    81  	if _, err := c.Attach("/"); err != unix.EINVAL {
    82  		t.Fatalf("got attach err %v, want unix.EINVAL", err)
    83  	}
    84  }
    85  
    86  func TestWalkAttach(t *testing.T) {
    87  	h, c := NewHarness(t)
    88  	defer h.Finish()
    89  
    90  	// Create a new root.
    91  	d := h.NewDirectory(map[string]Generator{
    92  		"a": h.NewDirectory(map[string]Generator{
    93  			"b": h.NewFile(),
    94  		}),
    95  	})(nil)
    96  	h.Attacher.EXPECT().Attach().Return(d, nil).Times(1)
    97  
    98  	// Attach to the client as a non-root, and ensure that the walk above
    99  	// occurs as expected. We should get back b, and all references should
   100  	// be dropped when the file is closed.
   101  	f, err := c.Attach("/a/b")
   102  	if err != nil {
   103  		t.Fatalf("got attach err %v, want nil", err)
   104  	}
   105  	defer f.Close()
   106  
   107  	// Check that's a regular file.
   108  	if _, _, attr, err := f.GetAttr(p9.AttrMaskAll()); err != nil {
   109  		t.Errorf("got err %v, want nil", err)
   110  	} else if !attr.Mode.IsRegular() {
   111  		t.Errorf("got mode %v, want regular file", err)
   112  	}
   113  }
   114  
   115  // newTypeMap returns a new type map dictionary.
   116  func newTypeMap(h *Harness) map[string]Generator {
   117  	return map[string]Generator{
   118  		"directory":        h.NewDirectory(map[string]Generator{}),
   119  		"file":             h.NewFile(),
   120  		"symlink":          h.NewSymlink(),
   121  		"block-device":     h.NewBlockDevice(),
   122  		"character-device": h.NewCharacterDevice(),
   123  		"named-pipe":       h.NewNamedPipe(),
   124  		"socket":           h.NewSocket(),
   125  	}
   126  }
   127  
   128  // newRoot returns a new root filesystem.
   129  //
   130  // This is set up in a deterministic way for testing most operations.
   131  //
   132  // The represented file system looks like:
   133  // - file
   134  // - symlink
   135  // - directory
   136  // ...
   137  // + one
   138  //   - file
   139  //   - symlink
   140  //   - directory
   141  //   ...
   142  //   + two
   143  //     - file
   144  //     - symlink
   145  //     - directory
   146  //     ...
   147  // + three
   148  //   - file
   149  //   - symlink
   150  //   - directory
   151  //   ...
   152  func newRoot(h *Harness, c *p9.Client) (*Mock, p9.File) {
   153  	root := newTypeMap(h)
   154  	one := newTypeMap(h)
   155  	two := newTypeMap(h)
   156  	three := newTypeMap(h)
   157  	one["two"] = h.NewDirectory(two)      // Will be nested in one.
   158  	root["one"] = h.NewDirectory(one)     // Top level.
   159  	root["three"] = h.NewDirectory(three) // Alternate top-level.
   160  
   161  	// Create a new root.
   162  	rootBackend := h.NewDirectory(root)(nil)
   163  	h.Attacher.EXPECT().Attach().Return(rootBackend, nil)
   164  
   165  	// Attach to the client.
   166  	r, err := c.Attach("/")
   167  	if err != nil {
   168  		h.t.Fatalf("got attach err %v, want nil", err)
   169  	}
   170  
   171  	return rootBackend, r
   172  }
   173  
   174  func allInvalidNames(from string) []string {
   175  	return []string{
   176  		from + "/other",
   177  		from + "/..",
   178  		from + "/.",
   179  		from + "/",
   180  		"other/" + from,
   181  		"/" + from,
   182  		"./" + from,
   183  		"../" + from,
   184  		".",
   185  		"..",
   186  		"/",
   187  		"",
   188  	}
   189  }
   190  
   191  func TestWalkInvalid(t *testing.T) {
   192  	h, c := NewHarness(t)
   193  	defer h.Finish()
   194  
   195  	_, root := newRoot(h, c)
   196  	defer root.Close()
   197  
   198  	// Run relevant tests.
   199  	for name := range newTypeMap(h) {
   200  		// These are all the various ways that one might attempt to
   201  		// construct compound paths. They should all be rejected, as
   202  		// any compound that contains a / is not allowed, as well as
   203  		// the singular paths of '.' and '..'.
   204  		if _, _, err := root.Walk([]string{".", name}); err != unix.EINVAL {
   205  			t.Errorf("Walk through . %s wanted EINVAL, got %v", name, err)
   206  		}
   207  		if _, _, err := root.Walk([]string{"..", name}); err != unix.EINVAL {
   208  			t.Errorf("Walk through . %s wanted EINVAL, got %v", name, err)
   209  		}
   210  		if _, _, err := root.Walk([]string{name, "."}); err != unix.EINVAL {
   211  			t.Errorf("Walk through %s . wanted EINVAL, got %v", name, err)
   212  		}
   213  		if _, _, err := root.Walk([]string{name, ".."}); err != unix.EINVAL {
   214  			t.Errorf("Walk through %s .. wanted EINVAL, got %v", name, err)
   215  		}
   216  		for _, invalidName := range allInvalidNames(name) {
   217  			if _, _, err := root.Walk([]string{invalidName}); err != unix.EINVAL {
   218  				t.Errorf("Walk through %s wanted EINVAL, got %v", invalidName, err)
   219  			}
   220  		}
   221  		wantErr := unix.EINVAL
   222  		if name == "directory" {
   223  			// We can attempt a walk through a directory. However,
   224  			// we should never see a file named "other", so we
   225  			// expect this to return ENOENT.
   226  			wantErr = unix.ENOENT
   227  		}
   228  		if _, _, err := root.Walk([]string{name, "other"}); err != wantErr {
   229  			t.Errorf("Walk through %s/other wanted %v, got %v", name, wantErr, err)
   230  		}
   231  
   232  		// Do a successful walk.
   233  		_, f, err := root.Walk([]string{name})
   234  		if err != nil {
   235  			t.Errorf("Walk to %s wanted nil, got %v", name, err)
   236  		}
   237  		defer f.Close()
   238  		local := h.Pop(f)
   239  
   240  		// Check that the file matches.
   241  		_, localMask, localAttr, localErr := local.GetAttr(p9.AttrMaskAll())
   242  		if _, mask, attr, err := f.GetAttr(p9.AttrMaskAll()); mask != localMask || attr != localAttr || err != localErr {
   243  			t.Errorf("GetAttr got (%v, %v, %v), wanted (%v, %v, %v)",
   244  				mask, attr, err, localMask, localAttr, localErr)
   245  		}
   246  
   247  		// Ensure we can't walk backwards.
   248  		if _, _, err := f.Walk([]string{"."}); err != unix.EINVAL {
   249  			t.Errorf("Walk through %s/. wanted EINVAL, got %v", name, err)
   250  		}
   251  		if _, _, err := f.Walk([]string{".."}); err != unix.EINVAL {
   252  			t.Errorf("Walk through %s/.. wanted EINVAL, got %v", name, err)
   253  		}
   254  	}
   255  }
   256  
   257  // fileGenerator is a function to generate files via walk or create.
   258  //
   259  // Examples are:
   260  //	- walkHelper
   261  //	- walkAndOpenHelper
   262  //	- createHelper
   263  type fileGenerator func(*Harness, string, p9.File) (*Mock, *Mock, p9.File)
   264  
   265  // walkHelper walks to the given file.
   266  //
   267  // The backends of the parent and walked file are returned, as well as the
   268  // walked client file.
   269  func walkHelper(h *Harness, name string, dir p9.File) (parentBackend *Mock, walkedBackend *Mock, walked p9.File) {
   270  	_, parent, err := dir.Walk(nil)
   271  	if err != nil {
   272  		h.t.Fatalf("Walk(nil) got err %v, want nil", err)
   273  	}
   274  	defer parent.Close()
   275  	parentBackend = h.Pop(parent)
   276  
   277  	_, walked, err = parent.Walk([]string{name})
   278  	if err != nil {
   279  		h.t.Fatalf("Walk(%s) got err %v, want nil", name, err)
   280  	}
   281  	walkedBackend = h.Pop(walked)
   282  
   283  	return parentBackend, walkedBackend, walked
   284  }
   285  
   286  // walkAndOpenHelper additionally opens the walked file, if possible.
   287  func walkAndOpenHelper(h *Harness, name string, dir p9.File) (*Mock, *Mock, p9.File) {
   288  	parentBackend, walkedBackend, walked := walkHelper(h, name, dir)
   289  	if p9.CanOpen(walkedBackend.Attr.Mode) {
   290  		// Open for all file types that we can. We stick to a read-only
   291  		// open here because directories may not be opened otherwise.
   292  		walkedBackend.EXPECT().Open(p9.ReadOnly).Times(1)
   293  		if _, _, _, err := walked.Open(p9.ReadOnly); err != nil {
   294  			h.t.Errorf("got open err %v, want nil", err)
   295  		}
   296  	} else {
   297  		// ... or assert an error for others.
   298  		if _, _, _, err := walked.Open(p9.ReadOnly); err != unix.EINVAL {
   299  			h.t.Errorf("got open err %v, want EINVAL", err)
   300  		}
   301  	}
   302  	return parentBackend, walkedBackend, walked
   303  }
   304  
   305  // createHelper creates the given file and returns the parent directory,
   306  // created file and client file, which must be closed when done.
   307  func createHelper(h *Harness, name string, dir p9.File) (*Mock, *Mock, p9.File) {
   308  	// Clone the directory first, since Create replaces the existing file.
   309  	// We change the type after calling create.
   310  	_, dirThenFile, err := dir.Walk(nil)
   311  	if err != nil {
   312  		h.t.Fatalf("got walk err %v, want nil", err)
   313  	}
   314  
   315  	// Create a new server-side file. On the server-side, the a new file is
   316  	// returned from a create call. The client will reuse the same file,
   317  	// but we still expect the normal chain of closes. This complicates
   318  	// things a bit because the "parent" will always chain to the cloned
   319  	// dir above.
   320  	dirBackend := h.Pop(dirThenFile)   // New backend directory.
   321  	newFile := h.NewFile()(dirBackend) // New file with backend parent.
   322  	dirBackend.EXPECT().Create(name, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, newFile, newFile.QID, uint32(0), nil)
   323  
   324  	// Create via the client.
   325  	_, dirThenFile, _, _, err = dirThenFile.Create(name, p9.ReadOnly, 0, 0, 0)
   326  	if err != nil {
   327  		h.t.Fatalf("got create err %v, want nil", err)
   328  	}
   329  
   330  	// Ensure subsequent walks succeed.
   331  	dirBackend.AddChild(name, h.NewFile())
   332  	return dirBackend, newFile, dirThenFile
   333  }
   334  
   335  // deprecatedRemover allows us to access the deprecated Remove operation within
   336  // the p9.File client object.
   337  type deprecatedRemover interface {
   338  	Remove() error
   339  }
   340  
   341  // checkDeleted asserts that relevant methods fail for an unlinked file.
   342  //
   343  // This function will close the file at the end.
   344  func checkDeleted(h *Harness, file p9.File) {
   345  	defer file.Close() // See doc.
   346  
   347  	if _, _, _, err := file.Open(p9.ReadOnly); err != unix.EINVAL {
   348  		h.t.Errorf("open while deleted, got %v, want EINVAL", err)
   349  	}
   350  	if _, _, _, _, err := file.Create("created", p9.ReadOnly, 0, 0, 0); err != unix.EINVAL {
   351  		h.t.Errorf("create while deleted, got %v, want EINVAL", err)
   352  	}
   353  	if _, err := file.Symlink("old", "new", 0, 0); err != unix.EINVAL {
   354  		h.t.Errorf("symlink while deleted, got %v, want EINVAL", err)
   355  	}
   356  	// N.B. This link is technically invalid, but if a call to link is
   357  	// actually made in the backend then the mock will panic.
   358  	if err := file.Link(file, "new"); err != unix.EINVAL {
   359  		h.t.Errorf("link while deleted, got %v, want EINVAL", err)
   360  	}
   361  	if err := file.RenameAt("src", file, "dst"); err != unix.EINVAL {
   362  		h.t.Errorf("renameAt while deleted, got %v, want EINVAL", err)
   363  	}
   364  	if err := file.UnlinkAt("file", 0); err != unix.EINVAL {
   365  		h.t.Errorf("unlinkAt while deleted, got %v, want EINVAL", err)
   366  	}
   367  	if err := file.Rename(file, "dst"); err != unix.EINVAL {
   368  		h.t.Errorf("rename while deleted, got %v, want EINVAL", err)
   369  	}
   370  	if _, err := file.Readlink(); err != unix.EINVAL {
   371  		h.t.Errorf("readlink while deleted, got %v, want EINVAL", err)
   372  	}
   373  	if _, err := file.Mkdir("dir", p9.ModeDirectory, 0, 0); err != unix.EINVAL {
   374  		h.t.Errorf("mkdir while deleted, got %v, want EINVAL", err)
   375  	}
   376  	if _, err := file.Mknod("dir", p9.ModeDirectory, 0, 0, 0, 0); err != unix.EINVAL {
   377  		h.t.Errorf("mknod while deleted, got %v, want EINVAL", err)
   378  	}
   379  	if _, err := file.Readdir(0, 1); err != unix.EINVAL {
   380  		h.t.Errorf("readdir while deleted, got %v, want EINVAL", err)
   381  	}
   382  	if _, err := file.Connect(p9.ConnectFlags(0)); err != unix.EINVAL {
   383  		h.t.Errorf("connect while deleted, got %v, want EINVAL", err)
   384  	}
   385  
   386  	// The remove method is technically deprecated, but we want to ensure
   387  	// that it still checks for deleted appropriately. We must first clone
   388  	// the file because remove is equivalent to close.
   389  	_, newFile, err := file.Walk(nil)
   390  	if err == unix.EBUSY {
   391  		// We can't walk from here because this reference is open
   392  		// already. Okay, we will also have unopened cases through
   393  		// TestUnlink, just skip the remove operation for now.
   394  		return
   395  	} else if err != nil {
   396  		h.t.Fatalf("clone failed, got %v, want nil", err)
   397  	}
   398  	if err := newFile.(deprecatedRemover).Remove(); err != unix.EINVAL {
   399  		h.t.Errorf("remove while deleted, got %v, want EINVAL", err)
   400  	}
   401  }
   402  
   403  // deleter is a function to remove a file.
   404  type deleter func(parent p9.File, name string) error
   405  
   406  // unlinkAt is a deleter.
   407  func unlinkAt(parent p9.File, name string) error {
   408  	// Call unlink. Note that a filesystem may normally impose additional
   409  	// constaints on unlinkat success, such as ensuring that a directory is
   410  	// empty, requiring AT_REMOVEDIR in flags to remove a directory, etc.
   411  	// None of that is required internally (entire trees can be marked
   412  	// deleted when this operation succeeds), so the mock will succeed.
   413  	return parent.UnlinkAt(name, 0)
   414  }
   415  
   416  // remove is a deleter.
   417  func remove(parent p9.File, name string) error {
   418  	// See notes above re: remove.
   419  	_, newFile, err := parent.Walk([]string{name})
   420  	if err != nil {
   421  		// Should not be expected.
   422  		return err
   423  	}
   424  
   425  	// Do the actual remove.
   426  	if err := newFile.(deprecatedRemover).Remove(); err != nil {
   427  		return err
   428  	}
   429  
   430  	// Ensure that the remove closed the file.
   431  	if err := newFile.(deprecatedRemover).Remove(); err != unix.EBADF {
   432  		return unix.EBADF // Propagate this code.
   433  	}
   434  
   435  	return nil
   436  }
   437  
   438  // unlinkHelper unlinks the noted path, and ensures that all relevant
   439  // operations on that path, acquired from multiple paths, start failing.
   440  func unlinkHelper(h *Harness, root p9.File, targetNames []string, targetGen fileGenerator, deleteFn deleter) {
   441  	// name is the file to be unlinked.
   442  	name := targetNames[len(targetNames)-1]
   443  
   444  	// Walk to the directory containing the target.
   445  	_, parent, err := root.Walk(targetNames[:len(targetNames)-1])
   446  	if err != nil {
   447  		h.t.Fatalf("got walk err %v, want nil", err)
   448  	}
   449  	defer parent.Close()
   450  	parentBackend := h.Pop(parent)
   451  
   452  	// Walk to or generate the target file.
   453  	_, _, target := targetGen(h, name, parent)
   454  	defer checkDeleted(h, target)
   455  
   456  	// Walk to a second reference.
   457  	_, second, err := parent.Walk([]string{name})
   458  	if err != nil {
   459  		h.t.Fatalf("got walk err %v, want nil", err)
   460  	}
   461  	defer checkDeleted(h, second)
   462  
   463  	// Walk to a third reference, from the start.
   464  	_, third, err := root.Walk(targetNames)
   465  	if err != nil {
   466  		h.t.Fatalf("got walk err %v, want nil", err)
   467  	}
   468  	defer checkDeleted(h, third)
   469  
   470  	// This will be translated in the backend to an unlinkat.
   471  	parentBackend.EXPECT().UnlinkAt(name, uint32(0)).Return(nil)
   472  
   473  	// Actually perform the deletion.
   474  	if err := deleteFn(parent, name); err != nil {
   475  		h.t.Fatalf("got delete err %v, want nil", err)
   476  	}
   477  }
   478  
   479  func unlinkTest(t *testing.T, targetNames []string, targetGen fileGenerator) {
   480  	t.Run(fmt.Sprintf("unlinkAt(%s)", strings.Join(targetNames, "/")), func(t *testing.T) {
   481  		h, c := NewHarness(t)
   482  		defer h.Finish()
   483  
   484  		_, root := newRoot(h, c)
   485  		defer root.Close()
   486  
   487  		unlinkHelper(h, root, targetNames, targetGen, unlinkAt)
   488  	})
   489  	t.Run(fmt.Sprintf("remove(%s)", strings.Join(targetNames, "/")), func(t *testing.T) {
   490  		h, c := NewHarness(t)
   491  		defer h.Finish()
   492  
   493  		_, root := newRoot(h, c)
   494  		defer root.Close()
   495  
   496  		unlinkHelper(h, root, targetNames, targetGen, remove)
   497  	})
   498  }
   499  
   500  func TestUnlink(t *testing.T) {
   501  	// Unlink all files.
   502  	for name := range newTypeMap(nil) {
   503  		unlinkTest(t, []string{name}, walkHelper)
   504  		unlinkTest(t, []string{name}, walkAndOpenHelper)
   505  		unlinkTest(t, []string{"one", name}, walkHelper)
   506  		unlinkTest(t, []string{"one", name}, walkAndOpenHelper)
   507  		unlinkTest(t, []string{"one", "two", name}, walkHelper)
   508  		unlinkTest(t, []string{"one", "two", name}, walkAndOpenHelper)
   509  	}
   510  
   511  	// Unlink a directory.
   512  	unlinkTest(t, []string{"one"}, walkHelper)
   513  	unlinkTest(t, []string{"one"}, walkAndOpenHelper)
   514  	unlinkTest(t, []string{"one", "two"}, walkHelper)
   515  	unlinkTest(t, []string{"one", "two"}, walkAndOpenHelper)
   516  
   517  	// Unlink created files.
   518  	unlinkTest(t, []string{"created"}, createHelper)
   519  	unlinkTest(t, []string{"one", "created"}, createHelper)
   520  	unlinkTest(t, []string{"one", "two", "created"}, createHelper)
   521  }
   522  
   523  func TestUnlinkAtInvalid(t *testing.T) {
   524  	h, c := NewHarness(t)
   525  	defer h.Finish()
   526  
   527  	_, root := newRoot(h, c)
   528  	defer root.Close()
   529  
   530  	for name := range newTypeMap(nil) {
   531  		for _, invalidName := range allInvalidNames(name) {
   532  			if err := root.UnlinkAt(invalidName, 0); err != unix.EINVAL {
   533  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
   534  			}
   535  		}
   536  	}
   537  }
   538  
   539  // expectRenamed asserts an ordered sequence of rename calls, based on all the
   540  // elements in elements being the source, and the first element therein
   541  // changing to dstName, parented at dstParent.
   542  func expectRenamed(file *Mock, elements []string, dstParent *Mock, dstName string) *gomock.Call {
   543  	if len(elements) > 0 {
   544  		// Recurse to the parent, if necessary.
   545  		call := expectRenamed(file.parent, elements[:len(elements)-1], dstParent, dstName)
   546  
   547  		// Recursive case: this element is unchanged, but should have
   548  		// it's hook called after the parent.
   549  		return file.EXPECT().Renamed(file.parent, elements[len(elements)-1]).Do(func(p p9.File, _ string) {
   550  			file.parent = p.(*Mock)
   551  		}).After(call)
   552  	}
   553  
   554  	// Base case: this is the changed element.
   555  	return file.EXPECT().Renamed(dstParent, dstName).Do(func(p p9.File, name string) {
   556  		file.parent = p.(*Mock)
   557  	})
   558  }
   559  
   560  // renamer is a rename function.
   561  type renamer func(h *Harness, srcParent, dstParent p9.File, origName, newName string, selfRename bool) error
   562  
   563  // renameAt is a renamer.
   564  func renameAt(_ *Harness, srcParent, dstParent p9.File, srcName, dstName string, selfRename bool) error {
   565  	return srcParent.RenameAt(srcName, dstParent, dstName)
   566  }
   567  
   568  // rename is a renamer.
   569  func rename(h *Harness, srcParent, dstParent p9.File, srcName, dstName string, selfRename bool) error {
   570  	_, f, err := srcParent.Walk([]string{srcName})
   571  	if err != nil {
   572  		return err
   573  	}
   574  	defer f.Close()
   575  	if !selfRename {
   576  		backend := h.Pop(f)
   577  		backend.EXPECT().Renamed(gomock.Any(), dstName).Do(func(p p9.File, name string) {
   578  			backend.parent = p.(*Mock) // Required for close ordering.
   579  		})
   580  	}
   581  	return f.Rename(dstParent, dstName)
   582  }
   583  
   584  // renameHelper executes a rename, and asserts that all relevant elements
   585  // receive expected notifications. If overwriting a file, this includes
   586  // ensuring that the target has been appropriately marked as unlinked.
   587  func renameHelper(h *Harness, root p9.File, srcNames []string, dstNames []string, target fileGenerator, renameFn renamer) {
   588  	// Walk to the directory containing the target.
   589  	srcQID, targetParent, err := root.Walk(srcNames[:len(srcNames)-1])
   590  	if err != nil {
   591  		h.t.Fatalf("got walk err %v, want nil", err)
   592  	}
   593  	defer targetParent.Close()
   594  	targetParentBackend := h.Pop(targetParent)
   595  
   596  	// Walk to or generate the target file.
   597  	_, targetBackend, src := target(h, srcNames[len(srcNames)-1], targetParent)
   598  	defer src.Close()
   599  
   600  	// Walk to a second reference.
   601  	_, second, err := targetParent.Walk([]string{srcNames[len(srcNames)-1]})
   602  	if err != nil {
   603  		h.t.Fatalf("got walk err %v, want nil", err)
   604  	}
   605  	defer second.Close()
   606  	secondBackend := h.Pop(second)
   607  
   608  	// Walk to a third reference, from the start.
   609  	_, third, err := root.Walk(srcNames)
   610  	if err != nil {
   611  		h.t.Fatalf("got walk err %v, want nil", err)
   612  	}
   613  	defer third.Close()
   614  	thirdBackend := h.Pop(third)
   615  
   616  	// Find the common suffix to identify the rename parent.
   617  	var (
   618  		renameDestPath []string
   619  		renameSrcPath  []string
   620  		selfRename     bool
   621  	)
   622  	for i := 1; i <= len(srcNames) && i <= len(dstNames); i++ {
   623  		if srcNames[len(srcNames)-i] != dstNames[len(dstNames)-i] {
   624  			// Take the full prefix of dstNames up until this
   625  			// point, including the first mismatched name. The
   626  			// first mismatch must be the renamed entry.
   627  			renameDestPath = dstNames[:len(dstNames)-i+1]
   628  			renameSrcPath = srcNames[:len(srcNames)-i+1]
   629  
   630  			// Does the renameDestPath fully contain the
   631  			// renameSrcPath here? If yes, then this is a mismatch.
   632  			// We can't rename the src to some subpath of itself.
   633  			if len(renameDestPath) > len(renameSrcPath) &&
   634  				reflect.DeepEqual(renameDestPath[:len(renameSrcPath)], renameSrcPath) {
   635  				renameDestPath = nil
   636  				renameSrcPath = nil
   637  				continue
   638  			}
   639  			break
   640  		}
   641  	}
   642  	if len(renameSrcPath) == 0 || len(renameDestPath) == 0 {
   643  		// This must be a rename to self, or a tricky look-alike. This
   644  		// happens iff we fail to find a suitable divergence in the two
   645  		// paths. It's a true self move if the path length is the same.
   646  		renameDestPath = dstNames
   647  		renameSrcPath = srcNames
   648  		selfRename = len(srcNames) == len(dstNames)
   649  	}
   650  
   651  	// Walk to the source parent.
   652  	_, srcParent, err := root.Walk(renameSrcPath[:len(renameSrcPath)-1])
   653  	if err != nil {
   654  		h.t.Fatalf("got walk err %v, want nil", err)
   655  	}
   656  	defer srcParent.Close()
   657  	srcParentBackend := h.Pop(srcParent)
   658  
   659  	// Walk to the destination parent.
   660  	_, dstParent, err := root.Walk(renameDestPath[:len(renameDestPath)-1])
   661  	if err != nil {
   662  		h.t.Fatalf("got walk err %v, want nil", err)
   663  	}
   664  	defer dstParent.Close()
   665  	dstParentBackend := h.Pop(dstParent)
   666  
   667  	// expectedErr is the result of the rename operation.
   668  	var expectedErr error
   669  
   670  	// Walk to the target file, if one exists.
   671  	dstQID, dst, err := root.Walk(renameDestPath)
   672  	if err == nil {
   673  		if !selfRename && srcQID[0].Type == dstQID[0].Type {
   674  			// If there is a destination file, and is it of the
   675  			// same type as the source file, then we expect the
   676  			// rename to succeed. We expect the destination file to
   677  			// be deleted, so we run a deletion test on it in this
   678  			// case.
   679  			defer checkDeleted(h, dst)
   680  		} else {
   681  			// If the type is different than the destination, then
   682  			// we expect the rename to fail. We expect that this
   683  			// is returned.
   684  			//
   685  			// If the file being renamed to itself, this is
   686  			// technically allowed and a no-op, but all the
   687  			// triggers will fire.
   688  			if !selfRename {
   689  				expectedErr = unix.EINVAL
   690  			}
   691  			dst.Close()
   692  		}
   693  	}
   694  	dstName := renameDestPath[len(renameDestPath)-1] // Renamed element.
   695  	srcName := renameSrcPath[len(renameSrcPath)-1]   // Renamed element.
   696  	if expectedErr == nil && !selfRename {
   697  		// Expect all to be renamed appropriately. Note that if this is
   698  		// a final file being renamed, then we expect the file to be
   699  		// called with the new parent. If not, then we expect the
   700  		// rename hook to be called, but the parent will remain
   701  		// unchanged.
   702  		elements := srcNames[len(renameSrcPath):]
   703  		expectRenamed(targetBackend, elements, dstParentBackend, dstName)
   704  		expectRenamed(secondBackend, elements, dstParentBackend, dstName)
   705  		expectRenamed(thirdBackend, elements, dstParentBackend, dstName)
   706  
   707  		// The target parent has also been opened, and may be moved
   708  		// directly or indirectly.
   709  		if len(elements) > 1 {
   710  			expectRenamed(targetParentBackend, elements[:len(elements)-1], dstParentBackend, dstName)
   711  		}
   712  	}
   713  
   714  	// Expect the rename if it's not the same file. Note that like unlink,
   715  	// renames are always translated to the at variant in the backend.
   716  	if !selfRename {
   717  		srcParentBackend.EXPECT().RenameAt(srcName, dstParentBackend, dstName).Return(expectedErr)
   718  	}
   719  
   720  	// Perform the actual rename; everything has been lined up.
   721  	if err := renameFn(h, srcParent, dstParent, srcName, dstName, selfRename); err != expectedErr {
   722  		h.t.Fatalf("got rename err %v, want %v", err, expectedErr)
   723  	}
   724  }
   725  
   726  func renameTest(t *testing.T, srcNames []string, dstNames []string, target fileGenerator) {
   727  	t.Run(fmt.Sprintf("renameAt(%s->%s)", strings.Join(srcNames, "/"), strings.Join(dstNames, "/")), func(t *testing.T) {
   728  		h, c := NewHarness(t)
   729  		defer h.Finish()
   730  
   731  		_, root := newRoot(h, c)
   732  		defer root.Close()
   733  
   734  		renameHelper(h, root, srcNames, dstNames, target, renameAt)
   735  	})
   736  	t.Run(fmt.Sprintf("rename(%s->%s)", strings.Join(srcNames, "/"), strings.Join(dstNames, "/")), func(t *testing.T) {
   737  		h, c := NewHarness(t)
   738  		defer h.Finish()
   739  
   740  		_, root := newRoot(h, c)
   741  		defer root.Close()
   742  
   743  		renameHelper(h, root, srcNames, dstNames, target, rename)
   744  	})
   745  }
   746  
   747  func TestRename(t *testing.T) {
   748  	// In-directory rename, simple case.
   749  	for name := range newTypeMap(nil) {
   750  		// Within the root.
   751  		renameTest(t, []string{name}, []string{"renamed"}, walkHelper)
   752  		renameTest(t, []string{name}, []string{"renamed"}, walkAndOpenHelper)
   753  
   754  		// Within a subdirectory.
   755  		renameTest(t, []string{"one", name}, []string{"one", "renamed"}, walkHelper)
   756  		renameTest(t, []string{"one", name}, []string{"one", "renamed"}, walkAndOpenHelper)
   757  	}
   758  
   759  	// ... with created files.
   760  	renameTest(t, []string{"created"}, []string{"renamed"}, createHelper)
   761  	renameTest(t, []string{"one", "created"}, []string{"one", "renamed"}, createHelper)
   762  
   763  	// Across directories.
   764  	for name := range newTypeMap(nil) {
   765  		// Down one level.
   766  		renameTest(t, []string{"one", name}, []string{"one", "two", "renamed"}, walkHelper)
   767  		renameTest(t, []string{"one", name}, []string{"one", "two", "renamed"}, walkAndOpenHelper)
   768  
   769  		// Up one level.
   770  		renameTest(t, []string{"one", "two", name}, []string{"one", "renamed"}, walkHelper)
   771  		renameTest(t, []string{"one", "two", name}, []string{"one", "renamed"}, walkAndOpenHelper)
   772  
   773  		// Across at the same level.
   774  		renameTest(t, []string{"one", name}, []string{"three", "renamed"}, walkHelper)
   775  		renameTest(t, []string{"one", name}, []string{"three", "renamed"}, walkAndOpenHelper)
   776  	}
   777  
   778  	// ... with created files.
   779  	renameTest(t, []string{"one", "created"}, []string{"one", "two", "renamed"}, createHelper)
   780  	renameTest(t, []string{"one", "two", "created"}, []string{"one", "renamed"}, createHelper)
   781  	renameTest(t, []string{"one", "created"}, []string{"three", "renamed"}, createHelper)
   782  
   783  	// Renaming parents.
   784  	for name := range newTypeMap(nil) {
   785  		// Rename a parent.
   786  		renameTest(t, []string{"one", name}, []string{"renamed", name}, walkHelper)
   787  		renameTest(t, []string{"one", name}, []string{"renamed", name}, walkAndOpenHelper)
   788  
   789  		// Rename a super parent.
   790  		renameTest(t, []string{"one", "two", name}, []string{"renamed", name}, walkHelper)
   791  		renameTest(t, []string{"one", "two", name}, []string{"renamed", name}, walkAndOpenHelper)
   792  	}
   793  
   794  	// ... with created files.
   795  	renameTest(t, []string{"one", "created"}, []string{"renamed", "created"}, createHelper)
   796  	renameTest(t, []string{"one", "two", "created"}, []string{"renamed", "created"}, createHelper)
   797  
   798  	// Over existing files, including itself.
   799  	for name := range newTypeMap(nil) {
   800  		for other := range newTypeMap(nil) {
   801  			// Overwrite the noted file (may be itself).
   802  			renameTest(t, []string{"one", name}, []string{"one", other}, walkHelper)
   803  			renameTest(t, []string{"one", name}, []string{"one", other}, walkAndOpenHelper)
   804  
   805  			// Overwrite other files in another directory.
   806  			renameTest(t, []string{"one", name}, []string{"one", "two", other}, walkHelper)
   807  			renameTest(t, []string{"one", name}, []string{"one", "two", other}, walkAndOpenHelper)
   808  		}
   809  
   810  		// Overwrite by moving the parent.
   811  		renameTest(t, []string{"three", name}, []string{"one", name}, walkHelper)
   812  		renameTest(t, []string{"three", name}, []string{"one", name}, walkAndOpenHelper)
   813  
   814  		// Create over the types.
   815  		renameTest(t, []string{"one", "created"}, []string{"one", name}, createHelper)
   816  		renameTest(t, []string{"one", "created"}, []string{"one", "two", name}, createHelper)
   817  		renameTest(t, []string{"three", "created"}, []string{"one", name}, createHelper)
   818  	}
   819  }
   820  
   821  func TestRenameInvalid(t *testing.T) {
   822  	h, c := NewHarness(t)
   823  	defer h.Finish()
   824  
   825  	_, root := newRoot(h, c)
   826  	defer root.Close()
   827  
   828  	for name := range newTypeMap(nil) {
   829  		for _, invalidName := range allInvalidNames(name) {
   830  			if err := root.Rename(root, invalidName); err != unix.EINVAL {
   831  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
   832  			}
   833  		}
   834  	}
   835  }
   836  
   837  func TestRenameAtInvalid(t *testing.T) {
   838  	h, c := NewHarness(t)
   839  	defer h.Finish()
   840  
   841  	_, root := newRoot(h, c)
   842  	defer root.Close()
   843  
   844  	for name := range newTypeMap(nil) {
   845  		for _, invalidName := range allInvalidNames(name) {
   846  			if err := root.RenameAt(invalidName, root, "okay"); err != unix.EINVAL {
   847  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
   848  			}
   849  			if err := root.RenameAt("okay", root, invalidName); err != unix.EINVAL {
   850  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
   851  			}
   852  		}
   853  	}
   854  }
   855  
   856  // TestRenameSecondOrder tests that indirect rename targets continue to receive
   857  // Renamed calls after a rename of its renamed parent. i.e.,
   858  //
   859  // 1. Create /one/file
   860  // 2. Create /directory
   861  // 3. Rename /one -> /directory/one
   862  // 4. Rename /directory -> /three/foo
   863  // 5. file from (1) should still receive Renamed.
   864  //
   865  // This is a regression test for b/135219260.
   866  func TestRenameSecondOrder(t *testing.T) {
   867  	h, c := NewHarness(t)
   868  	defer h.Finish()
   869  
   870  	rootBackend, root := newRoot(h, c)
   871  	defer root.Close()
   872  
   873  	// Walk to /one.
   874  	_, oneBackend, oneFile := walkHelper(h, "one", root)
   875  	defer oneFile.Close()
   876  
   877  	// Walk to and generate /one/file.
   878  	//
   879  	// walkHelper re-walks to oneFile, so we need the second backend,
   880  	// which will also receive Renamed calls.
   881  	oneSecondBackend, fileBackend, fileFile := walkHelper(h, "file", oneFile)
   882  	defer fileFile.Close()
   883  
   884  	// Walk to and generate /directory.
   885  	_, directoryBackend, directoryFile := walkHelper(h, "directory", root)
   886  	defer directoryFile.Close()
   887  
   888  	// Rename /one to /directory/one.
   889  	rootBackend.EXPECT().RenameAt("one", directoryBackend, "one").Return(nil)
   890  	expectRenamed(oneBackend, []string{}, directoryBackend, "one")
   891  	expectRenamed(oneSecondBackend, []string{}, directoryBackend, "one")
   892  	expectRenamed(fileBackend, []string{}, oneBackend, "file")
   893  	if err := renameAt(h, root, directoryFile, "one", "one", false); err != nil {
   894  		h.t.Fatalf("got rename err %v, want nil", err)
   895  	}
   896  
   897  	// Walk to /three.
   898  	_, threeBackend, threeFile := walkHelper(h, "three", root)
   899  	defer threeFile.Close()
   900  
   901  	// Rename /directory to /three/foo.
   902  	rootBackend.EXPECT().RenameAt("directory", threeBackend, "foo").Return(nil)
   903  	expectRenamed(directoryBackend, []string{}, threeBackend, "foo")
   904  	expectRenamed(oneBackend, []string{}, directoryBackend, "one")
   905  	expectRenamed(oneSecondBackend, []string{}, directoryBackend, "one")
   906  	expectRenamed(fileBackend, []string{}, oneBackend, "file")
   907  	if err := renameAt(h, root, threeFile, "directory", "foo", false); err != nil {
   908  		h.t.Fatalf("got rename err %v, want nil", err)
   909  	}
   910  }
   911  
   912  func TestReadlink(t *testing.T) {
   913  	for name := range newTypeMap(nil) {
   914  		t.Run(name, func(t *testing.T) {
   915  			h, c := NewHarness(t)
   916  			defer h.Finish()
   917  
   918  			_, root := newRoot(h, c)
   919  			defer root.Close()
   920  
   921  			// Walk to the file normally.
   922  			_, f, err := root.Walk([]string{name})
   923  			if err != nil {
   924  				t.Fatalf("walk failed: got %v, wanted nil", err)
   925  			}
   926  			defer f.Close()
   927  			backend := h.Pop(f)
   928  
   929  			const symlinkTarget = "symlink-target"
   930  
   931  			if backend.Attr.Mode.IsSymlink() {
   932  				// This should only go through on symlinks.
   933  				backend.EXPECT().Readlink().Return(symlinkTarget, nil)
   934  			}
   935  
   936  			// Attempt a Readlink operation.
   937  			target, err := f.Readlink()
   938  			if err != nil && err != unix.EINVAL {
   939  				t.Errorf("readlink got %v, wanted EINVAL", err)
   940  			} else if err == nil && target != symlinkTarget {
   941  				t.Errorf("readlink got %v, wanted %v", target, symlinkTarget)
   942  			}
   943  		})
   944  	}
   945  }
   946  
   947  // fdTest is a wrapper around operations that may send file descriptors. This
   948  // asserts that the file descriptors are working as intended.
   949  func fdTest(t *testing.T, sendFn func(*fd.FD) *fd.FD) {
   950  	// Create a pipe that we can read from.
   951  	r, w, err := os.Pipe()
   952  	if err != nil {
   953  		t.Fatalf("unable to create pipe: %v", err)
   954  	}
   955  	defer r.Close()
   956  	defer w.Close()
   957  
   958  	// Attempt to send the write end.
   959  	wFD, err := fd.NewFromFile(w)
   960  	if err != nil {
   961  		t.Fatalf("unable to convert file: %v", err)
   962  	}
   963  	defer wFD.Close() // This is a copy.
   964  
   965  	// Send wFD and receive newFD.
   966  	newFD := sendFn(wFD)
   967  	defer newFD.Close()
   968  
   969  	// Attempt to write.
   970  	const message = "hello"
   971  	if _, err := newFD.Write([]byte(message)); err != nil {
   972  		t.Fatalf("write got %v, wanted nil", err)
   973  	}
   974  
   975  	// Should see the message on our end.
   976  	buffer := []byte(message)
   977  	if _, err := io.ReadFull(r, buffer); err != nil {
   978  		t.Fatalf("read got %v, wanted nil", err)
   979  	}
   980  	if string(buffer) != message {
   981  		t.Errorf("got message %v, wanted %v", string(buffer), message)
   982  	}
   983  }
   984  
   985  func TestConnect(t *testing.T) {
   986  	for name := range newTypeMap(nil) {
   987  		t.Run(name, func(t *testing.T) {
   988  			h, c := NewHarness(t)
   989  			defer h.Finish()
   990  
   991  			_, root := newRoot(h, c)
   992  			defer root.Close()
   993  
   994  			// Walk to the file normally.
   995  			_, backend, f := walkHelper(h, name, root)
   996  			defer f.Close()
   997  
   998  			// Catch all the non-socket cases.
   999  			if !backend.Attr.Mode.IsSocket() {
  1000  				// This has been set up to fail if Connect is called.
  1001  				if _, err := f.Connect(p9.ConnectFlags(0)); err != unix.EINVAL {
  1002  					t.Errorf("connect got %v, wanted EINVAL", err)
  1003  				}
  1004  				return
  1005  			}
  1006  
  1007  			// Ensure the fd exchange works.
  1008  			fdTest(t, func(send *fd.FD) *fd.FD {
  1009  				backend.EXPECT().Connect(p9.ConnectFlags(0)).Return(send, nil)
  1010  				recv, err := backend.Connect(p9.ConnectFlags(0))
  1011  				if err != nil {
  1012  					t.Fatalf("connect got %v, wanted nil", err)
  1013  				}
  1014  				return recv
  1015  			})
  1016  		})
  1017  	}
  1018  }
  1019  
  1020  func TestReaddir(t *testing.T) {
  1021  	for name := range newTypeMap(nil) {
  1022  		t.Run(name, func(t *testing.T) {
  1023  			h, c := NewHarness(t)
  1024  			defer h.Finish()
  1025  
  1026  			_, root := newRoot(h, c)
  1027  			defer root.Close()
  1028  
  1029  			// Walk to the file normally.
  1030  			_, backend, f := walkHelper(h, name, root)
  1031  			defer f.Close()
  1032  
  1033  			// Catch all the non-directory cases.
  1034  			if !backend.Attr.Mode.IsDir() {
  1035  				// This has also been set up to fail if Readdir is called.
  1036  				if _, err := f.Readdir(0, 1); err != unix.EINVAL {
  1037  					t.Errorf("readdir got %v, wanted EINVAL", err)
  1038  				}
  1039  				return
  1040  			}
  1041  
  1042  			// Ensure that readdir works for directories.
  1043  			if _, err := f.Readdir(0, 1); err != unix.EINVAL {
  1044  				t.Errorf("readdir got %v, wanted EINVAL", err)
  1045  			}
  1046  			if _, _, _, err := f.Open(p9.ReadWrite); err != unix.EISDIR {
  1047  				t.Errorf("readdir got %v, wanted EISDIR", err)
  1048  			}
  1049  			if _, _, _, err := f.Open(p9.WriteOnly); err != unix.EISDIR {
  1050  				t.Errorf("readdir got %v, wanted EISDIR", err)
  1051  			}
  1052  			backend.EXPECT().Open(p9.ReadOnly).Times(1)
  1053  			if _, _, _, err := f.Open(p9.ReadOnly); err != nil {
  1054  				t.Errorf("readdir got %v, wanted nil", err)
  1055  			}
  1056  			backend.EXPECT().Readdir(uint64(0), uint32(1)).Times(1)
  1057  			if _, err := f.Readdir(0, 1); err != nil {
  1058  				t.Errorf("readdir got %v, wanted nil", err)
  1059  			}
  1060  		})
  1061  	}
  1062  }
  1063  
  1064  func TestOpen(t *testing.T) {
  1065  	type openTest struct {
  1066  		name  string
  1067  		flags p9.OpenFlags
  1068  		err   error
  1069  		match func(p9.FileMode) bool
  1070  	}
  1071  
  1072  	cases := []openTest{
  1073  		{
  1074  			name:  "not-openable-read-only",
  1075  			flags: p9.ReadOnly,
  1076  			err:   unix.EINVAL,
  1077  			match: func(mode p9.FileMode) bool { return !p9.CanOpen(mode) },
  1078  		},
  1079  		{
  1080  			name:  "not-openable-write-only",
  1081  			flags: p9.WriteOnly,
  1082  			err:   unix.EINVAL,
  1083  			match: func(mode p9.FileMode) bool { return !p9.CanOpen(mode) },
  1084  		},
  1085  		{
  1086  			name:  "not-openable-read-write",
  1087  			flags: p9.ReadWrite,
  1088  			err:   unix.EINVAL,
  1089  			match: func(mode p9.FileMode) bool { return !p9.CanOpen(mode) },
  1090  		},
  1091  		{
  1092  			name:  "directory-read-only",
  1093  			flags: p9.ReadOnly,
  1094  			err:   nil,
  1095  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1096  		},
  1097  		{
  1098  			name:  "directory-read-write",
  1099  			flags: p9.ReadWrite,
  1100  			err:   unix.EISDIR,
  1101  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1102  		},
  1103  		{
  1104  			name:  "directory-write-only",
  1105  			flags: p9.WriteOnly,
  1106  			err:   unix.EISDIR,
  1107  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1108  		},
  1109  		{
  1110  			name:  "read-only",
  1111  			flags: p9.ReadOnly,
  1112  			err:   nil,
  1113  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) },
  1114  		},
  1115  		{
  1116  			name:  "write-only",
  1117  			flags: p9.WriteOnly,
  1118  			err:   nil,
  1119  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) && !mode.IsDir() },
  1120  		},
  1121  		{
  1122  			name:  "read-write",
  1123  			flags: p9.ReadWrite,
  1124  			err:   nil,
  1125  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) && !mode.IsDir() },
  1126  		},
  1127  		{
  1128  			name:  "directory-read-only-truncate",
  1129  			flags: p9.ReadOnly | p9.OpenTruncate,
  1130  			err:   unix.EISDIR,
  1131  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1132  		},
  1133  		{
  1134  			name:  "read-only-truncate",
  1135  			flags: p9.ReadOnly | p9.OpenTruncate,
  1136  			err:   nil,
  1137  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) && !mode.IsDir() },
  1138  		},
  1139  		{
  1140  			name:  "write-only-truncate",
  1141  			flags: p9.WriteOnly | p9.OpenTruncate,
  1142  			err:   nil,
  1143  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) && !mode.IsDir() },
  1144  		},
  1145  		{
  1146  			name:  "read-write-truncate",
  1147  			flags: p9.ReadWrite | p9.OpenTruncate,
  1148  			err:   nil,
  1149  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) && !mode.IsDir() },
  1150  		},
  1151  	}
  1152  
  1153  	// Open(flags OpenFlags) (*fd.FD, QID, uint32, error)
  1154  	// - only works on Regular, NamedPipe, BLockDevice, CharacterDevice
  1155  	// - returning a file works as expected
  1156  	for name := range newTypeMap(nil) {
  1157  		for _, tc := range cases {
  1158  			t.Run(fmt.Sprintf("%s-%s", tc.name, name), func(t *testing.T) {
  1159  				h, c := NewHarness(t)
  1160  				defer h.Finish()
  1161  
  1162  				_, root := newRoot(h, c)
  1163  				defer root.Close()
  1164  
  1165  				// Walk to the file normally.
  1166  				_, backend, f := walkHelper(h, name, root)
  1167  				defer f.Close()
  1168  
  1169  				// Does this match the case?
  1170  				if !tc.match(backend.Attr.Mode) {
  1171  					t.SkipNow()
  1172  				}
  1173  
  1174  				// Ensure open-required operations fail.
  1175  				if _, err := f.ReadAt([]byte("hello"), 0); err != unix.EINVAL {
  1176  					t.Errorf("readAt got %v, wanted EINVAL", err)
  1177  				}
  1178  				if _, err := f.WriteAt(make([]byte, 6), 0); err != unix.EINVAL {
  1179  					t.Errorf("writeAt got %v, wanted EINVAL", err)
  1180  				}
  1181  				if err := f.FSync(); err != unix.EINVAL {
  1182  					t.Errorf("fsync got %v, wanted EINVAL", err)
  1183  				}
  1184  				if _, err := f.Readdir(0, 1); err != unix.EINVAL {
  1185  					t.Errorf("readdir got %v, wanted EINVAL", err)
  1186  				}
  1187  
  1188  				// Attempt the given open.
  1189  				if tc.err != nil {
  1190  					// We expect an error, just test and return.
  1191  					if _, _, _, err := f.Open(tc.flags); err != tc.err {
  1192  						t.Fatalf("open with flags %v got %v, want %v", tc.flags, err, tc.err)
  1193  					}
  1194  					return
  1195  				}
  1196  
  1197  				// Run an FD test, since we expect success.
  1198  				fdTest(t, func(send *fd.FD) *fd.FD {
  1199  					backend.EXPECT().Open(tc.flags).Return(send, p9.QID{}, uint32(0), nil).Times(1)
  1200  					recv, _, _, err := f.Open(tc.flags)
  1201  					if err != tc.err {
  1202  						t.Fatalf("open with flags %v got %v, want %v", tc.flags, err, tc.err)
  1203  					}
  1204  					return recv
  1205  				})
  1206  
  1207  				// If the open was successful, attempt another one.
  1208  				if _, _, _, err := f.Open(tc.flags); err != unix.EINVAL {
  1209  					t.Errorf("second open with flags %v got %v, want EINVAL", tc.flags, err)
  1210  				}
  1211  
  1212  				// Ensure that all illegal operations fail.
  1213  				if _, _, err := f.Walk(nil); err != unix.EINVAL && err != unix.EBUSY {
  1214  					t.Errorf("walk got %v, wanted EINVAL or EBUSY", err)
  1215  				}
  1216  				if _, _, _, _, err := f.WalkGetAttr(nil); err != unix.EINVAL && err != unix.EBUSY {
  1217  					t.Errorf("walkgetattr got %v, wanted EINVAL or EBUSY", err)
  1218  				}
  1219  			})
  1220  		}
  1221  	}
  1222  }
  1223  
  1224  func TestClose(t *testing.T) {
  1225  	type closeTest struct {
  1226  		name    string
  1227  		closeFn func(backend *Mock, f p9.File) error
  1228  	}
  1229  
  1230  	cases := []closeTest{
  1231  		{
  1232  			name: "close",
  1233  			closeFn: func(_ *Mock, f p9.File) error {
  1234  				return f.Close()
  1235  			},
  1236  		},
  1237  		{
  1238  			name: "remove",
  1239  			closeFn: func(backend *Mock, f p9.File) error {
  1240  				// Allow the rename call in the parent, automatically translated.
  1241  				backend.parent.EXPECT().UnlinkAt(gomock.Any(), gomock.Any()).Times(1)
  1242  				return f.(deprecatedRemover).Remove()
  1243  			},
  1244  		},
  1245  		{
  1246  			name: "setAttrClose",
  1247  			closeFn: func(backend *Mock, f p9.File) error {
  1248  				valid := p9.SetAttrMask{ATime: true}
  1249  				attr := p9.SetAttr{ATimeSeconds: 1, ATimeNanoSeconds: 2}
  1250  				backend.EXPECT().SetAttr(valid, attr).Times(1)
  1251  				return f.SetAttrClose(valid, attr)
  1252  			},
  1253  		},
  1254  	}
  1255  
  1256  	for name := range newTypeMap(nil) {
  1257  		for _, tc := range cases {
  1258  			t.Run(fmt.Sprintf("%s(%s)", tc.name, name), func(t *testing.T) {
  1259  				h, c := NewHarness(t)
  1260  				defer h.Finish()
  1261  
  1262  				_, root := newRoot(h, c)
  1263  				defer root.Close()
  1264  
  1265  				// Walk to the file normally.
  1266  				_, backend, f := walkHelper(h, name, root)
  1267  
  1268  				// Close via the prescribed method.
  1269  				if err := tc.closeFn(backend, f); err != nil {
  1270  					t.Fatalf("closeFn failed: %v", err)
  1271  				}
  1272  
  1273  				// Everything should fail with EBADF.
  1274  				if _, _, err := f.Walk(nil); err != unix.EBADF {
  1275  					t.Errorf("walk got %v, wanted EBADF", err)
  1276  				}
  1277  				if _, err := f.StatFS(); err != unix.EBADF {
  1278  					t.Errorf("statfs got %v, wanted EBADF", err)
  1279  				}
  1280  				if _, _, _, err := f.GetAttr(p9.AttrMaskAll()); err != unix.EBADF {
  1281  					t.Errorf("getattr got %v, wanted EBADF", err)
  1282  				}
  1283  				if err := f.SetAttr(p9.SetAttrMask{}, p9.SetAttr{}); err != unix.EBADF {
  1284  					t.Errorf("setattrk got %v, wanted EBADF", err)
  1285  				}
  1286  				if err := f.Rename(root, "new-name"); err != unix.EBADF {
  1287  					t.Errorf("rename got %v, wanted EBADF", err)
  1288  				}
  1289  				if err := f.Close(); err != unix.EBADF {
  1290  					t.Errorf("close got %v, wanted EBADF", err)
  1291  				}
  1292  				if _, _, _, err := f.Open(p9.ReadOnly); err != unix.EBADF {
  1293  					t.Errorf("open got %v, wanted EBADF", err)
  1294  				}
  1295  				if _, err := f.ReadAt([]byte("hello"), 0); err != unix.EBADF {
  1296  					t.Errorf("readAt got %v, wanted EBADF", err)
  1297  				}
  1298  				if _, err := f.WriteAt(make([]byte, 6), 0); err != unix.EBADF {
  1299  					t.Errorf("writeAt got %v, wanted EBADF", err)
  1300  				}
  1301  				if err := f.FSync(); err != unix.EBADF {
  1302  					t.Errorf("fsync got %v, wanted EBADF", err)
  1303  				}
  1304  				if _, _, _, _, err := f.Create("new-file", p9.ReadWrite, 0, 0, 0); err != unix.EBADF {
  1305  					t.Errorf("create got %v, wanted EBADF", err)
  1306  				}
  1307  				if _, err := f.Mkdir("new-directory", 0, 0, 0); err != unix.EBADF {
  1308  					t.Errorf("mkdir got %v, wanted EBADF", err)
  1309  				}
  1310  				if _, err := f.Symlink("old-name", "new-name", 0, 0); err != unix.EBADF {
  1311  					t.Errorf("symlink got %v, wanted EBADF", err)
  1312  				}
  1313  				if err := f.Link(root, "new-name"); err != unix.EBADF {
  1314  					t.Errorf("link got %v, wanted EBADF", err)
  1315  				}
  1316  				if _, err := f.Mknod("new-block-device", 0, 0, 0, 0, 0); err != unix.EBADF {
  1317  					t.Errorf("mknod got %v, wanted EBADF", err)
  1318  				}
  1319  				if err := f.RenameAt("old-name", root, "new-name"); err != unix.EBADF {
  1320  					t.Errorf("renameAt got %v, wanted EBADF", err)
  1321  				}
  1322  				if err := f.UnlinkAt("name", 0); err != unix.EBADF {
  1323  					t.Errorf("unlinkAt got %v, wanted EBADF", err)
  1324  				}
  1325  				if _, err := f.Readdir(0, 1); err != unix.EBADF {
  1326  					t.Errorf("readdir got %v, wanted EBADF", err)
  1327  				}
  1328  				if _, err := f.Readlink(); err != unix.EBADF {
  1329  					t.Errorf("readlink got %v, wanted EBADF", err)
  1330  				}
  1331  				if err := f.Flush(); err != unix.EBADF {
  1332  					t.Errorf("flush got %v, wanted EBADF", err)
  1333  				}
  1334  				if _, _, _, _, err := f.WalkGetAttr(nil); err != unix.EBADF {
  1335  					t.Errorf("walkgetattr got %v, wanted EBADF", err)
  1336  				}
  1337  				if _, err := f.Connect(p9.ConnectFlags(0)); err != unix.EBADF {
  1338  					t.Errorf("connect got %v, wanted EBADF", err)
  1339  				}
  1340  			})
  1341  		}
  1342  	}
  1343  }
  1344  
  1345  // onlyWorksOnOpenThings is a helper test method for operations that should
  1346  // only work on files that have been explicitly opened.
  1347  func onlyWorksOnOpenThings(h *Harness, t *testing.T, name string, root p9.File, mode p9.OpenFlags, expectedErr error, fn func(backend *Mock, f p9.File, shouldSucceed bool) error) {
  1348  	// Walk to the file normally.
  1349  	_, backend, f := walkHelper(h, name, root)
  1350  	defer f.Close()
  1351  
  1352  	// Does it work before opening?
  1353  	if err := fn(backend, f, false); err != unix.EINVAL {
  1354  		t.Errorf("operation got %v, wanted EINVAL", err)
  1355  	}
  1356  
  1357  	// Is this openable?
  1358  	if !p9.CanOpen(backend.Attr.Mode) {
  1359  		return // Nothing to do.
  1360  	}
  1361  
  1362  	// If this is a directory, we can't handle writing.
  1363  	if backend.Attr.Mode.IsDir() && (mode == p9.ReadWrite || mode == p9.WriteOnly) {
  1364  		return // Skip.
  1365  	}
  1366  
  1367  	// Open the file.
  1368  	backend.EXPECT().Open(mode)
  1369  	if _, _, _, err := f.Open(mode); err != nil {
  1370  		t.Fatalf("open got %v, wanted nil", err)
  1371  	}
  1372  
  1373  	// Attempt the operation.
  1374  	if err := fn(backend, f, expectedErr == nil); err != expectedErr {
  1375  		t.Fatalf("operation got %v, wanted %v", err, expectedErr)
  1376  	}
  1377  }
  1378  
  1379  func TestRead(t *testing.T) {
  1380  	type readTest struct {
  1381  		name string
  1382  		mode p9.OpenFlags
  1383  		err  error
  1384  	}
  1385  
  1386  	cases := []readTest{
  1387  		{
  1388  			name: "read-only",
  1389  			mode: p9.ReadOnly,
  1390  			err:  nil,
  1391  		},
  1392  		{
  1393  			name: "read-write",
  1394  			mode: p9.ReadWrite,
  1395  			err:  nil,
  1396  		},
  1397  		{
  1398  			name: "write-only",
  1399  			mode: p9.WriteOnly,
  1400  			err:  unix.EPERM,
  1401  		},
  1402  	}
  1403  
  1404  	for name := range newTypeMap(nil) {
  1405  		for _, tc := range cases {
  1406  			t.Run(fmt.Sprintf("%s-%s", tc.name, name), func(t *testing.T) {
  1407  				h, c := NewHarness(t)
  1408  				defer h.Finish()
  1409  
  1410  				_, root := newRoot(h, c)
  1411  				defer root.Close()
  1412  
  1413  				const message = "hello"
  1414  
  1415  				onlyWorksOnOpenThings(h, t, name, root, tc.mode, tc.err, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1416  					if !shouldSucceed {
  1417  						_, err := f.ReadAt([]byte(message), 0)
  1418  						return err
  1419  					}
  1420  
  1421  					// Prepare for the call to readAt in the backend.
  1422  					backend.EXPECT().ReadAt(gomock.Any(), uint64(0)).Do(func(p []byte, offset uint64) {
  1423  						copy(p, message)
  1424  					}).Return(len(message), nil)
  1425  
  1426  					// Make the client call.
  1427  					p := make([]byte, 2*len(message)) // Double size.
  1428  					n, err := f.ReadAt(p, 0)
  1429  
  1430  					// Sanity check result.
  1431  					if err != nil {
  1432  						return err
  1433  					}
  1434  					if n != len(message) {
  1435  						t.Fatalf("message length incorrect, got %d, want %d", n, len(message))
  1436  					}
  1437  					if !bytes.Equal(p[:n], []byte(message)) {
  1438  						t.Fatalf("message incorrect, got %v, want %v", p, []byte(message))
  1439  					}
  1440  					return nil // Success.
  1441  				})
  1442  			})
  1443  		}
  1444  	}
  1445  }
  1446  
  1447  func TestWrite(t *testing.T) {
  1448  	type writeTest struct {
  1449  		name string
  1450  		mode p9.OpenFlags
  1451  		err  error
  1452  	}
  1453  
  1454  	cases := []writeTest{
  1455  		{
  1456  			name: "read-only",
  1457  			mode: p9.ReadOnly,
  1458  			err:  unix.EPERM,
  1459  		},
  1460  		{
  1461  			name: "read-write",
  1462  			mode: p9.ReadWrite,
  1463  			err:  nil,
  1464  		},
  1465  		{
  1466  			name: "write-only",
  1467  			mode: p9.WriteOnly,
  1468  			err:  nil,
  1469  		},
  1470  	}
  1471  
  1472  	for name := range newTypeMap(nil) {
  1473  		for _, tc := range cases {
  1474  			t.Run(fmt.Sprintf("%s-%s", tc.name, name), func(t *testing.T) {
  1475  				h, c := NewHarness(t)
  1476  				defer h.Finish()
  1477  
  1478  				_, root := newRoot(h, c)
  1479  				defer root.Close()
  1480  
  1481  				const message = "hello"
  1482  
  1483  				onlyWorksOnOpenThings(h, t, name, root, tc.mode, tc.err, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1484  					if !shouldSucceed {
  1485  						_, err := f.WriteAt([]byte(message), 0)
  1486  						return err
  1487  					}
  1488  
  1489  					// Prepare for the call to readAt in the backend.
  1490  					var output []byte // Saved by Do below.
  1491  					backend.EXPECT().WriteAt(gomock.Any(), uint64(0)).Do(func(p []byte, offset uint64) {
  1492  						output = p
  1493  					}).Return(len(message), nil)
  1494  
  1495  					// Make the client call.
  1496  					n, err := f.WriteAt([]byte(message), 0)
  1497  
  1498  					// Sanity check result.
  1499  					if err != nil {
  1500  						return err
  1501  					}
  1502  					if n != len(message) {
  1503  						t.Fatalf("message length incorrect, got %d, want %d", n, len(message))
  1504  					}
  1505  					if !bytes.Equal(output, []byte(message)) {
  1506  						t.Fatalf("message incorrect, got %v, want %v", output, []byte(message))
  1507  					}
  1508  					return nil // Success.
  1509  				})
  1510  			})
  1511  		}
  1512  	}
  1513  }
  1514  
  1515  func TestFSync(t *testing.T) {
  1516  	for name := range newTypeMap(nil) {
  1517  		for _, mode := range []p9.OpenFlags{p9.ReadOnly, p9.WriteOnly, p9.ReadWrite} {
  1518  			t.Run(fmt.Sprintf("%s-%s", mode, name), func(t *testing.T) {
  1519  				h, c := NewHarness(t)
  1520  				defer h.Finish()
  1521  
  1522  				_, root := newRoot(h, c)
  1523  				defer root.Close()
  1524  
  1525  				onlyWorksOnOpenThings(h, t, name, root, mode, nil, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1526  					if shouldSucceed {
  1527  						backend.EXPECT().FSync().Times(1)
  1528  					}
  1529  					return f.FSync()
  1530  				})
  1531  			})
  1532  		}
  1533  	}
  1534  }
  1535  
  1536  func TestFlush(t *testing.T) {
  1537  	for name := range newTypeMap(nil) {
  1538  		t.Run(name, func(t *testing.T) {
  1539  			h, c := NewHarness(t)
  1540  			defer h.Finish()
  1541  
  1542  			_, root := newRoot(h, c)
  1543  			defer root.Close()
  1544  
  1545  			_, backend, f := walkHelper(h, name, root)
  1546  			defer f.Close()
  1547  
  1548  			backend.EXPECT().Flush()
  1549  			f.Flush()
  1550  		})
  1551  	}
  1552  }
  1553  
  1554  // onlyWorksOnDirectories is a helper test method for operations that should
  1555  // only work on unopened directories, such as create, mkdir and symlink.
  1556  func onlyWorksOnDirectories(h *Harness, t *testing.T, name string, root p9.File, fn func(backend *Mock, f p9.File, shouldSucceed bool) error) {
  1557  	// Walk to the file normally.
  1558  	_, backend, f := walkHelper(h, name, root)
  1559  	defer f.Close()
  1560  
  1561  	// Only directories support mknod.
  1562  	if !backend.Attr.Mode.IsDir() {
  1563  		if err := fn(backend, f, false); err != unix.EINVAL {
  1564  			t.Errorf("operation got %v, wanted EINVAL", err)
  1565  		}
  1566  		return // Nothing else to do.
  1567  	}
  1568  
  1569  	// Should succeed.
  1570  	if err := fn(backend, f, true); err != nil {
  1571  		t.Fatalf("operation got %v, wanted nil", err)
  1572  	}
  1573  
  1574  	// Open the directory.
  1575  	backend.EXPECT().Open(p9.ReadOnly).Times(1)
  1576  	if _, _, _, err := f.Open(p9.ReadOnly); err != nil {
  1577  		t.Fatalf("open got %v, wanted nil", err)
  1578  	}
  1579  
  1580  	// Should not work again.
  1581  	if err := fn(backend, f, false); err != unix.EINVAL {
  1582  		t.Fatalf("operation got %v, wanted EINVAL", err)
  1583  	}
  1584  }
  1585  
  1586  func TestCreate(t *testing.T) {
  1587  	for name := range newTypeMap(nil) {
  1588  		t.Run(name, func(t *testing.T) {
  1589  			h, c := NewHarness(t)
  1590  			defer h.Finish()
  1591  
  1592  			_, root := newRoot(h, c)
  1593  			defer root.Close()
  1594  
  1595  			onlyWorksOnDirectories(h, t, name, root, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1596  				if !shouldSucceed {
  1597  					_, _, _, _, err := f.Create("new-file", p9.ReadWrite, 0, 1, 2)
  1598  					return err
  1599  				}
  1600  
  1601  				// If the create is going to succeed, then we
  1602  				// need to create a new backend file, and we
  1603  				// clone to ensure that we don't close the
  1604  				// original.
  1605  				_, newF, err := f.Walk(nil)
  1606  				if err != nil {
  1607  					t.Fatalf("clone got %v, wanted nil", err)
  1608  				}
  1609  				defer newF.Close()
  1610  				newBackend := h.Pop(newF)
  1611  
  1612  				// Run a regular FD test to validate that path.
  1613  				fdTest(t, func(send *fd.FD) *fd.FD {
  1614  					// Return the send FD on success.
  1615  					newFile := h.NewFile()(backend) // New file with the parent backend.
  1616  					newBackend.EXPECT().Create("new-file", p9.ReadWrite, p9.FileMode(0), p9.UID(1), p9.GID(2)).Return(send, newFile, p9.QID{}, uint32(0), nil)
  1617  
  1618  					// Receive the fd back.
  1619  					recv, _, _, _, err := newF.Create("new-file", p9.ReadWrite, 0, 1, 2)
  1620  					if err != nil {
  1621  						t.Fatalf("create got %v, wanted nil", err)
  1622  					}
  1623  					return recv
  1624  				})
  1625  
  1626  				// The above will fail via normal test flow, so
  1627  				// we can assume that it passed.
  1628  				return nil
  1629  			})
  1630  		})
  1631  	}
  1632  }
  1633  
  1634  func TestCreateInvalid(t *testing.T) {
  1635  	h, c := NewHarness(t)
  1636  	defer h.Finish()
  1637  
  1638  	_, root := newRoot(h, c)
  1639  	defer root.Close()
  1640  
  1641  	for name := range newTypeMap(nil) {
  1642  		for _, invalidName := range allInvalidNames(name) {
  1643  			if _, _, _, _, err := root.Create(invalidName, p9.ReadWrite, 0, 0, 0); err != unix.EINVAL {
  1644  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
  1645  			}
  1646  		}
  1647  	}
  1648  }
  1649  
  1650  func TestMkdir(t *testing.T) {
  1651  	for name := range newTypeMap(nil) {
  1652  		t.Run(name, func(t *testing.T) {
  1653  			h, c := NewHarness(t)
  1654  			defer h.Finish()
  1655  
  1656  			_, root := newRoot(h, c)
  1657  			defer root.Close()
  1658  
  1659  			onlyWorksOnDirectories(h, t, name, root, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1660  				if shouldSucceed {
  1661  					backend.EXPECT().Mkdir("new-directory", p9.FileMode(0), p9.UID(1), p9.GID(2))
  1662  				}
  1663  				_, err := f.Mkdir("new-directory", 0, 1, 2)
  1664  				return err
  1665  			})
  1666  		})
  1667  	}
  1668  }
  1669  
  1670  func TestMkdirInvalid(t *testing.T) {
  1671  	h, c := NewHarness(t)
  1672  	defer h.Finish()
  1673  
  1674  	_, root := newRoot(h, c)
  1675  	defer root.Close()
  1676  
  1677  	for name := range newTypeMap(nil) {
  1678  		for _, invalidName := range allInvalidNames(name) {
  1679  			if _, err := root.Mkdir(invalidName, 0, 0, 0); err != unix.EINVAL {
  1680  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
  1681  			}
  1682  		}
  1683  	}
  1684  }
  1685  
  1686  func TestSymlink(t *testing.T) {
  1687  	for name := range newTypeMap(nil) {
  1688  		t.Run(name, func(t *testing.T) {
  1689  			h, c := NewHarness(t)
  1690  			defer h.Finish()
  1691  
  1692  			_, root := newRoot(h, c)
  1693  			defer root.Close()
  1694  
  1695  			onlyWorksOnDirectories(h, t, name, root, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1696  				if shouldSucceed {
  1697  					backend.EXPECT().Symlink("old-name", "new-name", p9.UID(1), p9.GID(2))
  1698  				}
  1699  				_, err := f.Symlink("old-name", "new-name", 1, 2)
  1700  				return err
  1701  			})
  1702  		})
  1703  	}
  1704  }
  1705  
  1706  func TestSyminkInvalid(t *testing.T) {
  1707  	h, c := NewHarness(t)
  1708  	defer h.Finish()
  1709  
  1710  	_, root := newRoot(h, c)
  1711  	defer root.Close()
  1712  
  1713  	for name := range newTypeMap(nil) {
  1714  		for _, invalidName := range allInvalidNames(name) {
  1715  			// We need only test for invalid names in the new name,
  1716  			// the target can be an arbitrary string and we don't
  1717  			// need to sanity check it.
  1718  			if _, err := root.Symlink("old-name", invalidName, 0, 0); err != unix.EINVAL {
  1719  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
  1720  			}
  1721  		}
  1722  	}
  1723  }
  1724  
  1725  func TestLink(t *testing.T) {
  1726  	for name := range newTypeMap(nil) {
  1727  		t.Run(name, func(t *testing.T) {
  1728  			h, c := NewHarness(t)
  1729  			defer h.Finish()
  1730  
  1731  			_, root := newRoot(h, c)
  1732  			defer root.Close()
  1733  
  1734  			onlyWorksOnDirectories(h, t, name, root, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1735  				if shouldSucceed {
  1736  					backend.EXPECT().Link(gomock.Any(), "new-link")
  1737  				}
  1738  				return f.Link(f, "new-link")
  1739  			})
  1740  		})
  1741  	}
  1742  }
  1743  
  1744  func TestLinkInvalid(t *testing.T) {
  1745  	h, c := NewHarness(t)
  1746  	defer h.Finish()
  1747  
  1748  	_, root := newRoot(h, c)
  1749  	defer root.Close()
  1750  
  1751  	for name := range newTypeMap(nil) {
  1752  		for _, invalidName := range allInvalidNames(name) {
  1753  			if err := root.Link(root, invalidName); err != unix.EINVAL {
  1754  				t.Errorf("got %v for name %q, want EINVAL", err, invalidName)
  1755  			}
  1756  		}
  1757  	}
  1758  }
  1759  
  1760  func TestMknod(t *testing.T) {
  1761  	for name := range newTypeMap(nil) {
  1762  		t.Run(name, func(t *testing.T) {
  1763  			h, c := NewHarness(t)
  1764  			defer h.Finish()
  1765  
  1766  			_, root := newRoot(h, c)
  1767  			defer root.Close()
  1768  
  1769  			onlyWorksOnDirectories(h, t, name, root, func(backend *Mock, f p9.File, shouldSucceed bool) error {
  1770  				if shouldSucceed {
  1771  					backend.EXPECT().Mknod("new-block-device", p9.FileMode(0), uint32(1), uint32(2), p9.UID(3), p9.GID(4)).Times(1)
  1772  				}
  1773  				_, err := f.Mknod("new-block-device", 0, 1, 2, 3, 4)
  1774  				return err
  1775  			})
  1776  		})
  1777  	}
  1778  }
  1779  
  1780  // concurrentFn is a specification of a concurrent operation. This is used to
  1781  // drive the concurrency tests below.
  1782  type concurrentFn struct {
  1783  	name  string
  1784  	match func(p9.FileMode) bool
  1785  	op    func(h *Harness, backend *Mock, f p9.File, callback func())
  1786  }
  1787  
  1788  func concurrentTest(t *testing.T, name string, fn1, fn2 concurrentFn, sameDir, expectedOkay bool) {
  1789  	var (
  1790  		names1 []string
  1791  		names2 []string
  1792  	)
  1793  	if sameDir {
  1794  		// Use the same file one directory up.
  1795  		names1, names2 = []string{"one", name}, []string{"one", name}
  1796  	} else {
  1797  		// For different directories, just use siblings.
  1798  		names1, names2 = []string{"one", name}, []string{"three", name}
  1799  	}
  1800  
  1801  	t.Run(fmt.Sprintf("%s(%v)+%s(%v)", fn1.name, names1, fn2.name, names2), func(t *testing.T) {
  1802  		h, c := NewHarness(t)
  1803  		defer h.Finish()
  1804  
  1805  		_, root := newRoot(h, c)
  1806  		defer root.Close()
  1807  
  1808  		// Walk to both files as given.
  1809  		_, f1, err := root.Walk(names1)
  1810  		if err != nil {
  1811  			t.Fatalf("error walking, got %v, want nil", err)
  1812  		}
  1813  		defer f1.Close()
  1814  		b1 := h.Pop(f1)
  1815  		_, f2, err := root.Walk(names2)
  1816  		if err != nil {
  1817  			t.Fatalf("error walking, got %v, want nil", err)
  1818  		}
  1819  		defer f2.Close()
  1820  		b2 := h.Pop(f2)
  1821  
  1822  		// Are these a good match for the current test case?
  1823  		if !fn1.match(b1.Attr.Mode) {
  1824  			t.SkipNow()
  1825  		}
  1826  		if !fn2.match(b2.Attr.Mode) {
  1827  			t.SkipNow()
  1828  		}
  1829  
  1830  		// Construct our "concurrency creator".
  1831  		in1 := make(chan struct{}, 1)
  1832  		in2 := make(chan struct{}, 1)
  1833  		var top sync.WaitGroup
  1834  		var fns sync.WaitGroup
  1835  		defer top.Wait()
  1836  		top.Add(2) // Accounting for below.
  1837  		defer fns.Done()
  1838  		fns.Add(1) // See line above; released before top.Wait.
  1839  		go func() {
  1840  			defer top.Done()
  1841  			fn1.op(h, b1, f1, func() {
  1842  				in1 <- struct{}{}
  1843  				fns.Wait()
  1844  			})
  1845  		}()
  1846  		go func() {
  1847  			defer top.Done()
  1848  			fn2.op(h, b2, f2, func() {
  1849  				in2 <- struct{}{}
  1850  				fns.Wait()
  1851  			})
  1852  		}()
  1853  
  1854  		// Compute a reasonable timeout. If we expect the operation to hang,
  1855  		// give it 10 milliseconds before we assert that it's fine. After all,
  1856  		// there will be a lot of these tests. If we don't expect it to hang,
  1857  		// give it a full minute, since the machine could be slow.
  1858  		timeout := 10 * time.Millisecond
  1859  		if expectedOkay {
  1860  			timeout = 1 * time.Minute
  1861  		}
  1862  
  1863  		// Read the first channel.
  1864  		var second chan struct{}
  1865  		select {
  1866  		case <-in1:
  1867  			second = in2
  1868  		case <-in2:
  1869  			second = in1
  1870  		}
  1871  
  1872  		// Catch concurrency.
  1873  		select {
  1874  		case <-second:
  1875  			// We finished successful. Is this good? Depends on the
  1876  			// expected result.
  1877  			if !expectedOkay {
  1878  				t.Errorf("%q and %q proceeded concurrently!", fn1.name, fn2.name)
  1879  			}
  1880  		case <-time.After(timeout):
  1881  			// Great, things did not proceed concurrently. Is that what we
  1882  			// expected?
  1883  			if expectedOkay {
  1884  				t.Errorf("%q and %q hung concurrently!", fn1.name, fn2.name)
  1885  			}
  1886  		}
  1887  	})
  1888  }
  1889  
  1890  func randomFileName() string {
  1891  	return fmt.Sprintf("%x", rand.Int63())
  1892  }
  1893  
  1894  func TestConcurrency(t *testing.T) {
  1895  	readExclusive := []concurrentFn{
  1896  		{
  1897  			// N.B. We can't explicitly check WalkGetAttr behavior,
  1898  			// but we rely on the fact that the internal code paths
  1899  			// are the same.
  1900  			name:  "walk",
  1901  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1902  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1903  				// See the documentation of WalkCallback.
  1904  				// Because walk is actually implemented by the
  1905  				// mock, we need a special place for this
  1906  				// callback.
  1907  				//
  1908  				// Note that a clone actually locks the parent
  1909  				// node. So we walk from this node to test
  1910  				// concurrent operations appropriately.
  1911  				backend.WalkCallback = func() error {
  1912  					callback()
  1913  					return nil
  1914  				}
  1915  				f.Walk([]string{randomFileName()}) // Won't exist.
  1916  			},
  1917  		},
  1918  		{
  1919  			name:  "fsync",
  1920  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) },
  1921  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1922  				backend.EXPECT().Open(gomock.Any())
  1923  				backend.EXPECT().FSync().Do(func() {
  1924  					callback()
  1925  				})
  1926  				f.Open(p9.ReadOnly) // Required.
  1927  				f.FSync()
  1928  			},
  1929  		},
  1930  		{
  1931  			name:  "readdir",
  1932  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  1933  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1934  				backend.EXPECT().Open(gomock.Any())
  1935  				backend.EXPECT().Readdir(gomock.Any(), gomock.Any()).Do(func(uint64, uint32) {
  1936  					callback()
  1937  				})
  1938  				f.Open(p9.ReadOnly) // Required.
  1939  				f.Readdir(0, 1)
  1940  			},
  1941  		},
  1942  		{
  1943  			name:  "readlink",
  1944  			match: func(mode p9.FileMode) bool { return mode.IsSymlink() },
  1945  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1946  				backend.EXPECT().Readlink().Do(func() {
  1947  					callback()
  1948  				})
  1949  				f.Readlink()
  1950  			},
  1951  		},
  1952  		{
  1953  			name:  "connect",
  1954  			match: func(mode p9.FileMode) bool { return mode.IsSocket() },
  1955  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1956  				backend.EXPECT().Connect(gomock.Any()).Do(func(p9.ConnectFlags) {
  1957  					callback()
  1958  				})
  1959  				f.Connect(0)
  1960  			},
  1961  		},
  1962  		{
  1963  			name:  "open",
  1964  			match: func(mode p9.FileMode) bool { return p9.CanOpen(mode) },
  1965  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1966  				backend.EXPECT().Open(gomock.Any()).Do(func(p9.OpenFlags) {
  1967  					callback()
  1968  				})
  1969  				f.Open(p9.ReadOnly)
  1970  			},
  1971  		},
  1972  		{
  1973  			name:  "flush",
  1974  			match: func(mode p9.FileMode) bool { return true },
  1975  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1976  				backend.EXPECT().Flush().Do(func() {
  1977  					callback()
  1978  				})
  1979  				f.Flush()
  1980  			},
  1981  		},
  1982  	}
  1983  	writeExclusive := []concurrentFn{
  1984  		{
  1985  			// N.B. We can't really check getattr. But this is an
  1986  			// extremely low-risk function, it seems likely that
  1987  			// this check is paranoid anyways.
  1988  			name:  "setattr",
  1989  			match: func(mode p9.FileMode) bool { return true },
  1990  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  1991  				backend.EXPECT().SetAttr(gomock.Any(), gomock.Any()).Do(func(p9.SetAttrMask, p9.SetAttr) {
  1992  					callback()
  1993  				})
  1994  				f.SetAttr(p9.SetAttrMask{}, p9.SetAttr{})
  1995  			},
  1996  		},
  1997  		{
  1998  			name:  "unlinkAt",
  1999  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2000  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2001  				backend.EXPECT().UnlinkAt(gomock.Any(), gomock.Any()).Do(func(string, uint32) {
  2002  					callback()
  2003  				})
  2004  				f.UnlinkAt(randomFileName(), 0)
  2005  			},
  2006  		},
  2007  		{
  2008  			name:  "mknod",
  2009  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2010  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2011  				backend.EXPECT().Mknod(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(func(string, p9.FileMode, uint32, uint32, p9.UID, p9.GID) {
  2012  					callback()
  2013  				})
  2014  				f.Mknod(randomFileName(), 0, 0, 0, 0, 0)
  2015  			},
  2016  		},
  2017  		{
  2018  			name:  "link",
  2019  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2020  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2021  				backend.EXPECT().Link(gomock.Any(), gomock.Any()).Do(func(p9.File, string) {
  2022  					callback()
  2023  				})
  2024  				f.Link(f, randomFileName())
  2025  			},
  2026  		},
  2027  		{
  2028  			name:  "symlink",
  2029  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2030  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2031  				backend.EXPECT().Symlink(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(func(string, string, p9.UID, p9.GID) {
  2032  					callback()
  2033  				})
  2034  				f.Symlink(randomFileName(), randomFileName(), 0, 0)
  2035  			},
  2036  		},
  2037  		{
  2038  			name:  "mkdir",
  2039  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2040  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2041  				backend.EXPECT().Mkdir(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(func(string, p9.FileMode, p9.UID, p9.GID) {
  2042  					callback()
  2043  				})
  2044  				f.Mkdir(randomFileName(), 0, 0, 0)
  2045  			},
  2046  		},
  2047  		{
  2048  			name:  "create",
  2049  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2050  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2051  				// Return an error for the creation operation, as this is the simplest.
  2052  				backend.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, p9.QID{}, uint32(0), unix.EINVAL).Do(func(string, p9.OpenFlags, p9.FileMode, p9.UID, p9.GID) {
  2053  					callback()
  2054  				})
  2055  				f.Create(randomFileName(), p9.ReadOnly, 0, 0, 0)
  2056  			},
  2057  		},
  2058  	}
  2059  	globalExclusive := []concurrentFn{
  2060  		{
  2061  			name:  "remove",
  2062  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2063  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2064  				// Remove operates on a locked parent. So we
  2065  				// add a child, walk to it and call remove.
  2066  				// Note that because this operation can operate
  2067  				// concurrently with itself, we need to
  2068  				// generate a random file name.
  2069  				randomFile := randomFileName()
  2070  				backend.AddChild(randomFile, h.NewFile())
  2071  				defer backend.RemoveChild(randomFile)
  2072  				_, file, err := f.Walk([]string{randomFile})
  2073  				if err != nil {
  2074  					h.t.Fatalf("walk got %v, want nil", err)
  2075  				}
  2076  
  2077  				// Remove is automatically translated to the parent.
  2078  				backend.EXPECT().UnlinkAt(gomock.Any(), gomock.Any()).Do(func(string, uint32) {
  2079  					callback()
  2080  				})
  2081  
  2082  				// Remove is also a close.
  2083  				file.(deprecatedRemover).Remove()
  2084  			},
  2085  		},
  2086  		{
  2087  			name:  "rename",
  2088  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2089  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2090  				// Similarly to remove, because we need to
  2091  				// operate on a child, we allow a walk.
  2092  				randomFile := randomFileName()
  2093  				backend.AddChild(randomFile, h.NewFile())
  2094  				defer backend.RemoveChild(randomFile)
  2095  				_, file, err := f.Walk([]string{randomFile})
  2096  				if err != nil {
  2097  					h.t.Fatalf("walk got %v, want nil", err)
  2098  				}
  2099  				defer file.Close()
  2100  				fileBackend := h.Pop(file)
  2101  
  2102  				// Rename is automatically translated to the parent.
  2103  				backend.EXPECT().RenameAt(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(string, p9.File, string) {
  2104  					callback()
  2105  				})
  2106  
  2107  				// Attempt the rename.
  2108  				fileBackend.EXPECT().Renamed(gomock.Any(), gomock.Any())
  2109  				file.Rename(f, randomFileName())
  2110  			},
  2111  		},
  2112  		{
  2113  			name:  "renameAt",
  2114  			match: func(mode p9.FileMode) bool { return mode.IsDir() },
  2115  			op: func(h *Harness, backend *Mock, f p9.File, callback func()) {
  2116  				backend.EXPECT().RenameAt(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(string, p9.File, string) {
  2117  					callback()
  2118  				})
  2119  
  2120  				// Attempt the rename. There are no active fids
  2121  				// with this name, so we don't need to expect
  2122  				// Renamed hooks on anything.
  2123  				f.RenameAt(randomFileName(), f, randomFileName())
  2124  			},
  2125  		},
  2126  	}
  2127  
  2128  	for _, fn1 := range readExclusive {
  2129  		for _, fn2 := range readExclusive {
  2130  			for name := range newTypeMap(nil) {
  2131  				// Everything should be able to proceed in parallel.
  2132  				concurrentTest(t, name, fn1, fn2, true, true)
  2133  				concurrentTest(t, name, fn1, fn2, false, true)
  2134  			}
  2135  		}
  2136  	}
  2137  
  2138  	for _, fn1 := range append(readExclusive, writeExclusive...) {
  2139  		for _, fn2 := range writeExclusive {
  2140  			for name := range newTypeMap(nil) {
  2141  				// Only cross-directory functions should proceed in parallel.
  2142  				concurrentTest(t, name, fn1, fn2, true, false)
  2143  				concurrentTest(t, name, fn1, fn2, false, true)
  2144  			}
  2145  		}
  2146  	}
  2147  
  2148  	for _, fn1 := range append(append(readExclusive, writeExclusive...), globalExclusive...) {
  2149  		for _, fn2 := range globalExclusive {
  2150  			for name := range newTypeMap(nil) {
  2151  				// Nothing should be able to run in parallel.
  2152  				concurrentTest(t, name, fn1, fn2, true, false)
  2153  				concurrentTest(t, name, fn1, fn2, false, false)
  2154  			}
  2155  		}
  2156  	}
  2157  }
  2158  
  2159  func TestReadWriteConcurrent(t *testing.T) {
  2160  	h, c := NewHarness(t)
  2161  	defer h.Finish()
  2162  
  2163  	_, root := newRoot(h, c)
  2164  	defer root.Close()
  2165  
  2166  	const (
  2167  		instances  = 10
  2168  		iterations = 10000
  2169  		dataSize   = 1024
  2170  	)
  2171  	var (
  2172  		dataSets [instances][dataSize]byte
  2173  		backends [instances]*Mock
  2174  		files    [instances]p9.File
  2175  	)
  2176  
  2177  	// Walk to the file normally.
  2178  	for i := 0; i < instances; i++ {
  2179  		_, backends[i], files[i] = walkHelper(h, "file", root)
  2180  		defer files[i].Close()
  2181  	}
  2182  
  2183  	// Open the files.
  2184  	for i := 0; i < instances; i++ {
  2185  		backends[i].EXPECT().Open(p9.ReadWrite)
  2186  		if _, _, _, err := files[i].Open(p9.ReadWrite); err != nil {
  2187  			t.Fatalf("open got %v, wanted nil", err)
  2188  		}
  2189  	}
  2190  
  2191  	// Initialize random data for each instance.
  2192  	for i := 0; i < instances; i++ {
  2193  		if _, err := rand.Read(dataSets[i][:]); err != nil {
  2194  			t.Fatalf("error initializing dataSet#%d, got %v", i, err)
  2195  		}
  2196  	}
  2197  
  2198  	// Define our random read/write mechanism.
  2199  	randRead := func(h *Harness, backend *Mock, f p9.File, data, test []byte) {
  2200  		// Prepare the backend.
  2201  		backend.EXPECT().ReadAt(gomock.Any(), uint64(0)).Do(func(p []byte, offset uint64) {
  2202  			if n := copy(p, data); n != len(data) {
  2203  				// Note that we have to assert the result here, as the Return statement
  2204  				// below cannot be dynamic: it will be bound before this call is made.
  2205  				h.t.Errorf("wanted length %d, got %d", len(data), n)
  2206  			}
  2207  		}).Return(len(data), nil)
  2208  
  2209  		// Execute the read.
  2210  		if n, err := f.ReadAt(test, 0); n != len(test) || err != nil {
  2211  			t.Errorf("failed read: wanted (%d, nil), got (%d, %v)", len(test), n, err)
  2212  			return // No sense doing check below.
  2213  		}
  2214  		if !bytes.Equal(test, data) {
  2215  			t.Errorf("data integrity failed during read") // Not as expected.
  2216  		}
  2217  	}
  2218  	randWrite := func(h *Harness, backend *Mock, f p9.File, data []byte) {
  2219  		// Prepare the backend.
  2220  		backend.EXPECT().WriteAt(gomock.Any(), uint64(0)).Do(func(p []byte, offset uint64) {
  2221  			if !bytes.Equal(p, data) {
  2222  				h.t.Errorf("data integrity failed during write") // Not as expected.
  2223  			}
  2224  		}).Return(len(data), nil)
  2225  
  2226  		// Execute the write.
  2227  		if n, err := f.WriteAt(data, 0); n != len(data) || err != nil {
  2228  			t.Errorf("failed read: wanted (%d, nil), got (%d, %v)", len(data), n, err)
  2229  		}
  2230  	}
  2231  	randReadWrite := func(n int, h *Harness, backend *Mock, f p9.File, data []byte) {
  2232  		test := make([]byte, len(data))
  2233  		for i := 0; i < n; i++ {
  2234  			if rand.Intn(2) == 0 {
  2235  				randRead(h, backend, f, data, test)
  2236  			} else {
  2237  				randWrite(h, backend, f, data)
  2238  			}
  2239  		}
  2240  	}
  2241  
  2242  	// Start reading and writing.
  2243  	var wg sync.WaitGroup
  2244  	for i := 0; i < instances; i++ {
  2245  		wg.Add(1)
  2246  		go func(i int) {
  2247  			defer wg.Done()
  2248  			randReadWrite(iterations, h, backends[i], files[i], dataSets[i][:])
  2249  		}(i)
  2250  	}
  2251  	wg.Wait()
  2252  }