github.com/criyle/go-sandbox@v0.10.3/runner/ptrace/filehandler/fileset.go (about)

     1  package filehandler
     2  
     3  import (
     4  	"path/filepath"
     5  	"strings"
     6  )
     7  
     8  // FileSet stores the file permissions in the hierarchical set
     9  type FileSet struct {
    10  	Set        map[string]bool
    11  	SystemRoot bool
    12  }
    13  
    14  // FilePerm stores the permission apply to the file
    15  type FilePerm int
    16  
    17  // FilePermWrite / Read / Stat are permissions
    18  const (
    19  	FilePermWrite = iota + 1
    20  	FilePermRead
    21  	FilePermStat
    22  )
    23  
    24  // NewFileSet creates the new file set
    25  func NewFileSet() FileSet {
    26  	return FileSet{make(map[string]bool), false}
    27  }
    28  
    29  // IsInSetSmart same from uoj-judger
    30  func (s *FileSet) IsInSetSmart(name string) bool {
    31  	if s.Set[name] {
    32  		return true
    33  	}
    34  	if name == "/" && s.SystemRoot {
    35  		return true
    36  	}
    37  	// check ...
    38  	level := 0
    39  	for level = 0; name != ""; level++ {
    40  		if level == 1 && s.Set[name+"/*"] {
    41  			return true
    42  		}
    43  		if s.Set[name+"/"] {
    44  			return true
    45  		}
    46  		name = dirname(name)
    47  	}
    48  	if level == 1 && s.Set["/*"] {
    49  		return true
    50  	}
    51  	if s.Set["/"] {
    52  		return true
    53  	}
    54  	return false
    55  }
    56  
    57  // Add adds a single file path into the FileSet
    58  func (s *FileSet) Add(name string) {
    59  	if name == "/" {
    60  		s.SystemRoot = true
    61  	} else {
    62  		s.Set[name] = true
    63  	}
    64  }
    65  
    66  // AddRange adds multiple files into the FileSet
    67  // If path is relative path, add according to the workPath
    68  func (s *FileSet) AddRange(names []string, workPath string) {
    69  	for _, n := range names {
    70  		if filepath.IsAbs(n) {
    71  			if n == "/" {
    72  				s.SystemRoot = true
    73  			} else {
    74  				s.Set[n] = true
    75  			}
    76  		} else {
    77  			s.Set[filepath.Join(workPath, n)+"/"] = true
    78  		}
    79  	}
    80  }
    81  
    82  // FileSets aggregates multiple permissions including write / read / stat / soft ban
    83  type FileSets struct {
    84  	Writable, Readable, Statable, SoftBan FileSet
    85  }
    86  
    87  // NewFileSets creates new FileSets struct
    88  func NewFileSets() *FileSets {
    89  	return &FileSets{NewFileSet(), NewFileSet(), NewFileSet(), NewFileSet()}
    90  }
    91  
    92  // IsWritableFile determines whether the file path inside the write set
    93  func (s *FileSets) IsWritableFile(name string) bool {
    94  	return s.Writable.IsInSetSmart(name) || s.Writable.IsInSetSmart(realPath(name))
    95  }
    96  
    97  // IsReadableFile determines whether the file path inside the read / write set
    98  func (s *FileSets) IsReadableFile(name string) bool {
    99  	return s.IsWritableFile(name) || s.Readable.IsInSetSmart(name) || s.Readable.IsInSetSmart(realPath(name))
   100  }
   101  
   102  // IsStatableFile determines whether the file path inside the stat / read / write set
   103  func (s *FileSets) IsStatableFile(name string) bool {
   104  	return s.IsReadableFile(name) || s.Statable.IsInSetSmart(name) || s.Statable.IsInSetSmart(realPath(name))
   105  }
   106  
   107  // IsSoftBanFile determines whether the file path inside the softban set
   108  func (s *FileSets) IsSoftBanFile(name string) bool {
   109  	return s.SoftBan.IsInSetSmart(name) || s.SoftBan.IsInSetSmart(realPath(name))
   110  }
   111  
   112  // AddFilePermission adds the file into fileSets according to the given permission
   113  func (s *FileSets) AddFilePermission(name string, mode FilePerm) {
   114  	if mode == FilePermWrite {
   115  		s.Writable.Add(name)
   116  	} else if mode == FilePermRead {
   117  		s.Readable.Add(name)
   118  	} else if mode == FilePermStat {
   119  		s.Statable.Add(name)
   120  	}
   121  	for name = dirname(name); name != ""; name = dirname(name) {
   122  		s.Statable.Add(name)
   123  	}
   124  }
   125  
   126  // GetExtraSet evaluates the concatenated file set according to real path or raw path
   127  func GetExtraSet(extra, raw []string) []string {
   128  	rt := make([]string, 0, len(extra)+len(raw))
   129  	rt = append(rt, raw...)
   130  	for _, v := range extra {
   131  		rt = append(rt, realPath(v))
   132  	}
   133  	return rt
   134  }
   135  
   136  // dirname return path without last "/"
   137  func dirname(path string) string {
   138  	if p := strings.LastIndex(path, "/"); p >= 0 {
   139  		return path[:p]
   140  	}
   141  	return ""
   142  }
   143  
   144  func realPath(p string) string {
   145  	f, err := filepath.EvalSymlinks(p)
   146  	if err != nil {
   147  		return ""
   148  	}
   149  	return f
   150  }