github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/hugofs/nosymlink_test.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     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  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package hugofs
    15  
    16  import (
    17  	"os"
    18  	"path/filepath"
    19  	"testing"
    20  
    21  	"github.com/bep/logg"
    22  	"github.com/gohugoio/hugo/common/loggers"
    23  	"github.com/gohugoio/hugo/htesting"
    24  
    25  	"github.com/spf13/afero"
    26  
    27  	qt "github.com/frankban/quicktest"
    28  )
    29  
    30  func prepareSymlinks(t *testing.T) (string, func()) {
    31  	c := qt.New(t)
    32  
    33  	workDir, clean, err := htesting.CreateTempDir(Os, "hugo-symlink-test")
    34  	c.Assert(err, qt.IsNil)
    35  	wd, _ := os.Getwd()
    36  
    37  	blogDir := filepath.Join(workDir, "blog")
    38  	blogSubDir := filepath.Join(blogDir, "sub")
    39  	c.Assert(os.MkdirAll(blogSubDir, 0777), qt.IsNil)
    40  	blogFile1 := filepath.Join(blogDir, "a.txt")
    41  	blogFile2 := filepath.Join(blogSubDir, "b.txt")
    42  	afero.WriteFile(Os, filepath.Join(blogFile1), []byte("content1"), 0777)
    43  	afero.WriteFile(Os, filepath.Join(blogFile2), []byte("content2"), 0777)
    44  	os.Chdir(workDir)
    45  	c.Assert(os.Symlink("blog", "symlinkdedir"), qt.IsNil)
    46  	os.Chdir(blogDir)
    47  	c.Assert(os.Symlink("sub", "symsub"), qt.IsNil)
    48  	c.Assert(os.Symlink("a.txt", "symlinkdedfile.txt"), qt.IsNil)
    49  
    50  	return workDir, func() {
    51  		clean()
    52  		os.Chdir(wd)
    53  	}
    54  }
    55  
    56  func TestNoSymlinkFs(t *testing.T) {
    57  	if skipSymlink() {
    58  		t.Skip("Skip; os.Symlink needs administrator rights on Windows")
    59  	}
    60  	c := qt.New(t)
    61  	workDir, clean := prepareSymlinks(t)
    62  	defer clean()
    63  
    64  	blogDir := filepath.Join(workDir, "blog")
    65  	blogFile1 := filepath.Join(blogDir, "a.txt")
    66  
    67  	logger := loggers.NewDefault()
    68  
    69  	for _, bfs := range []afero.Fs{NewBaseFileDecorator(Os), Os} {
    70  		for _, allowFiles := range []bool{false, true} {
    71  			logger.Reset()
    72  			fs := NewNoSymlinkFs(bfs, logger, allowFiles)
    73  			ls := fs.(afero.Lstater)
    74  			symlinkedDir := filepath.Join(workDir, "symlinkdedir")
    75  			symlinkedFilename := "symlinkdedfile.txt"
    76  			symlinkedFile := filepath.Join(blogDir, symlinkedFilename)
    77  
    78  			assertFileErr := func(err error) {
    79  				if allowFiles {
    80  					c.Assert(err, qt.IsNil)
    81  				} else {
    82  					c.Assert(err, qt.Equals, ErrPermissionSymlink)
    83  				}
    84  			}
    85  
    86  			assertFileStat := func(name string, fi os.FileInfo, err error) {
    87  				t.Helper()
    88  				assertFileErr(err)
    89  				if err == nil {
    90  					c.Assert(fi, qt.Not(qt.IsNil))
    91  					c.Assert(fi.Name(), qt.Equals, name)
    92  				}
    93  			}
    94  
    95  			// Check Stat and Lstat
    96  			for _, stat := range []func(name string) (os.FileInfo, error){
    97  				func(name string) (os.FileInfo, error) {
    98  					return fs.Stat(name)
    99  				},
   100  				func(name string) (os.FileInfo, error) {
   101  					fi, _, err := ls.LstatIfPossible(name)
   102  					return fi, err
   103  				},
   104  			} {
   105  				_, err := stat(symlinkedDir)
   106  				c.Assert(err, qt.Equals, ErrPermissionSymlink)
   107  				fi, err := stat(symlinkedFile)
   108  				assertFileStat(symlinkedFilename, fi, err)
   109  
   110  				fi, err = stat(filepath.Join(workDir, "blog"))
   111  				c.Assert(err, qt.IsNil)
   112  				c.Assert(fi, qt.Not(qt.IsNil))
   113  
   114  				fi, err = stat(blogFile1)
   115  				c.Assert(err, qt.IsNil)
   116  				c.Assert(fi, qt.Not(qt.IsNil))
   117  			}
   118  
   119  			// Check Open
   120  			_, err := fs.Open(symlinkedDir)
   121  			c.Assert(err, qt.Equals, ErrPermissionSymlink)
   122  			_, err = fs.OpenFile(symlinkedDir, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
   123  			c.Assert(err, qt.Equals, ErrPermissionSymlink)
   124  			_, err = fs.OpenFile(symlinkedFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
   125  			assertFileErr(err)
   126  			_, err = fs.Open(symlinkedFile)
   127  			assertFileErr(err)
   128  			f, err := fs.Open(blogDir)
   129  			c.Assert(err, qt.IsNil)
   130  			f.Close()
   131  			f, err = fs.Open(blogFile1)
   132  			c.Assert(err, qt.IsNil)
   133  			f.Close()
   134  
   135  			// Check readdir
   136  			f, err = fs.Open(workDir)
   137  			c.Assert(err, qt.IsNil)
   138  			// There is at least one unsupported symlink inside workDir
   139  			_, err = f.Readdir(-1)
   140  			c.Assert(err, qt.IsNil)
   141  			f.Close()
   142  			c.Assert(logger.LoggCount(logg.LevelWarn), qt.Equals, 1)
   143  
   144  		}
   145  	}
   146  }