// Config: load files/ directory tree // SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2021-2025 Simon Ruderich 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") // Windows doesn't track permissions. 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() var perm int var data []byte // Existing permissions of the files are not respected (except for +x // on regular files). if typ == 0 /* regular file */ { perm = 0644 // Respect +x for files; except on windows where permissions.yaml // must be used if !windows && info.Mode().Perm()&0100 != 0 { perm = 0755 } data, err = os.ReadFile(path) if err != nil { return err } } else if typ == fs.ModeDir { perm = 0755 } else if typ == fs.ModeSymlink { x, err := os.Readlink(path) if err != nil { return err } data = []byte(x) perm = 0777 // see 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 } // vi: set noet ts=4 sw=4 sts=4: