mirror of
https://github.com/safing/portbase
synced 2025-09-01 10:09:50 +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
|
@ -6,6 +6,8 @@ import (
|
|||
"runtime"
|
||||
)
|
||||
|
||||
const isWindows = runtime.GOOS == "windows"
|
||||
|
||||
// EnsureDirectory ensures that the given directoy exists and that is has the given permissions set.
|
||||
// If path is a file, it is deleted and a directory created.
|
||||
// If a directory is created, also all missing directories up to the required one are created with the given permissions.
|
||||
|
@ -16,7 +18,7 @@ func EnsureDirectory(path string, perm os.FileMode) error {
|
|||
// file exists
|
||||
if f.IsDir() {
|
||||
// directory exists, check permissions
|
||||
if runtime.GOOS == "windows" {
|
||||
if isWindows {
|
||||
// TODO: set correct permission on windows
|
||||
// acl.Chmod(path, perm)
|
||||
} else if f.Mode().Perm() != perm {
|
||||
|
|
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:])
|
||||
}
|
72
utils/structure_test.go
Normal file
72
utils/structure_test.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
// +build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ExampleDirStructure() {
|
||||
// output:
|
||||
// / [755]
|
||||
// /repo [777]
|
||||
// /repo/b [755]
|
||||
// /repo/b/c [750]
|
||||
// /repo/b/d [755]
|
||||
// /repo/b/d/e [755]
|
||||
// /repo/b/d/f [755]
|
||||
// /secret [700]
|
||||
|
||||
basePath, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ds := NewDirStructure(basePath, 0755)
|
||||
secret := ds.ChildDir("secret", 0700)
|
||||
repo := ds.ChildDir("repo", 0777)
|
||||
_ = repo.ChildDir("a", 0700)
|
||||
b := repo.ChildDir("b", 0755)
|
||||
c := b.ChildDir("c", 0750)
|
||||
|
||||
err = ds.Ensure()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = c.Ensure()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = secret.Ensure()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = b.EnsureRelDir("d", "e")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = b.EnsureRelPath("d/f")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
|
||||
if err == nil {
|
||||
dir := strings.TrimPrefix(path, basePath)
|
||||
if dir == "" {
|
||||
dir = "/"
|
||||
}
|
||||
fmt.Printf("%s [%o]\n", dir, info.Mode().Perm())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
Loading…
Add table
Reference in a new issue