1 package utils
2
3 import (
4 "flag"
5 "fmt"
6 "golang.org/x/sys/unix"
7 "io/fs"
8 "io/ioutil"
9 "os"
10 "os/user"
11 "path/filepath"
12 "strings"
13 "sync"
14 )
15
16 var (
17 safely_write_lock sync.Mutex
18 extra_dir = flag.String("ge_findfile_additional_dir", "", "if set, findfile will search this directory as well")
19 debug_find_file = flag.Bool("ge_debug_find_file", false, "debug fuzzy filename matches")
20 find_file_cache = make(map[string]string)
21 ffclock sync.Mutex
22 workingdir string
23 )
24
25 func init() {
26 var err error
27 workingdir, err = os.Getwd()
28 if err != nil {
29 fmt.Printf("cannot get current working directory: %s\n", err)
30 }
31 }
32
33
34 func MakeSafeFilename(name string) string {
35
36 foo := ".0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-"
37 res := ""
38 isdup := false
39 for _, x := range name {
40 isgood := false
41 for _, allowed := range foo {
42 if allowed == x {
43 isgood = true
44 break
45 }
46 }
47 if isgood {
48 isdup = false
49 } else {
50 if isdup {
51 continue
52 }
53 isdup = true
54 x = '_'
55 }
56 res = res + fmt.Sprintf("%c", x)
57 }
58 return res
59 }
60
61
62 func SafelyWriteFile(filename string, content []byte) error {
63 unix.Umask(000)
64 safely_write_lock.Lock()
65 defer safely_write_lock.Unlock()
66 tmpfile := ""
67 i := 0
68 for {
69 tmpfile = filename + fmt.Sprintf("_tmp_%d", i)
70 if !FileExists(tmpfile) {
71 break
72 }
73 i++
74 }
75 err := ioutil.WriteFile(tmpfile, content, 0666)
76 if err != nil {
77 return err
78 }
79 err = os.Rename(tmpfile, filename)
80 if err != nil {
81 os.Remove(tmpfile)
82 return err
83 }
84 return nil
85 }
86
87
88 func WriteFile(filename string, content []byte) error {
89 unix.Umask(000)
90 err := ioutil.WriteFile(filename, content, 0666)
91 return err
92 }
93
94
95 func WriteFileCreateDir(filename string, content []byte) error {
96 unix.Umask(000)
97 if strings.Contains(filename, "/") {
98 dir := filepath.Dir(filename)
99 os.MkdirAll(dir, 0777)
100 }
101 err := ioutil.WriteFile(filename, content, 0666)
102 return err
103 }
104
105
106 func OpenWriteFile(filename string) (*os.File, error) {
107 unix.Umask(000)
108 file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
109 return file, err
110 }
111
112
113
114 func FileExists(filename string) bool {
115 _, err := os.Stat(filename)
116 if err != nil {
117 return false
118 }
119 return true
120 }
121 func debugFind(name, nname string) {
122 if !*debug_find_file {
123 return
124 }
125 fmt.Printf("File: %s resolved to %s\n", name, nname)
126 return
127 }
128
129
130 func FindFile(name string) (string, error) {
131 ffclock.Lock()
132 nname, foo := find_file_cache[name]
133 ffclock.Unlock()
134 if foo {
135 return nname, nil
136 }
137 nname = name
138 for i := 0; i < 20; i++ {
139 if FileExists(nname) {
140 debugFind(name, nname)
141 ffclock.Lock()
142 find_file_cache[name] = nname
143 ffclock.Unlock()
144 nname, err := filepath.Abs(nname)
145 if err != nil {
146 return "", err
147 }
148 return nname, nil
149 }
150 nname = "../" + nname
151 }
152 if *extra_dir != "" {
153 nname := fmt.Sprintf("%s/%s", *extra_dir, name)
154 nname, err := filepath.Abs(nname)
155 if err != nil {
156 return "", err
157 }
158 if FileExists(nname) {
159 return nname, nil
160 }
161 }
162 debugFind(name, "[not found]")
163 return "", fmt.Errorf("File not found: %s", name)
164 }
165
166
167
168
169
170 func FindFileInWorkingDir(name string) (string, error) {
171 name, err := FindFile(name)
172 if err != nil {
173 return "", err
174 }
175 name, err = filepath.Abs(name)
176 if err != nil {
177 return "", err
178 }
179 if !strings.HasPrefix(name, WorkingDir()) {
180 return "", fmt.Errorf("file %s not in working dir %s", name, WorkingDir())
181 }
182 return name, nil
183 }
184
185
186 func ReadFile(filename string) ([]byte, error) {
187 fn, err := FindFile(filename)
188 if err != nil {
189 return nil, err
190 }
191 b, err := ioutil.ReadFile(fn)
192 return b, err
193 }
194
195
196 func WorkingDir() string {
197 if workingdir == "" {
198 var err error
199 workingdir, err = os.Getwd()
200
201
202 Bail("failed to get workingdir", err)
203 }
204 return workingdir
205 }
206
207
208 func HomeDir() (string, error) {
209 he := os.Getenv("HOME")
210 if he != "" && FileExists(he) {
211 return he, nil
212 }
213 u, err := user.Current()
214 if err != nil {
215 return "", fmt.Errorf("no current user: %s", err)
216 }
217 if u == nil {
218 return "", fmt.Errorf("No current user")
219 }
220 return u.HomeDir, nil
221 }
222
223
224 func RemoveAll(dir string) error {
225 var err error
226
227 err = os.RemoveAll(dir)
228 if err == nil {
229 return nil
230 }
231
232
233 err = ChmodR(dir, 0777, 0777)
234 if err != nil {
235 return err
236 }
237 err = os.RemoveAll(dir)
238 if err != nil {
239 return err
240 }
241
242 return err
243 }
244
245
246 func ChmodR(dir string, dirmask, filemask fs.FileMode) error {
247 err := os.Chmod(dir, dirmask)
248 if err != nil {
249 return err
250 }
251 files, err := ioutil.ReadDir(dir)
252 if err != nil {
253 return err
254 }
255 for _, f := range files {
256 if f.IsDir() {
257 err = ChmodR(dir+"/"+f.Name(), dirmask, filemask)
258 if err != nil {
259 return err
260 }
261 continue
262 }
263 err = os.Chmod(dir+"/"+f.Name(), filemask)
264 if err != nil {
265 return err
266 }
267 }
268 return nil
269 }
270
271
272 func IsDir(name string) (bool, error) {
273 fname, err := FindFile(name)
274 if err != nil {
275 return false, err
276 }
277
278 fileInfo, err := os.Stat(fname)
279 if err != nil {
280 return false, err
281 }
282
283
284 if fileInfo.IsDir() {
285 return true, nil
286 }
287 return false, nil
288 }
289
View as plain text