// 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 . package config import ( "fmt" "io/fs" "os" slashpath "path" "path/filepath" "runtime" "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". ` // No permission checks on windows which doesn't track them. windows := runtime.GOOS == "windows" 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 windows { perm = 0644 // 0755 must be set via permissions.yaml if // windows is used } 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 windows { perm = 0755 } 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) perm |= 0777 // see cmd/safcm-remote/sync/files.go } else { return fmt.Errorf("%q: file type not supported", path) } // Convert to absolute and slash-separated path as used on the // target host x, err := filepath.Rel(basePath, path) if err != nil { return err } x = slashpath.Join("/", filepath.ToSlash(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 }