// "fixperms" sub-command: apply proper permissions in files/ directories // 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 main import ( "fmt" "io/fs" "log" "os" "path/filepath" "ruderich.org/simon/safcm/cmd/safcm-remote/sync" "ruderich.org/simon/safcm/cmd/safcm/config" ) func MainFixperms() error { _, _, _, err := LoadBaseFiles() if err != nil { return fmt.Errorf("not in a safcm directory: %v", err) } xs, err := os.ReadDir(".") if err != nil { return err } for _, x := range xs { if !x.IsDir() { continue } path := filepath.Join(x.Name(), "files") err := filepath.WalkDir(path, fixpermsWalkDirFunc) if err != nil { if os.IsNotExist(err) { continue } return fmt.Errorf("%s: %v", path, err) } } return nil } func fixpermsWalkDirFunc(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 := config.FileModeToFullPerm(info.Mode()) if typ == 0 /* regular file */ { if perm != 0644 && perm != 0755 { if perm&0111 != 0 /* executable */ { perm = 0755 } else { perm = 0644 } log.Printf("chmodding %q to %#o", path, perm) // This is safe because perm does not include // setuid/setgid/sticky which use different values in // FileMode. err := chmodNoFollow(path, fs.FileMode(perm)) if err != nil { return err } } } else if typ == fs.ModeDir { if perm != 0755 { perm = 0755 log.Printf("chmodding %q to %#o", path, perm) err := chmodNoFollow(path, fs.FileMode(perm)) if err != nil { return err } } } // Other file types are caught by regular "sync" return nil } // chmodNoFollow works like os.Chmod but doesn't follow symlinks. func chmodNoFollow(path string, mode fs.FileMode) error { x, err := sync.OpenFileNoFollow(path) if err != nil { return err } defer x.Close() err = x.Chmod(mode) if err != nil { return err } return nil }