mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +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
 | |
| }
 |