]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/config/files.go
7ffa8b201cfeb5548cb0d2356f19677931218542
[safcm/safcm.git] / cmd / safcm / config / files.go
1 // Config: load files/ directory tree
2
3 // Copyright (C) 2021  Simon Ruderich
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 package config
19
20 import (
21         "fmt"
22         "io/fs"
23         "os"
24         slashpath "path"
25         "path/filepath"
26         "runtime"
27
28         "ruderich.org/simon/safcm"
29 )
30
31 func LoadFiles(group string) (map[string]*safcm.File, error) {
32         basePath := filepath.Join(group, "files")
33
34         const errMsg = `
35
36 The actual permissions and user/group of files and directories are not used
37 (except for +x on files). 0644/0755 and current remote user/group is used per
38 default. Apply different file permissions via permissions.yaml. To prevent
39 confusion files must be manually chmodded 0644/0755 and directories 0755 or
40 via "safcm fixperms".
41 `
42
43         files := make(map[string]*safcm.File)
44         err := filepath.WalkDir(basePath, func(path string, d fs.DirEntry,
45                 err error) error {
46
47                 if err != nil {
48                         return err
49                 }
50
51                 info, err := d.Info()
52                 if err != nil {
53                         return err
54                 }
55                 typ := info.Mode().Type()
56                 perm := FileModeToFullPerm(info.Mode())
57
58                 var data []byte
59                 // See errMsg above. If a user stores a file with stricter
60                 // permissions they could assume that these permissions are
61                 // respected. This is not the case.
62                 if typ == 0 /* regular file */ {
63                         if perm != 0644 && perm != 0755 {
64                                 return fmt.Errorf(
65                                         "%q: invalid permissions %#o%s",
66                                         path, perm, errMsg)
67                         }
68                         data, err = os.ReadFile(path)
69                         if err != nil {
70                                 return err
71                         }
72                 } else if typ == fs.ModeDir {
73                         if perm != 0755 {
74                                 return fmt.Errorf(
75                                         "%q: invalid permissions %#o%s",
76                                         path, perm, errMsg)
77                         }
78                 } else if typ == fs.ModeSymlink {
79                         x, err := os.Readlink(path)
80                         if err != nil {
81                                 return err
82                         }
83                         data = []byte(x)
84                         perm |= 0777 // see cmd/safcm-remote/sync/files.go
85                 } else {
86                         return fmt.Errorf("%q: file type not supported", path)
87                 }
88
89                 // Convert to absolute and slash-separated path as used on the
90                 // target host
91                 x, err := filepath.Rel(basePath, path)
92                 if err != nil {
93                         return err
94                 }
95                 x = slashpath.Join("/", filepath.ToSlash(x))
96
97                 files[x] = &safcm.File{
98                         Path: x,
99                         Mode: typ | (fs.FileMode(perm) & fs.ModePerm),
100                         Uid:  -1,
101                         Gid:  -1,
102                         Data: data,
103                 }
104                 return nil
105         })
106         if err != nil {
107                 if os.IsNotExist(err) {
108                         return nil, nil
109                 }
110                 return nil, fmt.Errorf("%s: %v", group, err)
111         }
112         return files, nil
113 }