feat: restart to apply update, privileged helper, rollback
This commit is contained in:
1 parent
70460e4170
commit
54e8fd5fed
63 files changed
+8635
-164
No files matched your search
@@ -0,0 +1,163 @@
|
||||
//go:build linux
|
||||
|
||||
package update
|
||||
|
||||
import (
|
||||
domain "RenewCMS/internal/domain/update"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
privateTempDirPrefix = "renewcms-update-"
|
||||
readNoFollowFlags = os.O_RDONLY | syscall.O_NOFOLLOW | syscall.O_NONBLOCK
|
||||
createNoFollowFlags = os.O_WRONLY | os.O_CREATE | os.O_EXCL | syscall.O_NOFOLLOW
|
||||
directoryFlags = os.O_RDONLY | syscall.O_NOFOLLOW | syscall.O_DIRECTORY
|
||||
)
|
||||
|
||||
var errNotRegularFile = errors.New("not a regular file")
|
||||
|
||||
type NoFollowFilesystem struct{}
|
||||
|
||||
var _ domain.HelperFilesystem = &NoFollowFilesystem{}
|
||||
|
||||
func NewNoFollowFilesystem() *NoFollowFilesystem {
|
||||
return &NoFollowFilesystem{}
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) Lstat(path string) (domain.FileInfo, error) {
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return domain.FileInfo{}, err
|
||||
}
|
||||
mode := info.Mode()
|
||||
return domain.FileInfo{
|
||||
IsSymlink: mode&fs.ModeSymlink != 0,
|
||||
IsDir: mode.IsDir(),
|
||||
IsRegular: mode.IsRegular(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) ReadFile(path string) ([]byte, error) {
|
||||
file, err := openRegularNoFollow(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return io.ReadAll(file)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) CreateExclusive(path string, content []byte, mode uint32) error {
|
||||
file, err := os.OpenFile(path, createNoFollowFlags, fs.FileMode(mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := file.Write(content); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
return finishWrite(file, mode)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) Copy(source string, destination string, mode uint32) error {
|
||||
input, err := openRegularNoFollow(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer input.Close()
|
||||
output, err := os.OpenFile(destination, createNoFollowFlags, fs.FileMode(mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(output, input); err != nil {
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
return finishWrite(output, mode)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) Rename(oldPath string, newPath string) error {
|
||||
return os.Rename(oldPath, newPath)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) Remove(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) RemoveAll(path string) error {
|
||||
info, err := os.Lstat(path)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return os.Remove(path)
|
||||
}
|
||||
names, err := readDirectoryNames(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range names {
|
||||
if err := f.RemoveAll(filepath.Join(path, name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) Chmod(path string, mode uint32) error {
|
||||
file, err := os.OpenFile(path, readNoFollowFlags, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
return file.Chmod(fs.FileMode(mode))
|
||||
}
|
||||
|
||||
func (f *NoFollowFilesystem) MakePrivateTempDir() (string, error) {
|
||||
return os.MkdirTemp("", privateTempDirPrefix)
|
||||
}
|
||||
|
||||
func openRegularNoFollow(path string) (*os.File, error) {
|
||||
file, err := os.OpenFile(path, readNoFollowFlags, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
file.Close()
|
||||
return nil, errNotRegularFile
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func finishWrite(file *os.File, mode uint32) error {
|
||||
if err := file.Chmod(fs.FileMode(mode)); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
if err := file.Sync(); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func readDirectoryNames(path string) ([]string, error) {
|
||||
directory, err := os.OpenFile(path, directoryFlags, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer directory.Close()
|
||||
return directory.Readdirnames(-1)
|
||||
}
|
||||
Reference in new issue
Block a user