all repos — searchix @ bdb5a54c661407c39668096074a1f4a57898eb77

Search engine for NixOS, nix-darwin, home-manager and NUR users

internal/file/root.go (view raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//nolint:forbidigo // wrappers for os.File functions go here
package file

import (
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"time"

	"github.com/Southclaws/fault"
	"github.com/Southclaws/fault/fmsg"
)

type Root struct {
	*os.Root
}

func CreateAndOpenRoot(name string) (*Root, error) {
	exists, err := exists(name)
	if err != nil {
		return nil, fault.Wrap(err, fmsg.Withf("failed to check data root existence %s", name))
	}
	if !exists {
		err := mkdirp(name)
		if err != nil {
			return nil, fault.Wrap(err, fmsg.Withf("failed to create data root %s", name))
		}
	}

	return OpenRoot(name)
}

func OpenRoot(name string) (*Root, error) {
	r, err := os.OpenRoot(name)
	if err != nil {
		return nil, fault.Wrap(err, fmsg.Withf("failed to open data root directory %s", name))
	}

	return &Root{
		Root: r,
	}, nil
}

func (r *Root) JoinPath(path string) string {
	return filepath.Join(r.Name(), path)
}

func (r *Root) StatIfExists(name string) (fs.FileInfo, error) {
	stat, err := r.Stat(name)

	return stat, needNotExist(err)
}

func (r *Root) Exists(file string) (bool, error) {
	stat, err := r.StatIfExists(file)

	return stat != nil, err
}

func (r *Root) CopyTo(source, target string) error {
	src, err := os.Open(source)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to open source file %s", source))
	}
	defer src.Close()

	dst, err := r.OpenFile(target, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o640)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to create target file %s", target))
	}
	defer dst.Close()

	if _, err := io.Copy(dst, src); err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to copy file from %s to %s", source, target))
	}

	err = dst.Sync()
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to sync target file %s", target))
	}

	return nil
}

func (r *Root) Chtimes(name string, atime time.Time, mtime time.Time) error {
	err := os.Chtimes(r.JoinPath(name), atime, mtime)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to change times of %s", name))
	}

	return nil
}

func (r *Root) MkdirAll(name string) error {
	err := os.MkdirAll(r.JoinPath(name), 0o750)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to create directory %s", name))
	}

	return nil
}

func (r *Root) ReadFile(name string) ([]byte, error) {
	b, err := fs.ReadFile(r.FS(), name)
	if err != nil {
		return nil, fault.Wrap(err, fmsg.Withf("failed to read file %s", name))
	}

	return b, nil
}

func (r *Root) WriteFile(name string, data []byte, perm fs.FileMode) error {
	f, err := r.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to write file %s", name))
	}
	defer f.Close()

	_, err = f.Write(data)
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to write file %s", name))
	}

	return nil
}

func (r *Root) RemoveAll(name string) error {
	err := os.RemoveAll(r.JoinPath(name))
	if err != nil {
		return fault.Wrap(err, fmsg.Withf("failed to remove path %s", r.JoinPath(name)))
	}

	return nil
}