...

Source file src/k8s.io/kubernetes/pkg/volume/util/subpath/subpath_linux_test.go

Documentation: k8s.io/kubernetes/pkg/volume/util/subpath

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2014 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package subpath
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net"
    26  	"os"
    27  	"path/filepath"
    28  	"reflect"
    29  	"strconv"
    30  	"syscall"
    31  	"testing"
    32  
    33  	"k8s.io/klog/v2"
    34  	"k8s.io/mount-utils"
    35  )
    36  
    37  func TestSafeMakeDir(t *testing.T) {
    38  	defaultPerm := os.FileMode(0750) + os.ModeDir
    39  	maxPerm := os.FileMode(0777) + os.ModeDir
    40  	tests := []struct {
    41  		name string
    42  		// Function that prepares directory structure for the test under given
    43  		// base.
    44  		prepare     func(base string) error
    45  		path        string
    46  		checkPath   string
    47  		perm        os.FileMode
    48  		expectError bool
    49  	}{
    50  		{
    51  			"directory-does-not-exist",
    52  			func(base string) error {
    53  				return nil
    54  			},
    55  			"test/directory",
    56  			"test/directory",
    57  			defaultPerm,
    58  			false,
    59  		},
    60  		{
    61  			"all-created-subpath-directory-with-permissions",
    62  			func(base string) error {
    63  				return nil
    64  			},
    65  			"test/directory",
    66  			"test",
    67  			maxPerm,
    68  			false,
    69  		},
    70  		{
    71  			"directory-with-sgid",
    72  			func(base string) error {
    73  				return nil
    74  			},
    75  			"test/directory",
    76  			"test/directory",
    77  			os.FileMode(0777) + os.ModeDir + os.ModeSetgid,
    78  			false,
    79  		},
    80  		{
    81  			"directory-with-suid",
    82  			func(base string) error {
    83  				return nil
    84  			},
    85  			"test/directory",
    86  			"test/directory",
    87  			os.FileMode(0777) + os.ModeDir + os.ModeSetuid,
    88  			false,
    89  		},
    90  		{
    91  			"directory-with-sticky-bit",
    92  			func(base string) error {
    93  				return nil
    94  			},
    95  			"test/directory",
    96  			"test/directory",
    97  			os.FileMode(0777) + os.ModeDir + os.ModeSticky,
    98  			false,
    99  		},
   100  		{
   101  			"directory-exists",
   102  			func(base string) error {
   103  				return os.MkdirAll(filepath.Join(base, "test/directory"), 0750)
   104  			},
   105  			"test/directory",
   106  			"test/directory",
   107  			defaultPerm,
   108  			false,
   109  		},
   110  		{
   111  			"create-base",
   112  			func(base string) error {
   113  				return nil
   114  			},
   115  			"",
   116  			"",
   117  			defaultPerm,
   118  			false,
   119  		},
   120  		{
   121  			"escape-base-using-dots",
   122  			func(base string) error {
   123  				return nil
   124  			},
   125  			"..",
   126  			"",
   127  			defaultPerm,
   128  			true,
   129  		},
   130  		{
   131  			"escape-base-using-dots-2",
   132  			func(base string) error {
   133  				return nil
   134  			},
   135  			"test/../../..",
   136  			"",
   137  			defaultPerm,
   138  			true,
   139  		},
   140  		{
   141  			"follow-symlinks",
   142  			func(base string) error {
   143  				if err := os.MkdirAll(filepath.Join(base, "destination"), defaultPerm); err != nil {
   144  					return err
   145  				}
   146  				return os.Symlink("destination", filepath.Join(base, "test"))
   147  			},
   148  			"test/directory",
   149  			"destination/directory",
   150  			defaultPerm,
   151  			false,
   152  		},
   153  		{
   154  			"follow-symlink-loop",
   155  			func(base string) error {
   156  				return os.Symlink("test", filepath.Join(base, "test"))
   157  			},
   158  			"test/directory",
   159  			"",
   160  			defaultPerm,
   161  			true,
   162  		},
   163  		{
   164  			"follow-symlink-multiple follow",
   165  			func(base string) error {
   166  				/* test1/dir points to test2 and test2/dir points to test1 */
   167  				if err := os.MkdirAll(filepath.Join(base, "test1"), defaultPerm); err != nil {
   168  					return err
   169  				}
   170  				if err := os.MkdirAll(filepath.Join(base, "test2"), defaultPerm); err != nil {
   171  					return err
   172  				}
   173  				if err := os.Symlink(filepath.Join(base, "test2"), filepath.Join(base, "test1/dir")); err != nil {
   174  					return err
   175  				}
   176  				if err := os.Symlink(filepath.Join(base, "test1"), filepath.Join(base, "test2/dir")); err != nil {
   177  					return err
   178  				}
   179  				return nil
   180  			},
   181  			"test1/dir/dir/dir/dir/dir/dir/dir/foo",
   182  			"test2/foo",
   183  			defaultPerm,
   184  			false,
   185  		},
   186  		{
   187  			"danglink-symlink",
   188  			func(base string) error {
   189  				return os.Symlink("non-existing", filepath.Join(base, "test"))
   190  			},
   191  			"test/directory",
   192  			"",
   193  			defaultPerm,
   194  			true,
   195  		},
   196  		{
   197  			"non-directory",
   198  			func(base string) error {
   199  				return ioutil.WriteFile(filepath.Join(base, "test"), []byte{}, defaultPerm)
   200  			},
   201  			"test/directory",
   202  			"",
   203  			defaultPerm,
   204  			true,
   205  		},
   206  		{
   207  			"non-directory-final",
   208  			func(base string) error {
   209  				return ioutil.WriteFile(filepath.Join(base, "test"), []byte{}, defaultPerm)
   210  			},
   211  			"test",
   212  			"",
   213  			defaultPerm,
   214  			true,
   215  		},
   216  		{
   217  			"escape-with-relative-symlink",
   218  			func(base string) error {
   219  				if err := os.MkdirAll(filepath.Join(base, "dir"), defaultPerm); err != nil {
   220  					return err
   221  				}
   222  				if err := os.MkdirAll(filepath.Join(base, "exists"), defaultPerm); err != nil {
   223  					return err
   224  				}
   225  				return os.Symlink("../exists", filepath.Join(base, "dir/test"))
   226  			},
   227  			"dir/test",
   228  			"",
   229  			defaultPerm,
   230  			false,
   231  		},
   232  		{
   233  			"escape-with-relative-symlink-not-exists",
   234  			func(base string) error {
   235  				if err := os.MkdirAll(filepath.Join(base, "dir"), defaultPerm); err != nil {
   236  					return err
   237  				}
   238  				return os.Symlink("../not-exists", filepath.Join(base, "dir/test"))
   239  			},
   240  			"dir/test",
   241  			"",
   242  			defaultPerm,
   243  			true,
   244  		},
   245  		{
   246  			"escape-with-symlink",
   247  			func(base string) error {
   248  				return os.Symlink("/", filepath.Join(base, "test"))
   249  			},
   250  			"test/directory",
   251  			"",
   252  			defaultPerm,
   253  			true,
   254  		},
   255  	}
   256  
   257  	for i := range tests {
   258  		test := tests[i]
   259  		t.Run(test.name, func(t *testing.T) {
   260  			base, err := ioutil.TempDir("", "safe-make-dir-"+test.name+"-")
   261  			if err != nil {
   262  				t.Fatalf(err.Error())
   263  			}
   264  			defer os.RemoveAll(base)
   265  			test.prepare(base)
   266  			pathToCreate := filepath.Join(base, test.path)
   267  			err = doSafeMakeDir(pathToCreate, base, test.perm)
   268  			if err != nil && !test.expectError {
   269  				t.Fatal(err)
   270  			}
   271  			if err != nil {
   272  				t.Logf("got error: %s", err)
   273  			}
   274  			if err == nil && test.expectError {
   275  				t.Fatalf("expected error, got none")
   276  			}
   277  
   278  			if test.checkPath != "" {
   279  				st, err := os.Stat(filepath.Join(base, test.checkPath))
   280  				if err != nil {
   281  					t.Fatalf("cannot read path %s", test.checkPath)
   282  				}
   283  				actualMode := st.Mode()
   284  				if actualMode != test.perm {
   285  					if actualMode^test.perm == os.ModeSetgid && test.perm&os.ModeSetgid == 0 {
   286  						// when TMPDIR is a kubernetes emptydir, the sticky gid bit is set due to fsgroup
   287  						t.Logf("masking bit from %o", actualMode)
   288  					} else {
   289  						t.Errorf("expected permissions %o, got %o (%b)", test.perm, actualMode, test.perm^actualMode)
   290  					}
   291  				}
   292  			}
   293  		})
   294  	}
   295  }
   296  
   297  func TestRemoveEmptyDirs(t *testing.T) {
   298  	defaultPerm := os.FileMode(0750)
   299  	tests := []struct {
   300  		name string
   301  		// Function that prepares directory structure for the test under given
   302  		// base.
   303  		prepare func(base string) error
   304  		// Function that validates directory structure after the test
   305  		validate    func(base string) error
   306  		baseDir     string
   307  		endDir      string
   308  		expectError bool
   309  	}{
   310  		{
   311  			name: "all-empty",
   312  			prepare: func(base string) error {
   313  				return os.MkdirAll(filepath.Join(base, "a/b/c"), defaultPerm)
   314  			},
   315  			validate: func(base string) error {
   316  				return validateDirEmpty(filepath.Join(base, "a"))
   317  			},
   318  			baseDir:     "a",
   319  			endDir:      "a/b/c",
   320  			expectError: false,
   321  		},
   322  		{
   323  			name: "dir-not-empty",
   324  			prepare: func(base string) error {
   325  				if err := os.MkdirAll(filepath.Join(base, "a/b/c"), defaultPerm); err != nil {
   326  					return err
   327  				}
   328  				return os.Mkdir(filepath.Join(base, "a/b/d"), defaultPerm)
   329  			},
   330  			validate: func(base string) error {
   331  				if err := validateDirNotExists(filepath.Join(base, "a/b/c")); err != nil {
   332  					return err
   333  				}
   334  				return validateDirExists(filepath.Join(base, "a/b"))
   335  			},
   336  			baseDir:     "a",
   337  			endDir:      "a/b/c",
   338  			expectError: false,
   339  		},
   340  		{
   341  			name: "path-not-within-base",
   342  			prepare: func(base string) error {
   343  				return os.MkdirAll(filepath.Join(base, "a/b/c"), defaultPerm)
   344  			},
   345  			validate: func(base string) error {
   346  				return validateDirExists(filepath.Join(base, "a"))
   347  			},
   348  			baseDir:     "a",
   349  			endDir:      "b/c",
   350  			expectError: true,
   351  		},
   352  		{
   353  			name: "path-already-deleted",
   354  			prepare: func(base string) error {
   355  				return nil
   356  			},
   357  			validate: func(base string) error {
   358  				return nil
   359  			},
   360  			baseDir:     "a",
   361  			endDir:      "a/b/c",
   362  			expectError: false,
   363  		},
   364  		{
   365  			name: "path-not-dir",
   366  			prepare: func(base string) error {
   367  				if err := os.MkdirAll(filepath.Join(base, "a/b"), defaultPerm); err != nil {
   368  					return err
   369  				}
   370  				return ioutil.WriteFile(filepath.Join(base, "a/b", "c"), []byte{}, defaultPerm)
   371  			},
   372  			validate: func(base string) error {
   373  				if err := validateDirExists(filepath.Join(base, "a/b")); err != nil {
   374  					return err
   375  				}
   376  				return validateFileExists(filepath.Join(base, "a/b/c"))
   377  			},
   378  			baseDir:     "a",
   379  			endDir:      "a/b/c",
   380  			expectError: true,
   381  		},
   382  	}
   383  
   384  	for _, test := range tests {
   385  		klog.V(4).Infof("test %q", test.name)
   386  		base, err := ioutil.TempDir("", "remove-empty-dirs-"+test.name+"-")
   387  		if err != nil {
   388  			t.Fatalf(err.Error())
   389  		}
   390  		if err = test.prepare(base); err != nil {
   391  			os.RemoveAll(base)
   392  			t.Fatalf("failed to prepare test %q: %v", test.name, err.Error())
   393  		}
   394  
   395  		err = removeEmptyDirs(filepath.Join(base, test.baseDir), filepath.Join(base, test.endDir))
   396  		if err != nil && !test.expectError {
   397  			t.Errorf("test %q failed: %v", test.name, err)
   398  		}
   399  		if err == nil && test.expectError {
   400  			t.Errorf("test %q failed: expected error, got success", test.name)
   401  		}
   402  
   403  		if err = test.validate(base); err != nil {
   404  			t.Errorf("test %q failed validation: %v", test.name, err)
   405  		}
   406  
   407  		os.RemoveAll(base)
   408  	}
   409  }
   410  
   411  func TestCleanSubPaths(t *testing.T) {
   412  	defaultPerm := os.FileMode(0750)
   413  	testVol := "vol1"
   414  
   415  	tests := []struct {
   416  		name string
   417  		// Function that prepares directory structure for the test under given
   418  		// base.
   419  		prepare func(base string) ([]mount.MountPoint, error)
   420  		// Function that validates directory structure after the test
   421  		validate    func(base string) error
   422  		expectError bool
   423  		unmount     func(path string) error
   424  	}{
   425  		{
   426  			name: "not-exists",
   427  			prepare: func(base string) ([]mount.MountPoint, error) {
   428  				return nil, nil
   429  			},
   430  			validate: func(base string) error {
   431  				return nil
   432  			},
   433  			expectError: false,
   434  		},
   435  		{
   436  			name: "subpath-not-mount",
   437  			prepare: func(base string) ([]mount.MountPoint, error) {
   438  				return nil, os.MkdirAll(filepath.Join(base, containerSubPathDirectoryName, testVol, "container1", "0"), defaultPerm)
   439  			},
   440  			validate: func(base string) error {
   441  				return validateDirNotExists(filepath.Join(base, containerSubPathDirectoryName))
   442  			},
   443  			expectError: false,
   444  		},
   445  		{
   446  			name: "subpath-file",
   447  			prepare: func(base string) ([]mount.MountPoint, error) {
   448  				path := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1")
   449  				if err := os.MkdirAll(path, defaultPerm); err != nil {
   450  					return nil, err
   451  				}
   452  				return nil, ioutil.WriteFile(filepath.Join(path, "0"), []byte{}, defaultPerm)
   453  			},
   454  			validate: func(base string) error {
   455  				return validateDirNotExists(filepath.Join(base, containerSubPathDirectoryName))
   456  			},
   457  			expectError: false,
   458  		},
   459  		{
   460  			name: "subpath-container-not-dir",
   461  			prepare: func(base string) ([]mount.MountPoint, error) {
   462  				path := filepath.Join(base, containerSubPathDirectoryName, testVol)
   463  				if err := os.MkdirAll(path, defaultPerm); err != nil {
   464  					return nil, err
   465  				}
   466  				return nil, ioutil.WriteFile(filepath.Join(path, "container1"), []byte{}, defaultPerm)
   467  			},
   468  			validate: func(base string) error {
   469  				return validateDirExists(filepath.Join(base, containerSubPathDirectoryName, testVol))
   470  			},
   471  			expectError: true,
   472  		},
   473  		{
   474  			name: "subpath-multiple-container-not-dir",
   475  			prepare: func(base string) ([]mount.MountPoint, error) {
   476  				path := filepath.Join(base, containerSubPathDirectoryName, testVol)
   477  				if err := os.MkdirAll(filepath.Join(path, "container1"), defaultPerm); err != nil {
   478  					return nil, err
   479  				}
   480  				return nil, ioutil.WriteFile(filepath.Join(path, "container2"), []byte{}, defaultPerm)
   481  			},
   482  			validate: func(base string) error {
   483  				path := filepath.Join(base, containerSubPathDirectoryName, testVol)
   484  				if err := validateDirNotExists(filepath.Join(path, "container1")); err != nil {
   485  					return err
   486  				}
   487  				return validateFileExists(filepath.Join(path, "container2"))
   488  			},
   489  			expectError: true,
   490  		},
   491  		{
   492  			name: "subpath-mount",
   493  			prepare: func(base string) ([]mount.MountPoint, error) {
   494  				path := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1", "0")
   495  				if err := os.MkdirAll(path, defaultPerm); err != nil {
   496  					return nil, err
   497  				}
   498  				mounts := []mount.MountPoint{{Device: "/dev/sdb", Path: path}}
   499  				return mounts, nil
   500  			},
   501  			validate: func(base string) error {
   502  				return validateDirNotExists(filepath.Join(base, containerSubPathDirectoryName))
   503  			},
   504  		},
   505  		{
   506  			name: "subpath-mount-multiple",
   507  			prepare: func(base string) ([]mount.MountPoint, error) {
   508  				path := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1", "0")
   509  				path2 := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1", "1")
   510  				path3 := filepath.Join(base, containerSubPathDirectoryName, testVol, "container2", "1")
   511  				if err := os.MkdirAll(path, defaultPerm); err != nil {
   512  					return nil, err
   513  				}
   514  				if err := os.MkdirAll(path2, defaultPerm); err != nil {
   515  					return nil, err
   516  				}
   517  				if err := os.MkdirAll(path3, defaultPerm); err != nil {
   518  					return nil, err
   519  				}
   520  				mounts := []mount.MountPoint{
   521  					{Device: "/dev/sdb", Path: path},
   522  					{Device: "/dev/sdb", Path: path3},
   523  				}
   524  				return mounts, nil
   525  			},
   526  			validate: func(base string) error {
   527  				return validateDirNotExists(filepath.Join(base, containerSubPathDirectoryName))
   528  			},
   529  		},
   530  		{
   531  			name: "subpath-mount-multiple-vols",
   532  			prepare: func(base string) ([]mount.MountPoint, error) {
   533  				path := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1", "0")
   534  				path2 := filepath.Join(base, containerSubPathDirectoryName, "vol2", "container1", "1")
   535  				if err := os.MkdirAll(path, defaultPerm); err != nil {
   536  					return nil, err
   537  				}
   538  				if err := os.MkdirAll(path2, defaultPerm); err != nil {
   539  					return nil, err
   540  				}
   541  				mounts := []mount.MountPoint{
   542  					{Device: "/dev/sdb", Path: path},
   543  				}
   544  				return mounts, nil
   545  			},
   546  			validate: func(base string) error {
   547  				baseSubdir := filepath.Join(base, containerSubPathDirectoryName)
   548  				if err := validateDirNotExists(filepath.Join(baseSubdir, testVol)); err != nil {
   549  					return err
   550  				}
   551  				return validateDirExists(baseSubdir)
   552  			},
   553  		},
   554  		{
   555  			name: "subpath-with-files",
   556  			prepare: func(base string) ([]mount.MountPoint, error) {
   557  				containerPath := filepath.Join(base, containerSubPathDirectoryName, testVol, "container1")
   558  				if err := os.MkdirAll(containerPath, defaultPerm); err != nil {
   559  					return nil, err
   560  				}
   561  
   562  				file0 := filepath.Join(containerPath, "0")
   563  				if err := ioutil.WriteFile(file0, []byte{}, defaultPerm); err != nil {
   564  					return nil, err
   565  				}
   566  
   567  				dir1 := filepath.Join(containerPath, "1")
   568  				if err := os.MkdirAll(filepath.Join(dir1, "my-dir-1"), defaultPerm); err != nil {
   569  					return nil, err
   570  				}
   571  
   572  				dir2 := filepath.Join(containerPath, "2")
   573  				if err := os.MkdirAll(filepath.Join(dir2, "my-dir-2"), defaultPerm); err != nil {
   574  					return nil, err
   575  				}
   576  
   577  				file3 := filepath.Join(containerPath, "3")
   578  				if err := ioutil.WriteFile(file3, []byte{}, defaultPerm); err != nil {
   579  					return nil, err
   580  				}
   581  
   582  				mounts := []mount.MountPoint{
   583  					{Device: "/dev/sdb", Path: file0},
   584  					{Device: "/dev/sdc", Path: dir1},
   585  					{Device: "/dev/sdd", Path: dir2},
   586  					{Device: "/dev/sde", Path: file3},
   587  				}
   588  				return mounts, nil
   589  			},
   590  			unmount: func(mountpath string) error {
   591  				err := filepath.Walk(mountpath, func(path string, info os.FileInfo, _ error) error {
   592  					if path == mountpath {
   593  						// Skip top level directory
   594  						return nil
   595  					}
   596  
   597  					if err := os.Remove(path); err != nil {
   598  						return err
   599  					}
   600  					return filepath.SkipDir
   601  				})
   602  				if err != nil {
   603  					return fmt.Errorf("error processing %s: %s", mountpath, err)
   604  				}
   605  
   606  				return nil
   607  			},
   608  			validate: func(base string) error {
   609  				return validateDirNotExists(filepath.Join(base, containerSubPathDirectoryName))
   610  			},
   611  		},
   612  	}
   613  
   614  	for _, test := range tests {
   615  		klog.V(4).Infof("test %q", test.name)
   616  		base, err := ioutil.TempDir("", "clean-subpaths-"+test.name+"-")
   617  		if err != nil {
   618  			t.Fatalf(err.Error())
   619  		}
   620  		mounts, err := test.prepare(base)
   621  		if err != nil {
   622  			os.RemoveAll(base)
   623  			t.Fatalf("failed to prepare test %q: %v", test.name, err.Error())
   624  		}
   625  
   626  		fm := mount.NewFakeMounter(mounts)
   627  		fm.UnmountFunc = test.unmount
   628  
   629  		err = doCleanSubPaths(fm, base, testVol)
   630  		if err != nil && !test.expectError {
   631  			t.Errorf("test %q failed: %v", test.name, err)
   632  		}
   633  		if err == nil && test.expectError {
   634  			t.Errorf("test %q failed: expected error, got success", test.name)
   635  		}
   636  		if err = test.validate(base); err != nil {
   637  			t.Errorf("test %q failed validation: %v", test.name, err)
   638  		}
   639  
   640  		os.RemoveAll(base)
   641  	}
   642  }
   643  
   644  var (
   645  	testVol       = "vol1"
   646  	testPod       = "pod0"
   647  	testContainer = "container0"
   648  	testSubpath   = 1
   649  )
   650  
   651  func setupFakeMounter(testMounts []string) *mount.FakeMounter {
   652  	mounts := []mount.MountPoint{}
   653  	for _, mountPoint := range testMounts {
   654  		mounts = append(mounts, mount.MountPoint{Device: "/foo", Path: mountPoint})
   655  	}
   656  	return mount.NewFakeMounter(mounts)
   657  }
   658  
   659  func getTestPaths(base string) (string, string) {
   660  	return filepath.Join(base, testVol),
   661  		filepath.Join(base, testPod, containerSubPathDirectoryName, testVol, testContainer, strconv.Itoa(testSubpath))
   662  }
   663  
   664  func TestBindSubPath(t *testing.T) {
   665  	defaultPerm := os.FileMode(0750)
   666  
   667  	tests := []struct {
   668  		name string
   669  		// Function that prepares directory structure for the test under given
   670  		// base.
   671  		prepare     func(base string) ([]string, string, string, error)
   672  		expectError bool
   673  	}{
   674  		{
   675  			name: "subpath-dir",
   676  			prepare: func(base string) ([]string, string, string, error) {
   677  				volpath, _ := getTestPaths(base)
   678  				subpath := filepath.Join(volpath, "dir0")
   679  				return nil, volpath, subpath, os.MkdirAll(subpath, defaultPerm)
   680  			},
   681  			expectError: false,
   682  		},
   683  		{
   684  			name: "subpath-dir-symlink",
   685  			prepare: func(base string) ([]string, string, string, error) {
   686  				volpath, _ := getTestPaths(base)
   687  				subpath := filepath.Join(volpath, "dir0")
   688  				if err := os.MkdirAll(subpath, defaultPerm); err != nil {
   689  					return nil, "", "", err
   690  				}
   691  				subpathLink := filepath.Join(volpath, "dirLink")
   692  				return nil, volpath, subpath, os.Symlink(subpath, subpathLink)
   693  			},
   694  			expectError: false,
   695  		},
   696  		{
   697  			name: "subpath-file",
   698  			prepare: func(base string) ([]string, string, string, error) {
   699  				volpath, _ := getTestPaths(base)
   700  				subpath := filepath.Join(volpath, "file0")
   701  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   702  					return nil, "", "", err
   703  				}
   704  				return nil, volpath, subpath, ioutil.WriteFile(subpath, []byte{}, defaultPerm)
   705  			},
   706  			expectError: false,
   707  		},
   708  		{
   709  			name: "subpath-not-exists",
   710  			prepare: func(base string) ([]string, string, string, error) {
   711  				volpath, _ := getTestPaths(base)
   712  				subpath := filepath.Join(volpath, "file0")
   713  				return nil, volpath, subpath, nil
   714  			},
   715  			expectError: true,
   716  		},
   717  		{
   718  			name: "subpath-outside",
   719  			prepare: func(base string) ([]string, string, string, error) {
   720  				volpath, _ := getTestPaths(base)
   721  				subpath := filepath.Join(volpath, "dir0")
   722  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   723  					return nil, "", "", err
   724  				}
   725  				return nil, volpath, subpath, os.Symlink(base, subpath)
   726  			},
   727  			expectError: true,
   728  		},
   729  		{
   730  			name: "subpath-symlink-child-outside",
   731  			prepare: func(base string) ([]string, string, string, error) {
   732  				volpath, _ := getTestPaths(base)
   733  				subpathDir := filepath.Join(volpath, "dir0")
   734  				subpath := filepath.Join(subpathDir, "child0")
   735  				if err := os.MkdirAll(subpathDir, defaultPerm); err != nil {
   736  					return nil, "", "", err
   737  				}
   738  				return nil, volpath, subpath, os.Symlink(base, subpath)
   739  			},
   740  			expectError: true,
   741  		},
   742  		{
   743  			name: "subpath-child-outside-exists",
   744  			prepare: func(base string) ([]string, string, string, error) {
   745  				volpath, _ := getTestPaths(base)
   746  				subpathDir := filepath.Join(volpath, "dir0")
   747  				child := filepath.Join(base, "child0")
   748  				subpath := filepath.Join(subpathDir, "child0")
   749  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   750  					return nil, "", "", err
   751  				}
   752  				// touch file outside
   753  				if err := ioutil.WriteFile(child, []byte{}, defaultPerm); err != nil {
   754  					return nil, "", "", err
   755  				}
   756  
   757  				// create symlink for subpath dir
   758  				return nil, volpath, subpath, os.Symlink(base, subpathDir)
   759  			},
   760  			expectError: true,
   761  		},
   762  		{
   763  			name: "subpath-child-outside-not-exists",
   764  			prepare: func(base string) ([]string, string, string, error) {
   765  				volpath, _ := getTestPaths(base)
   766  				subpathDir := filepath.Join(volpath, "dir0")
   767  				subpath := filepath.Join(subpathDir, "child0")
   768  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   769  					return nil, "", "", err
   770  				}
   771  				// create symlink for subpath dir
   772  				return nil, volpath, subpath, os.Symlink(base, subpathDir)
   773  			},
   774  			expectError: true,
   775  		},
   776  		{
   777  			name: "subpath-child-outside-exists-middle-dir-symlink",
   778  			prepare: func(base string) ([]string, string, string, error) {
   779  				volpath, _ := getTestPaths(base)
   780  				subpathDir := filepath.Join(volpath, "dir0")
   781  				symlinkDir := filepath.Join(subpathDir, "linkDir0")
   782  				child := filepath.Join(base, "child0")
   783  				subpath := filepath.Join(symlinkDir, "child0")
   784  				if err := os.MkdirAll(subpathDir, defaultPerm); err != nil {
   785  					return nil, "", "", err
   786  				}
   787  				// touch file outside
   788  				if err := ioutil.WriteFile(child, []byte{}, defaultPerm); err != nil {
   789  					return nil, "", "", err
   790  				}
   791  
   792  				// create symlink for middle dir
   793  				return nil, volpath, subpath, os.Symlink(base, symlinkDir)
   794  			},
   795  			expectError: true,
   796  		},
   797  		{
   798  			name: "subpath-backstepping",
   799  			prepare: func(base string) ([]string, string, string, error) {
   800  				volpath, _ := getTestPaths(base)
   801  				subpath := filepath.Join(volpath, "dir0")
   802  				symlinkBase := filepath.Join(volpath, "..")
   803  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   804  					return nil, "", "", err
   805  				}
   806  
   807  				// create symlink for subpath
   808  				return nil, volpath, subpath, os.Symlink(symlinkBase, subpath)
   809  			},
   810  			expectError: true,
   811  		},
   812  		{
   813  			name: "subpath-mountdir-already-exists",
   814  			prepare: func(base string) ([]string, string, string, error) {
   815  				volpath, subpathMount := getTestPaths(base)
   816  				if err := os.MkdirAll(subpathMount, defaultPerm); err != nil {
   817  					return nil, "", "", err
   818  				}
   819  
   820  				subpath := filepath.Join(volpath, "dir0")
   821  				return nil, volpath, subpath, os.MkdirAll(subpath, defaultPerm)
   822  			},
   823  			expectError: false,
   824  		},
   825  		{
   826  			name: "subpath-mount-already-exists",
   827  			prepare: func(base string) ([]string, string, string, error) {
   828  				volpath, subpathMount := getTestPaths(base)
   829  				mounts := []string{subpathMount}
   830  				if err := os.MkdirAll(subpathMount, defaultPerm); err != nil {
   831  					return nil, "", "", err
   832  				}
   833  
   834  				subpath := filepath.Join(volpath, "dir0")
   835  				return mounts, volpath, subpath, os.MkdirAll(subpath, defaultPerm)
   836  			},
   837  			expectError: false,
   838  		},
   839  		{
   840  			name: "mount-unix-socket",
   841  			prepare: func(base string) ([]string, string, string, error) {
   842  				volpath, subpathMount := getTestPaths(base)
   843  				mounts := []string{subpathMount}
   844  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   845  					return nil, "", "", err
   846  				}
   847  
   848  				socketFile, socketCreateError := createSocketFile(volpath)
   849  
   850  				return mounts, volpath, socketFile, socketCreateError
   851  			},
   852  			expectError: false,
   853  		},
   854  		{
   855  			name: "subpath-mounting-fifo",
   856  			prepare: func(base string) ([]string, string, string, error) {
   857  				volpath, subpathMount := getTestPaths(base)
   858  				mounts := []string{subpathMount}
   859  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   860  					return nil, "", "", err
   861  				}
   862  
   863  				testFifo := filepath.Join(volpath, "mount_test.fifo")
   864  				err := syscall.Mkfifo(testFifo, 0)
   865  				return mounts, volpath, testFifo, err
   866  			},
   867  			expectError: false,
   868  		},
   869  	}
   870  
   871  	for _, test := range tests {
   872  		klog.V(4).Infof("test %q", test.name)
   873  		base, err := ioutil.TempDir("", "bind-subpath-"+test.name+"-")
   874  		if err != nil {
   875  			t.Fatalf(err.Error())
   876  		}
   877  
   878  		mounts, volPath, subPath, err := test.prepare(base)
   879  		if err != nil {
   880  			os.RemoveAll(base)
   881  			t.Fatalf("failed to prepare test %q: %v", test.name, err.Error())
   882  		}
   883  
   884  		fm := setupFakeMounter(mounts)
   885  
   886  		subpath := Subpath{
   887  			VolumeMountIndex: testSubpath,
   888  			Path:             subPath,
   889  			VolumeName:       testVol,
   890  			VolumePath:       volPath,
   891  			PodDir:           filepath.Join(base, "pod0"),
   892  			ContainerName:    testContainer,
   893  		}
   894  
   895  		_, subpathMount := getTestPaths(base)
   896  		bindPathTarget, err := doBindSubPath(fm, subpath)
   897  		if test.expectError {
   898  			if err == nil {
   899  				t.Errorf("test %q failed: expected error, got success", test.name)
   900  			}
   901  			if bindPathTarget != "" {
   902  				t.Errorf("test %q failed: expected empty bindPathTarget, got %v", test.name, bindPathTarget)
   903  			}
   904  			if err = validateDirNotExists(subpathMount); err != nil {
   905  				t.Errorf("test %q failed: %v", test.name, err)
   906  			}
   907  		}
   908  		if !test.expectError {
   909  			if err != nil {
   910  				t.Errorf("test %q failed: %v", test.name, err)
   911  			}
   912  			if bindPathTarget != subpathMount {
   913  				t.Errorf("test %q failed: expected bindPathTarget %v, got %v", test.name, subpathMount, bindPathTarget)
   914  			}
   915  			if err = validateFileExists(subpathMount); err != nil {
   916  				t.Errorf("test %q failed: %v", test.name, err)
   917  			}
   918  		}
   919  
   920  		os.RemoveAll(base)
   921  	}
   922  }
   923  
   924  func TestSubpath_PrepareSafeSubpath(t *testing.T) {
   925  	//complete code
   926  	defaultPerm := os.FileMode(0750)
   927  
   928  	tests := []struct {
   929  		name string
   930  		// Function that prepares directory structure for the test under given
   931  		// base.
   932  		prepare      func(base string) ([]string, string, string, error)
   933  		expectError  bool
   934  		expectAction []mount.FakeAction
   935  		mountExists  bool
   936  	}{
   937  		{
   938  			name: "subpath-mount-already-exists-with-mismatching-mount",
   939  			prepare: func(base string) ([]string, string, string, error) {
   940  				volpath, subpathMount := getTestPaths(base)
   941  				mounts := []string{subpathMount}
   942  				if err := os.MkdirAll(subpathMount, defaultPerm); err != nil {
   943  					return nil, "", "", err
   944  				}
   945  
   946  				subpath := filepath.Join(volpath, "dir0")
   947  				return mounts, volpath, subpath, os.MkdirAll(subpath, defaultPerm)
   948  			},
   949  			expectError:  false,
   950  			expectAction: []mount.FakeAction{{Action: "unmount"}},
   951  			mountExists:  false,
   952  		},
   953  		{
   954  			name: "subpath-mount-already-exists-with-samefile",
   955  			prepare: func(base string) ([]string, string, string, error) {
   956  				volpath, subpathMount := getTestPaths(base)
   957  				mounts := []string{subpathMount}
   958  				subpathMountRoot := filepath.Dir(subpathMount)
   959  
   960  				if err := os.MkdirAll(subpathMountRoot, defaultPerm); err != nil {
   961  					return nil, "", "", err
   962  				}
   963  				targetFile, err := os.Create(subpathMount)
   964  				if err != nil {
   965  					return nil, "", "", err
   966  				}
   967  				defer targetFile.Close()
   968  
   969  				if err := os.MkdirAll(volpath, defaultPerm); err != nil {
   970  					return nil, "", "", err
   971  				}
   972  				subpath := filepath.Join(volpath, "file0")
   973  				// using hard link to simulate bind mounts
   974  				err = os.Link(subpathMount, subpath)
   975  				if err != nil {
   976  					return nil, "", "", err
   977  				}
   978  				return mounts, volpath, subpath, nil
   979  			},
   980  			expectError:  false,
   981  			expectAction: []mount.FakeAction{},
   982  			mountExists:  true,
   983  		},
   984  	}
   985  	for _, test := range tests {
   986  		klog.V(4).Infof("test %q", test.name)
   987  		base, err := ioutil.TempDir("", "bind-subpath-"+test.name+"-")
   988  		if err != nil {
   989  			t.Fatalf(err.Error())
   990  		}
   991  		defer os.RemoveAll(base)
   992  
   993  		mounts, volPath, subPath, err := test.prepare(base)
   994  		if err != nil {
   995  			os.RemoveAll(base)
   996  			t.Fatalf("failed to prepare test %q: %v", test.name, err.Error())
   997  		}
   998  
   999  		fm := setupFakeMounter(mounts)
  1000  
  1001  		subpath := Subpath{
  1002  			VolumeMountIndex: testSubpath,
  1003  			Path:             subPath,
  1004  			VolumeName:       testVol,
  1005  			VolumePath:       volPath,
  1006  			PodDir:           filepath.Join(base, "pod0"),
  1007  			ContainerName:    testContainer,
  1008  		}
  1009  
  1010  		_, subpathMount := getTestPaths(base)
  1011  		bindMountExists, bindPathTarget, err := prepareSubpathTarget(fm, subpath)
  1012  
  1013  		if bindMountExists != test.mountExists {
  1014  			t.Errorf("test %q failed: expected bindMountExists %v, got %v", test.name, test.mountExists, bindMountExists)
  1015  		}
  1016  
  1017  		logActions := fm.GetLog()
  1018  		if len(test.expectAction) == 0 && len(logActions) > 0 {
  1019  			t.Errorf("test %q failed: expected no actions, got %v", test.name, logActions)
  1020  		}
  1021  
  1022  		if len(test.expectAction) > 0 {
  1023  			foundMatchingAction := false
  1024  			testAction := test.expectAction[0]
  1025  			for _, action := range logActions {
  1026  				if action.Action == testAction.Action {
  1027  					foundMatchingAction = true
  1028  					break
  1029  				}
  1030  			}
  1031  			if !foundMatchingAction {
  1032  				t.Errorf("test %q failed: expected action %q, got %v", test.name, testAction.Action, logActions)
  1033  			}
  1034  		}
  1035  
  1036  		if test.expectError {
  1037  			if err == nil {
  1038  				t.Errorf("test %q failed: expected error, got success", test.name)
  1039  			}
  1040  			if bindPathTarget != "" {
  1041  				t.Errorf("test %q failed: expected empty bindPathTarget, got %v", test.name, bindPathTarget)
  1042  			}
  1043  			if err = validateDirNotExists(subpathMount); err != nil {
  1044  				t.Errorf("test %q failed: %v", test.name, err)
  1045  			}
  1046  		}
  1047  		if !test.expectError {
  1048  			if err != nil {
  1049  				t.Errorf("test %q failed: %v", test.name, err)
  1050  			}
  1051  			if bindPathTarget != subpathMount {
  1052  				t.Errorf("test %q failed: expected bindPathTarget %v, got %v", test.name, subpathMount, bindPathTarget)
  1053  			}
  1054  			if err = validateFileExists(subpathMount); err != nil {
  1055  				t.Errorf("test %q failed: %v", test.name, err)
  1056  			}
  1057  		}
  1058  	}
  1059  }
  1060  
  1061  func TestSafeOpen(t *testing.T) {
  1062  	defaultPerm := os.FileMode(0750)
  1063  
  1064  	tests := []struct {
  1065  		name string
  1066  		// Function that prepares directory structure for the test under given
  1067  		// base.
  1068  		prepare     func(base string) error
  1069  		path        string
  1070  		expectError bool
  1071  	}{
  1072  		{
  1073  			"directory-does-not-exist",
  1074  			func(base string) error {
  1075  				return nil
  1076  			},
  1077  			"test/directory",
  1078  			true,
  1079  		},
  1080  		{
  1081  			"directory-exists",
  1082  			func(base string) error {
  1083  				return os.MkdirAll(filepath.Join(base, "test/directory"), 0750)
  1084  			},
  1085  			"test/directory",
  1086  			false,
  1087  		},
  1088  		{
  1089  			"escape-base-using-dots",
  1090  			func(base string) error {
  1091  				return nil
  1092  			},
  1093  			"..",
  1094  			true,
  1095  		},
  1096  		{
  1097  			"escape-base-using-dots-2",
  1098  			func(base string) error {
  1099  				return os.MkdirAll(filepath.Join(base, "test"), 0750)
  1100  			},
  1101  			"test/../../..",
  1102  			true,
  1103  		},
  1104  		{
  1105  			"symlink",
  1106  			func(base string) error {
  1107  				if err := os.MkdirAll(filepath.Join(base, "destination"), defaultPerm); err != nil {
  1108  					return err
  1109  				}
  1110  				return os.Symlink("destination", filepath.Join(base, "test"))
  1111  			},
  1112  			"test",
  1113  			true,
  1114  		},
  1115  		{
  1116  			"symlink-nested",
  1117  			func(base string) error {
  1118  				if err := os.MkdirAll(filepath.Join(base, "dir1/dir2"), defaultPerm); err != nil {
  1119  					return err
  1120  				}
  1121  				return os.Symlink("dir1", filepath.Join(base, "dir1/dir2/test"))
  1122  			},
  1123  			"test",
  1124  			true,
  1125  		},
  1126  		{
  1127  			"symlink-loop",
  1128  			func(base string) error {
  1129  				return os.Symlink("test", filepath.Join(base, "test"))
  1130  			},
  1131  			"test",
  1132  			true,
  1133  		},
  1134  		{
  1135  			"symlink-not-exists",
  1136  			func(base string) error {
  1137  				return os.Symlink("non-existing", filepath.Join(base, "test"))
  1138  			},
  1139  			"test",
  1140  			true,
  1141  		},
  1142  		{
  1143  			"non-directory",
  1144  			func(base string) error {
  1145  				return ioutil.WriteFile(filepath.Join(base, "test"), []byte{}, defaultPerm)
  1146  			},
  1147  			"test/directory",
  1148  			true,
  1149  		},
  1150  		{
  1151  			"non-directory-final",
  1152  			func(base string) error {
  1153  				return ioutil.WriteFile(filepath.Join(base, "test"), []byte{}, defaultPerm)
  1154  			},
  1155  			"test",
  1156  			false,
  1157  		},
  1158  		{
  1159  			"escape-with-relative-symlink",
  1160  			func(base string) error {
  1161  				if err := os.MkdirAll(filepath.Join(base, "dir"), defaultPerm); err != nil {
  1162  					return err
  1163  				}
  1164  				if err := os.MkdirAll(filepath.Join(base, "exists"), defaultPerm); err != nil {
  1165  					return err
  1166  				}
  1167  				return os.Symlink("../exists", filepath.Join(base, "dir/test"))
  1168  			},
  1169  			"dir/test",
  1170  			true,
  1171  		},
  1172  		{
  1173  			"escape-with-relative-symlink-not-exists",
  1174  			func(base string) error {
  1175  				if err := os.MkdirAll(filepath.Join(base, "dir"), defaultPerm); err != nil {
  1176  					return err
  1177  				}
  1178  				return os.Symlink("../not-exists", filepath.Join(base, "dir/test"))
  1179  			},
  1180  			"dir/test",
  1181  			true,
  1182  		},
  1183  		{
  1184  			"escape-with-symlink",
  1185  			func(base string) error {
  1186  				return os.Symlink("/", filepath.Join(base, "test"))
  1187  			},
  1188  			"test",
  1189  			true,
  1190  		},
  1191  		{
  1192  			"mount-unix-socket",
  1193  			func(base string) error {
  1194  				socketFile, socketError := createSocketFile(base)
  1195  
  1196  				if socketError != nil {
  1197  					return fmt.Errorf("error preparing socket file %s with %w", socketFile, socketError)
  1198  				}
  1199  				return nil
  1200  			},
  1201  			"mt.sock",
  1202  			false,
  1203  		},
  1204  		{
  1205  			"mounting-unix-socket-in-middle",
  1206  			func(base string) error {
  1207  				testSocketFile, socketError := createSocketFile(base)
  1208  
  1209  				if socketError != nil {
  1210  					return fmt.Errorf("error preparing socket file %s with %w", testSocketFile, socketError)
  1211  				}
  1212  				return nil
  1213  			},
  1214  			"mt.sock/bar",
  1215  			true,
  1216  		},
  1217  	}
  1218  
  1219  	for _, test := range tests {
  1220  		klog.V(4).Infof("test %q", test.name)
  1221  		base, err := ioutil.TempDir("", "safe-open-"+test.name+"-")
  1222  		if err != nil {
  1223  			t.Fatalf(err.Error())
  1224  		}
  1225  
  1226  		test.prepare(base)
  1227  		pathToCreate := filepath.Join(base, test.path)
  1228  		fd, err := doSafeOpen(pathToCreate, base)
  1229  		if err != nil && !test.expectError {
  1230  			t.Errorf("test %q: %s", test.name, err)
  1231  		}
  1232  		if err != nil {
  1233  			klog.Infof("got error: %s", err)
  1234  		}
  1235  		if err == nil && test.expectError {
  1236  			t.Errorf("test %q: expected error, got none", test.name)
  1237  		}
  1238  
  1239  		syscall.Close(fd)
  1240  		os.RemoveAll(base)
  1241  	}
  1242  }
  1243  
  1244  func createSocketFile(socketDir string) (string, error) {
  1245  	testSocketFile := filepath.Join(socketDir, "mt.sock")
  1246  
  1247  	// Switch to volume path and create the socket file
  1248  	// socket file can not have length of more than 108 character
  1249  	// and hence we must use relative path
  1250  	oldDir, _ := os.Getwd()
  1251  
  1252  	err := os.Chdir(socketDir)
  1253  	if err != nil {
  1254  		return "", err
  1255  	}
  1256  	defer func() {
  1257  		os.Chdir(oldDir)
  1258  	}()
  1259  	_, socketCreateError := net.Listen("unix", "mt.sock")
  1260  	return testSocketFile, socketCreateError
  1261  }
  1262  
  1263  func TestFindExistingPrefix(t *testing.T) {
  1264  	defaultPerm := os.FileMode(0750)
  1265  	tests := []struct {
  1266  		name string
  1267  		// Function that prepares directory structure for the test under given
  1268  		// base.
  1269  		prepare      func(base string) error
  1270  		path         string
  1271  		expectedPath string
  1272  		expectedDirs []string
  1273  		expectError  bool
  1274  	}{
  1275  		{
  1276  			"directory-does-not-exist",
  1277  			func(base string) error {
  1278  				return nil
  1279  			},
  1280  			"directory",
  1281  			"",
  1282  			[]string{"directory"},
  1283  			false,
  1284  		},
  1285  		{
  1286  			"directory-exists",
  1287  			func(base string) error {
  1288  				return os.MkdirAll(filepath.Join(base, "test/directory"), 0750)
  1289  			},
  1290  			"test/directory",
  1291  			"test/directory",
  1292  			[]string{},
  1293  			false,
  1294  		},
  1295  		{
  1296  			"follow-symlinks",
  1297  			func(base string) error {
  1298  				if err := os.MkdirAll(filepath.Join(base, "destination/directory"), defaultPerm); err != nil {
  1299  					return err
  1300  				}
  1301  				return os.Symlink("destination", filepath.Join(base, "test"))
  1302  			},
  1303  			"test/directory",
  1304  			"test/directory",
  1305  			[]string{},
  1306  			false,
  1307  		},
  1308  		{
  1309  			"follow-symlink-loop",
  1310  			func(base string) error {
  1311  				return os.Symlink("test", filepath.Join(base, "test"))
  1312  			},
  1313  			"test/directory",
  1314  			"",
  1315  			nil,
  1316  			true,
  1317  		},
  1318  		{
  1319  			"follow-symlink-multiple follow",
  1320  			func(base string) error {
  1321  				/* test1/dir points to test2 and test2/dir points to test1 */
  1322  				if err := os.MkdirAll(filepath.Join(base, "test1"), defaultPerm); err != nil {
  1323  					return err
  1324  				}
  1325  				if err := os.MkdirAll(filepath.Join(base, "test2"), defaultPerm); err != nil {
  1326  					return err
  1327  				}
  1328  				if err := os.Symlink(filepath.Join(base, "test2"), filepath.Join(base, "test1/dir")); err != nil {
  1329  					return err
  1330  				}
  1331  				if err := os.Symlink(filepath.Join(base, "test1"), filepath.Join(base, "test2/dir")); err != nil {
  1332  					return err
  1333  				}
  1334  				return nil
  1335  			},
  1336  			"test1/dir/dir/foo/bar",
  1337  			"test1/dir/dir",
  1338  			[]string{"foo", "bar"},
  1339  			false,
  1340  		},
  1341  		{
  1342  			"danglink-symlink",
  1343  			func(base string) error {
  1344  				return os.Symlink("non-existing", filepath.Join(base, "test"))
  1345  			},
  1346  			// OS returns IsNotExist error both for dangling symlink and for
  1347  			// non-existing directory.
  1348  			"test/directory",
  1349  			"",
  1350  			[]string{"test", "directory"},
  1351  			false,
  1352  		},
  1353  		{
  1354  			"with-fifo-in-middle",
  1355  			func(base string) error {
  1356  				testFifo := filepath.Join(base, "mount_test.fifo")
  1357  				return syscall.Mkfifo(testFifo, 0)
  1358  			},
  1359  			"mount_test.fifo/directory",
  1360  			"",
  1361  			nil,
  1362  			true,
  1363  		},
  1364  	}
  1365  
  1366  	for _, test := range tests {
  1367  		klog.V(4).Infof("test %q", test.name)
  1368  		base, err := ioutil.TempDir("", "find-prefix-"+test.name+"-")
  1369  		if err != nil {
  1370  			t.Fatalf(err.Error())
  1371  		}
  1372  		test.prepare(base)
  1373  		path := filepath.Join(base, test.path)
  1374  		existingPath, dirs, err := findExistingPrefix(base, path)
  1375  		if err != nil && !test.expectError {
  1376  			t.Errorf("test %q: %s", test.name, err)
  1377  		}
  1378  		if err != nil {
  1379  			klog.Infof("got error: %s", err)
  1380  		}
  1381  		if err == nil && test.expectError {
  1382  			t.Errorf("test %q: expected error, got none", test.name)
  1383  		}
  1384  
  1385  		fullExpectedPath := filepath.Join(base, test.expectedPath)
  1386  		if existingPath != fullExpectedPath {
  1387  			t.Errorf("test %q: expected path %q, got %q", test.name, fullExpectedPath, existingPath)
  1388  		}
  1389  		if !reflect.DeepEqual(dirs, test.expectedDirs) {
  1390  			t.Errorf("test %q: expected dirs %v, got %v", test.name, test.expectedDirs, dirs)
  1391  		}
  1392  		os.RemoveAll(base)
  1393  	}
  1394  }
  1395  
  1396  func validateDirEmpty(dir string) error {
  1397  	files, err := ioutil.ReadDir(dir)
  1398  	if err != nil {
  1399  		return err
  1400  	}
  1401  
  1402  	if len(files) != 0 {
  1403  		return fmt.Errorf("directory %q is not empty", dir)
  1404  	}
  1405  	return nil
  1406  }
  1407  
  1408  func validateDirExists(dir string) error {
  1409  	_, err := ioutil.ReadDir(dir)
  1410  	if err != nil {
  1411  		return err
  1412  	}
  1413  	return nil
  1414  }
  1415  
  1416  func validateDirNotExists(dir string) error {
  1417  	_, err := ioutil.ReadDir(dir)
  1418  	if os.IsNotExist(err) {
  1419  		return nil
  1420  	}
  1421  	if err != nil {
  1422  		return err
  1423  	}
  1424  	return fmt.Errorf("dir %q still exists", dir)
  1425  }
  1426  
  1427  func validateFileExists(file string) error {
  1428  	if _, err := os.Stat(file); err != nil {
  1429  		return err
  1430  	}
  1431  	return nil
  1432  }
  1433  

View as plain text