mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	
		
			
				
	
	
		
			243 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
package chroot
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/go-git/go-billy/v5"
 | 
						|
	"github.com/go-git/go-billy/v5/helper/polyfill"
 | 
						|
)
 | 
						|
 | 
						|
// ChrootHelper is a helper to implement billy.Chroot.
 | 
						|
type ChrootHelper struct {
 | 
						|
	underlying billy.Filesystem
 | 
						|
	base       string
 | 
						|
}
 | 
						|
 | 
						|
// New creates a new filesystem wrapping up the given 'fs'.
 | 
						|
// The created filesystem has its base in the given ChrootHelperectory of the
 | 
						|
// underlying filesystem.
 | 
						|
func New(fs billy.Basic, base string) billy.Filesystem {
 | 
						|
	return &ChrootHelper{
 | 
						|
		underlying: polyfill.New(fs),
 | 
						|
		base:       base,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) underlyingPath(filename string) (string, error) {
 | 
						|
	if isCrossBoundaries(filename) {
 | 
						|
		return "", billy.ErrCrossedBoundary
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.Join(fs.Root(), filename), nil
 | 
						|
}
 | 
						|
 | 
						|
func isCrossBoundaries(path string) bool {
 | 
						|
	path = filepath.ToSlash(path)
 | 
						|
	path = filepath.Clean(path)
 | 
						|
 | 
						|
	return strings.HasPrefix(path, ".."+string(filepath.Separator))
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Create(filename string) (billy.File, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := fs.underlying.Create(fullpath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return newFile(fs, f, filename), nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Open(filename string) (billy.File, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := fs.underlying.Open(fullpath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return newFile(fs, f, filename), nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (billy.File, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := fs.underlying.OpenFile(fullpath, flag, mode)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return newFile(fs, f, filename), nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.Stat(fullpath)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Rename(from, to string) error {
 | 
						|
	var err error
 | 
						|
	from, err = fs.underlyingPath(from)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	to, err = fs.underlyingPath(to)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.Rename(from, to)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Remove(path string) error {
 | 
						|
	fullpath, err := fs.underlyingPath(path)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.Remove(fullpath)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Join(elem ...string) string {
 | 
						|
	return fs.underlying.Join(elem...)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(dir)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := fs.underlying.(billy.TempFile).TempFile(fullpath, prefix)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(path)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.(billy.Dir).ReadDir(fullpath)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.(billy.Dir).MkdirAll(fullpath, perm)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(filename)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.(billy.Symlink).Lstat(fullpath)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Symlink(target, link string) error {
 | 
						|
	target = filepath.FromSlash(target)
 | 
						|
 | 
						|
	// only rewrite target if it's already absolute
 | 
						|
	if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) {
 | 
						|
		target = fs.Join(fs.Root(), target)
 | 
						|
		target = filepath.Clean(filepath.FromSlash(target))
 | 
						|
	}
 | 
						|
 | 
						|
	link, err := fs.underlyingPath(link)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return fs.underlying.(billy.Symlink).Symlink(target, link)
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Readlink(link string) (string, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(link)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	target, err := fs.underlying.(billy.Symlink).Readlink(fullpath)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	if !filepath.IsAbs(target) && !strings.HasPrefix(target, string(filepath.Separator)) {
 | 
						|
		return target, nil
 | 
						|
	}
 | 
						|
 | 
						|
	target, err = filepath.Rel(fs.base, target)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	return string(os.PathSeparator) + target, nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) {
 | 
						|
	fullpath, err := fs.underlyingPath(path)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return New(fs.underlying, fullpath), nil
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Root() string {
 | 
						|
	return fs.base
 | 
						|
}
 | 
						|
 | 
						|
func (fs *ChrootHelper) Underlying() billy.Basic {
 | 
						|
	return fs.underlying
 | 
						|
}
 | 
						|
 | 
						|
// Capabilities implements the Capable interface.
 | 
						|
func (fs *ChrootHelper) Capabilities() billy.Capability {
 | 
						|
	return billy.Capabilities(fs.underlying)
 | 
						|
}
 | 
						|
 | 
						|
type file struct {
 | 
						|
	billy.File
 | 
						|
	name string
 | 
						|
}
 | 
						|
 | 
						|
func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File {
 | 
						|
	filename = fs.Join(fs.Root(), filename)
 | 
						|
	filename, _ = filepath.Rel(fs.Root(), filename)
 | 
						|
 | 
						|
	return &file{
 | 
						|
		File: f,
 | 
						|
		name: filename,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (f *file) Name() string {
 | 
						|
	return f.name
 | 
						|
}
 |