mirror of
https://github.com/safing/portbase
synced 2025-09-13 00:30:09 +00:00
Add new dir structure util to ensure correct dir permissions in a structure
This commit is contained in:
parent
46b151ddfe
commit
c4b9c73f41
3 changed files with 214 additions and 1 deletions
139
utils/structure.go
Normal file
139
utils/structure.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// DirStructure represents a directory structure with permissions that should be enforced.
|
||||
type DirStructure struct {
|
||||
sync.Mutex
|
||||
|
||||
Path string
|
||||
Dir string
|
||||
Perm os.FileMode
|
||||
Parent *DirStructure
|
||||
Children map[string]*DirStructure
|
||||
}
|
||||
|
||||
// NewDirStructure returns a new DirStructure.
|
||||
func NewDirStructure(path string, perm os.FileMode) *DirStructure {
|
||||
return &DirStructure{
|
||||
Path: path,
|
||||
Perm: perm,
|
||||
Children: make(map[string]*DirStructure),
|
||||
}
|
||||
}
|
||||
|
||||
// ChildDir adds a new child DirStructure and returns it. Should the child already exist, the existing child is returned and the permissions are updated.
|
||||
func (ds *DirStructure) ChildDir(dirName string, perm os.FileMode) (child *DirStructure) {
|
||||
ds.Lock()
|
||||
defer ds.Unlock()
|
||||
|
||||
// if exists, update
|
||||
child, ok := ds.Children[dirName]
|
||||
if ok {
|
||||
child.Perm = perm
|
||||
return child
|
||||
}
|
||||
|
||||
// create new
|
||||
new := &DirStructure{
|
||||
Path: filepath.Join(ds.Path, dirName),
|
||||
Dir: dirName,
|
||||
Perm: perm,
|
||||
Parent: ds,
|
||||
Children: make(map[string]*DirStructure),
|
||||
}
|
||||
ds.Children[dirName] = new
|
||||
return new
|
||||
}
|
||||
|
||||
// Ensure ensures that the specified directory structure (from the first parent on) exists.
|
||||
func (ds *DirStructure) Ensure() error {
|
||||
return ds.EnsureAbsPath(ds.Path)
|
||||
}
|
||||
|
||||
// EnsureRelPath ensures that the specified directory structure (from the first parent on) and the given relative path (to the DirStructure) exists.
|
||||
func (ds *DirStructure) EnsureRelPath(dirPath string) error {
|
||||
return ds.EnsureAbsPath(filepath.Join(ds.Path, dirPath))
|
||||
}
|
||||
|
||||
// EnsureRelDir ensures that the specified directory structure (from the first parent on) and the given relative path (to the DirStructure) exists.
|
||||
func (ds *DirStructure) EnsureRelDir(dirNames ...string) error {
|
||||
return ds.EnsureAbsPath(filepath.Join(append([]string{ds.Path}, dirNames...)...))
|
||||
}
|
||||
|
||||
// EnsureAbsPath ensures that the specified directory structure (from the first parent on) and the given absolute path exists.
|
||||
// If the given path is outside the DirStructure, an error will be returned.
|
||||
func (ds *DirStructure) EnsureAbsPath(dirPath string) error {
|
||||
// always start at the top
|
||||
if ds.Parent != nil {
|
||||
return ds.Parent.EnsureAbsPath(dirPath)
|
||||
}
|
||||
|
||||
// check if root
|
||||
if dirPath == ds.Path {
|
||||
return ds.ensure(nil)
|
||||
}
|
||||
|
||||
// check scope
|
||||
slashedPath := ds.Path
|
||||
// add slash to end
|
||||
if !strings.HasSuffix(slashedPath, string(filepath.Separator)) {
|
||||
slashedPath += string(filepath.Separator)
|
||||
}
|
||||
// check if given path is in scope
|
||||
if !strings.HasPrefix(dirPath, slashedPath) {
|
||||
return fmt.Errorf(`path "%s" is outside of DirStructure scope`, dirPath)
|
||||
}
|
||||
|
||||
// get relative path
|
||||
relPath, err := filepath.Rel(ds.Path, dirPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get relative path: %s", err)
|
||||
}
|
||||
|
||||
// split to path elements
|
||||
pathDirs := strings.Split(filepath.ToSlash(relPath), "/")
|
||||
|
||||
// start checking
|
||||
return ds.ensure(pathDirs)
|
||||
}
|
||||
|
||||
func (ds *DirStructure) ensure(pathDirs []string) error {
|
||||
ds.Lock()
|
||||
defer ds.Unlock()
|
||||
|
||||
// check current dir
|
||||
err := EnsureDirectory(ds.Path, ds.Perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(pathDirs) == 0 {
|
||||
// we reached the end!
|
||||
return nil
|
||||
}
|
||||
|
||||
child, ok := ds.Children[pathDirs[0]]
|
||||
if !ok {
|
||||
// we have reached the end of the defined dir structure
|
||||
// ensure all remaining dirs
|
||||
dirPath := ds.Path
|
||||
for _, dir := range pathDirs {
|
||||
dirPath = filepath.Join(dirPath, dir)
|
||||
err := EnsureDirectory(dirPath, ds.Perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// we got a child, continue
|
||||
return child.ensure(pathDirs[1:])
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue