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