Source file src/os/stat_test.go

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os_test
     6  
     7  import (
     8  	"internal/testenv"
     9  	"io/fs"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  )
    14  
    15  // testStatAndLstat verifies that all os.Stat, os.Lstat os.File.Stat and os.Readdir work.
    16  func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, fs.FileInfo)) {
    17  	// test os.Stat
    18  	sfi, err := os.Stat(path)
    19  	if err != nil {
    20  		t.Error(err)
    21  		return
    22  	}
    23  	statCheck(t, path, sfi)
    24  
    25  	// test os.Lstat
    26  	lsfi, err := os.Lstat(path)
    27  	if err != nil {
    28  		t.Error(err)
    29  		return
    30  	}
    31  	lstatCheck(t, path, lsfi)
    32  
    33  	if isLink {
    34  		if os.SameFile(sfi, lsfi) {
    35  			t.Errorf("stat and lstat of %q should not be the same", path)
    36  		}
    37  	} else {
    38  		if !os.SameFile(sfi, lsfi) {
    39  			t.Errorf("stat and lstat of %q should be the same", path)
    40  		}
    41  	}
    42  
    43  	// test os.File.Stat
    44  	f, err := os.Open(path)
    45  	if err != nil {
    46  		t.Error(err)
    47  		return
    48  	}
    49  	defer f.Close()
    50  
    51  	sfi2, err := f.Stat()
    52  	if err != nil {
    53  		t.Error(err)
    54  		return
    55  	}
    56  	statCheck(t, path, sfi2)
    57  
    58  	if !os.SameFile(sfi, sfi2) {
    59  		t.Errorf("stat of open %q file and stat of %q should be the same", path, path)
    60  	}
    61  
    62  	if isLink {
    63  		if os.SameFile(sfi2, lsfi) {
    64  			t.Errorf("stat of opened %q file and lstat of %q should not be the same", path, path)
    65  		}
    66  	} else {
    67  		if !os.SameFile(sfi2, lsfi) {
    68  			t.Errorf("stat of opened %q file and lstat of %q should be the same", path, path)
    69  		}
    70  	}
    71  
    72  	// test fs.FileInfo returned by os.Readdir
    73  	if len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
    74  		// skip os.Readdir test of directories with slash at the end
    75  		return
    76  	}
    77  	parentdir := filepath.Dir(path)
    78  	parent, err := os.Open(parentdir)
    79  	if err != nil {
    80  		t.Error(err)
    81  		return
    82  	}
    83  	defer parent.Close()
    84  
    85  	fis, err := parent.Readdir(-1)
    86  	if err != nil {
    87  		t.Error(err)
    88  		return
    89  	}
    90  	var lsfi2 fs.FileInfo
    91  	base := filepath.Base(path)
    92  	for _, fi2 := range fis {
    93  		if fi2.Name() == base {
    94  			lsfi2 = fi2
    95  			break
    96  		}
    97  	}
    98  	if lsfi2 == nil {
    99  		t.Errorf("failed to find %q in its parent", path)
   100  		return
   101  	}
   102  	lstatCheck(t, path, lsfi2)
   103  
   104  	if !os.SameFile(lsfi, lsfi2) {
   105  		t.Errorf("lstat of %q file in %q directory and %q should be the same", lsfi2.Name(), parentdir, path)
   106  	}
   107  }
   108  
   109  // testIsDir verifies that fi refers to directory.
   110  func testIsDir(t *testing.T, path string, fi fs.FileInfo) {
   111  	t.Helper()
   112  	if !fi.IsDir() {
   113  		t.Errorf("%q should be a directory", path)
   114  	}
   115  	if fi.Mode()&fs.ModeSymlink != 0 {
   116  		t.Errorf("%q should not be a symlink", path)
   117  	}
   118  }
   119  
   120  // testIsSymlink verifies that fi refers to symlink.
   121  func testIsSymlink(t *testing.T, path string, fi fs.FileInfo) {
   122  	t.Helper()
   123  	if fi.IsDir() {
   124  		t.Errorf("%q should not be a directory", path)
   125  	}
   126  	if fi.Mode()&fs.ModeSymlink == 0 {
   127  		t.Errorf("%q should be a symlink", path)
   128  	}
   129  }
   130  
   131  // testIsFile verifies that fi refers to file.
   132  func testIsFile(t *testing.T, path string, fi fs.FileInfo) {
   133  	t.Helper()
   134  	if fi.IsDir() {
   135  		t.Errorf("%q should not be a directory", path)
   136  	}
   137  	if fi.Mode()&fs.ModeSymlink != 0 {
   138  		t.Errorf("%q should not be a symlink", path)
   139  	}
   140  }
   141  
   142  func testDirStats(t *testing.T, path string) {
   143  	testStatAndLstat(t, path, false, testIsDir, testIsDir)
   144  }
   145  
   146  func testFileStats(t *testing.T, path string) {
   147  	testStatAndLstat(t, path, false, testIsFile, testIsFile)
   148  }
   149  
   150  func testSymlinkStats(t *testing.T, path string, isdir bool) {
   151  	if isdir {
   152  		testStatAndLstat(t, path, true, testIsDir, testIsSymlink)
   153  	} else {
   154  		testStatAndLstat(t, path, true, testIsFile, testIsSymlink)
   155  	}
   156  }
   157  
   158  func testSymlinkSameFile(t *testing.T, path, link string) {
   159  	pathfi, err := os.Stat(path)
   160  	if err != nil {
   161  		t.Error(err)
   162  		return
   163  	}
   164  
   165  	linkfi, err := os.Stat(link)
   166  	if err != nil {
   167  		t.Error(err)
   168  		return
   169  	}
   170  	if !os.SameFile(pathfi, linkfi) {
   171  		t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", path, link)
   172  	}
   173  
   174  	linkfi, err = os.Lstat(link)
   175  	if err != nil {
   176  		t.Error(err)
   177  		return
   178  	}
   179  	if os.SameFile(pathfi, linkfi) {
   180  		t.Errorf("os.Stat(%q) and os.Lstat(%q) are the same file", path, link)
   181  	}
   182  }
   183  
   184  func testSymlinkSameFileOpen(t *testing.T, link string) {
   185  	f, err := os.Open(link)
   186  	if err != nil {
   187  		t.Error(err)
   188  		return
   189  	}
   190  	defer f.Close()
   191  
   192  	fi, err := f.Stat()
   193  	if err != nil {
   194  		t.Error(err)
   195  		return
   196  	}
   197  
   198  	fi2, err := os.Stat(link)
   199  	if err != nil {
   200  		t.Error(err)
   201  		return
   202  	}
   203  
   204  	if !os.SameFile(fi, fi2) {
   205  		t.Errorf("os.Open(%q).Stat() and os.Stat(%q) are not the same file", link, link)
   206  	}
   207  }
   208  
   209  func TestDirAndSymlinkStats(t *testing.T) {
   210  	testenv.MustHaveSymlink(t)
   211  	t.Parallel()
   212  
   213  	tmpdir := t.TempDir()
   214  	dir := filepath.Join(tmpdir, "dir")
   215  	if err := os.Mkdir(dir, 0777); err != nil {
   216  		t.Fatal(err)
   217  	}
   218  	testDirStats(t, dir)
   219  
   220  	dirlink := filepath.Join(tmpdir, "link")
   221  	if err := os.Symlink(dir, dirlink); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	testSymlinkStats(t, dirlink, true)
   225  	testSymlinkSameFile(t, dir, dirlink)
   226  	testSymlinkSameFileOpen(t, dirlink)
   227  
   228  	linklink := filepath.Join(tmpdir, "linklink")
   229  	if err := os.Symlink(dirlink, linklink); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	testSymlinkStats(t, linklink, true)
   233  	testSymlinkSameFile(t, dir, linklink)
   234  	testSymlinkSameFileOpen(t, linklink)
   235  }
   236  
   237  func TestFileAndSymlinkStats(t *testing.T) {
   238  	testenv.MustHaveSymlink(t)
   239  	t.Parallel()
   240  
   241  	tmpdir := t.TempDir()
   242  	file := filepath.Join(tmpdir, "file")
   243  	if err := os.WriteFile(file, []byte(""), 0644); err != nil {
   244  		t.Fatal(err)
   245  	}
   246  	testFileStats(t, file)
   247  
   248  	filelink := filepath.Join(tmpdir, "link")
   249  	if err := os.Symlink(file, filelink); err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	testSymlinkStats(t, filelink, false)
   253  	testSymlinkSameFile(t, file, filelink)
   254  	testSymlinkSameFileOpen(t, filelink)
   255  
   256  	linklink := filepath.Join(tmpdir, "linklink")
   257  	if err := os.Symlink(filelink, linklink); err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	testSymlinkStats(t, linklink, false)
   261  	testSymlinkSameFile(t, file, linklink)
   262  	testSymlinkSameFileOpen(t, linklink)
   263  }
   264  
   265  // see issue 27225 for details
   266  func TestSymlinkWithTrailingSlash(t *testing.T) {
   267  	testenv.MustHaveSymlink(t)
   268  	t.Parallel()
   269  
   270  	tmpdir := t.TempDir()
   271  	dir := filepath.Join(tmpdir, "dir")
   272  	if err := os.Mkdir(dir, 0777); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	dirlink := filepath.Join(tmpdir, "link")
   276  	if err := os.Symlink(dir, dirlink); err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	dirlinkWithSlash := dirlink + string(os.PathSeparator)
   280  
   281  	testDirStats(t, dirlinkWithSlash)
   282  
   283  	fi1, err := os.Stat(dir)
   284  	if err != nil {
   285  		t.Error(err)
   286  		return
   287  	}
   288  	fi2, err := os.Stat(dirlinkWithSlash)
   289  	if err != nil {
   290  		t.Error(err)
   291  		return
   292  	}
   293  	if !os.SameFile(fi1, fi2) {
   294  		t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", dir, dirlinkWithSlash)
   295  	}
   296  }
   297  

View as plain text