]> ruderich.org/simon Gitweb - safcm/safcm.git/blobdiff - cmd/safcm/config/files.go
First working version
[safcm/safcm.git] / cmd / safcm / config / files.go
diff --git a/cmd/safcm/config/files.go b/cmd/safcm/config/files.go
new file mode 100644 (file)
index 0000000..08b2dbf
--- /dev/null
@@ -0,0 +1,108 @@
+// Config: load files/ directory tree
+
+// Copyright (C) 2021  Simon Ruderich
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package config
+
+import (
+       "fmt"
+       "io/fs"
+       "os"
+       "path/filepath"
+
+       "ruderich.org/simon/safcm"
+)
+
+func LoadFiles(group string) (map[string]*safcm.File, error) {
+       basePath := filepath.Join(group, "files")
+
+       const errMsg = `
+The actual permissions and user/group of files and directories are not used
+(except for +x on files). 0644/0755 and current remote user/group is used per
+default. Apply different file permissions via permissions.yaml. To prevent
+confusion files must be manually chmodded 0644/0755 and directories 0755 or
+via "safcm fixperms".
+`
+
+       files := make(map[string]*safcm.File)
+       err := filepath.WalkDir(basePath, func(path string, d fs.DirEntry,
+               err error) error {
+
+               if err != nil {
+                       return err
+               }
+
+               info, err := d.Info()
+               if err != nil {
+                       return err
+               }
+               typ := info.Mode().Type()
+               perm := FileModeToFullPerm(info.Mode())
+
+               var data []byte
+               // See errMsg above. If a user stores a file with stricter
+               // permissions they could assume that these permissions are
+               // respected. This is not the case.
+               if typ == 0 /* regular file */ {
+                       if perm != 0644 && perm != 0755 {
+                               return fmt.Errorf(
+                                       "%q: invalid permissions %#o%s",
+                                       path, perm, errMsg)
+                       }
+                       data, err = os.ReadFile(path)
+                       if err != nil {
+                               return err
+                       }
+               } else if typ == fs.ModeDir {
+                       if perm != 0755 {
+                               return fmt.Errorf(
+                                       "%q: invalid permissions %#o%s",
+                                       path, perm, errMsg)
+                       }
+               } else if typ == fs.ModeSymlink {
+                       x, err := os.Readlink(path)
+                       if err != nil {
+                               return err
+                       }
+                       data = []byte(x)
+               } else {
+                       return fmt.Errorf("%q: file type not supported", path)
+               }
+
+               // Convert to absolute path as used on the target host
+               x, err := filepath.Rel(basePath, path)
+               if err != nil {
+                       return err
+               }
+               x = filepath.Join("/", x)
+
+               files[x] = &safcm.File{
+                       Path: x,
+                       Mode: typ | (fs.FileMode(perm) & fs.ModePerm),
+                       Uid:  -1,
+                       Gid:  -1,
+                       Data: data,
+               }
+               return nil
+       })
+       if err != nil {
+               if os.IsNotExist(err) {
+                       return nil, nil
+               }
+               return nil, fmt.Errorf("%s: %v", group, err)
+       }
+       return files, nil
+}