package chroot

import (
	
	
	

	
	
)
ChrootHelper is a helper to implement billy.Chroot.
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 ( billy.Basic,  string) billy.Filesystem {
	return &ChrootHelper{
		underlying: polyfill.New(),
		base:       ,
	}
}

func ( *ChrootHelper) ( string) (string, error) {
	if isCrossBoundaries() {
		return "", billy.ErrCrossedBoundary
	}

	return .Join(.Root(), ), nil
}

func ( string) bool {
	 = filepath.ToSlash()
	 = filepath.Clean()

	return strings.HasPrefix(, ".."+string(filepath.Separator))
}

func ( *ChrootHelper) ( string) (billy.File, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	,  := .underlying.Create()
	if  != nil {
		return nil, 
	}

	return newFile(, , ), nil
}

func ( *ChrootHelper) ( string) (billy.File, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	,  := .underlying.Open()
	if  != nil {
		return nil, 
	}

	return newFile(, , ), nil
}

func ( *ChrootHelper) ( string,  int,  os.FileMode) (billy.File, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	,  := .underlying.OpenFile(, , )
	if  != nil {
		return nil, 
	}

	return newFile(, , ), nil
}

func ( *ChrootHelper) ( string) (os.FileInfo, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	return .underlying.Stat()
}

func ( *ChrootHelper) (,  string) error {
	var  error
	,  = .underlyingPath()
	if  != nil {
		return 
	}

	,  = .underlyingPath()
	if  != nil {
		return 
	}

	return .underlying.Rename(, )
}

func ( *ChrootHelper) ( string) error {
	,  := .underlyingPath()
	if  != nil {
		return 
	}

	return .underlying.Remove()
}

func ( *ChrootHelper) ( ...string) string {
	return .underlying.Join(...)
}

func ( *ChrootHelper) (,  string) (billy.File, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	,  := .underlying.(billy.TempFile).TempFile(, )
	if  != nil {
		return nil, 
	}

	return newFile(, , .Join(, filepath.Base(.Name()))), nil
}

func ( *ChrootHelper) ( string) ([]os.FileInfo, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	return .underlying.(billy.Dir).ReadDir()
}

func ( *ChrootHelper) ( string,  os.FileMode) error {
	,  := .underlyingPath()
	if  != nil {
		return 
	}

	return .underlying.(billy.Dir).MkdirAll(, )
}

func ( *ChrootHelper) ( string) (os.FileInfo, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	return .underlying.(billy.Symlink).Lstat()
}

func ( *ChrootHelper) (,  string) error {
	 = filepath.FromSlash()
only rewrite target if it's already absolute
	if filepath.IsAbs() || strings.HasPrefix(, string(filepath.Separator)) {
		 = .Join(.Root(), )
		 = filepath.Clean(filepath.FromSlash())
	}

	,  := .underlyingPath()
	if  != nil {
		return 
	}

	return .underlying.(billy.Symlink).Symlink(, )
}

func ( *ChrootHelper) ( string) (string, error) {
	,  := .underlyingPath()
	if  != nil {
		return "", 
	}

	,  := .underlying.(billy.Symlink).Readlink()
	if  != nil {
		return "", 
	}

	if !filepath.IsAbs() && !strings.HasPrefix(, string(filepath.Separator)) {
		return , nil
	}

	,  = filepath.Rel(.base, )
	if  != nil {
		return "", 
	}

	return string(os.PathSeparator) + , nil
}

func ( *ChrootHelper) ( string) (billy.Filesystem, error) {
	,  := .underlyingPath()
	if  != nil {
		return nil, 
	}

	return New(.underlying, ), nil
}

func ( *ChrootHelper) () string {
	return .base
}

func ( *ChrootHelper) () billy.Basic {
	return .underlying
}
Capabilities implements the Capable interface.
func ( *ChrootHelper) () billy.Capability {
	return billy.Capabilities(.underlying)
}

type file struct {
	billy.File
	name string
}

func ( billy.Filesystem,  billy.File,  string) billy.File {
	 = .Join(.Root(), )
	, _ = filepath.Rel(.Root(), )

	return &file{
		File: ,
		name: ,
	}
}

func ( *file) () string {
	return .name