Skip to content

Commit

Permalink
feat(config): added new feature: set owner and group ID for result files
Browse files Browse the repository at this point in the history
New options: UID, GID and IsRoot. They are the id of user/group in UNIX system. If you'll set UID(without IsRoot option), then the moved files will have a owner, that you specified in configuration. Option 'IsRoot', enables option to set ownership for root user(requiers root permission)
  • Loading branch information
Wittano committed Apr 15, 2024
1 parent 0e318c2 commit dac683d
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 31 deletions.
8 changes: 6 additions & 2 deletions cmd/filebot/filebot.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import (

func runMainCommand(_ *cobra.Command, _ []string) {
ctx := context.Background()
conf := setting.Flags.Config()
conf, err := setting.Flags.Config()
if err != nil {
setting.Logger().Fatal("Failed load configuration", err)
return
}

w := watcher.NewWatcher(ctx)
defer w.Close()
w.AddFilesToObservable(*conf)
w.AddFilesToObservable(conf)

tasks.RunTaskWithInterval(ctx, 1*time.Hour, tasks.MoveToTrashTask)

Expand Down
16 changes: 13 additions & 3 deletions file/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,30 @@ func MoveToDestination(dest string, paths ...string) (err error) {

newPath := filepath.Join(fixedDest, filepath.Base(src))

if _, err = os.Stat(src); !errors.Is(err, os.ErrNotExist) {
err = os.Rename(src, newPath)
if err != nil {
if stat, err := os.Stat(src); err == nil {
if err = os.Rename(src, newPath); err != nil {
setting.Logger().Error(fmt.Sprintf("Failed to move file from %s to %s", src, newPath), err)
continue
}

if err = updateOwnerAndGroupID(stat, newPath); err != nil {
return err
}

setting.Logger().Info(fmt.Sprintf("Moved file from %s to %s", src, dest))
}
}

return nil
}

func updateOwnerAndGroupID(ogInfo os.FileInfo, src string) (err error) {
conf, _ := setting.Flags.Config()
uid, gid := uid(src, ogInfo, conf), gid(src, ogInfo, conf)

return os.Chown(src, int(uid), int(gid))
}

func checkFilePermissions(stat os.FileInfo) error {
writePermIndex := strings.Index(stat.Mode().String(), unixWritePermission)
if writePermIndex == -1 {
Expand Down
55 changes: 55 additions & 0 deletions file/stat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package file

import (
"github.com/wittano/filebot/setting"
"os"
"path/filepath"
"syscall"
)

type uID int
type gID int

const (
rootID uID = 0
rootGID gID = 0
)

func uid(path string, ogStat os.FileInfo, config setting.Config) uID {
baseDir := filepath.Dir(path)

for _, dir := range config.Dirs {
if dir.Dest == baseDir {
uid := uID(os.Getuid())

if dir.UID > 0 {
uid = uID(dir.UID)
} else if dir.IsRoot {
uid = rootID
}

return uid
}
}

return uID(ogStat.Sys().(*syscall.Stat_t).Uid)
}

func gid(path string, ogStat os.FileInfo, config setting.Config) gID {
baseDir := filepath.Dir(path)

for _, dir := range config.Dirs {
if dir.Dest == baseDir {
uid := gID(os.Getgid())
if dir.UID > 0 {
uid = gID(dir.GID)
} else if dir.IsRoot {
uid = rootGID
}

return uid
}
}

return gID(ogStat.Sys().(*syscall.Stat_t).Gid)
}
23 changes: 9 additions & 14 deletions setting/config_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Config struct {
Dirs []Directory `validate:"required"`
}

var config *Config
var config Config

type Directory struct {
Src []string `validate:"required"`
Expand All @@ -30,16 +30,12 @@ type Directory struct {
MoveToTrash bool `validate:"required_without=Dest"`
After uint
Exceptions []string
UID uint32
GID uint32
IsRoot bool
}

func (d Directory) RealPaths() (paths []string, err error) {
v := validator.New(validator.WithRequiredStructEnabled())

err = v.Struct(d)
if err != nil {
return
}

for _, exp := range d.Src {
if d.Recursive {
paths, err = path.PathsFromPatternRecursive(exp)
Expand Down Expand Up @@ -139,29 +135,28 @@ func isUserRoot() bool {
return os.Getuid() == 0
}

func load(path string) (*Config, error) {
func load(path string) (Config, error) {
bytes, err := os.ReadFile(path)
if err != nil {
return nil, err
return Config{}, err
}

var unmarshal map[string]Directory
if err := toml.Unmarshal(bytes, &unmarshal); err != nil {
return nil, err
return Config{}, err
}

if len(unmarshal) == 0 {
return nil, errors.New("config file is empty")
return Config{}, errors.New("config file is empty")
}

config = new(Config)
config.Dirs = maps.Values(unmarshal)

v := validator.New(validator.WithRequiredStructEnabled())

for _, d := range config.Dirs {
if err = v.Struct(d); err != nil {
return nil, err
return Config{}, err
}
}

Expand Down
13 changes: 4 additions & 9 deletions setting/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@ var Flags = Flag{
"",
}

func (f Flag) Config() *Config {
if config != nil {
return config
func (f Flag) Config() (Config, error) {
if config.Dirs != nil {
return config, nil
}

c, err := load(f.ConfigPath)
if err != nil {
Logger().Fatal("Failed to load config file", err)
}

return c
return load(f.ConfigPath)
}

func (f Flag) LogLevel() LogLevel {
Expand Down
7 changes: 6 additions & 1 deletion tasks/trash.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ func MoveToTrashTask(ctx context.Context) (err error) {
default:
}

for _, dir := range setting.Flags.Config().Dirs {
config, err := setting.Flags.Config()
if err != nil {
return err
}

for _, dir := range config.Dirs {
if dir.MoveToTrash {
if err = moveFileToTrash(dir); err != nil {
return
Expand Down
4 changes: 2 additions & 2 deletions watcher/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ func (w *MyWatcher) updateObservableFileList(ctx context.Context) error {
case <-ctx.Done():
return
default:
conf := setting.Flags.Config()
conf, _ := setting.Flags.Config()

w.AddFilesToObservable(*conf)
w.AddFilesToObservable(conf)
}
}()

Expand Down

0 comments on commit dac683d

Please sign in to comment.