mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-02 01:52:16 +00:00
Currently IsDirEmpty returns true, err if it encounters any error after trying to os.Open the directory. I noticed this while studying the code and recalled a bug from an earlier project in which doing the exact same thing on code without permissions would trip out and falsely report that the directory was empty. Given demo.go in https://play.golang.org/p/vhTPU2RiCJ * Demo: ```shell $ mkdir -p sample-demo/1 && touch sample-demo/2 $ echo "1st round" && go run demo.go sample-demo $ sudo chown root sample-demo && sudo chmod 0700 sample-demo $ echo "2nd round" && go run demo.go sample-demo ``` That then prints out ```shell 1st round original:: empty: false err: <nil> updated:: empty: false err: <nil> 2nd round original:: empty: true err: open data/: permission denied updated:: empty: false err: open data/: permission denied ``` where in "2nd round", the original code falsely reports that the directory is empty but that's a permission error. I could write a code test for it, but that test requires me to change users and switch to root as a Go user so no point in complicating our tests, but otherwise it is a 1-to-1 translation between shell and Go.
165 lines
3.7 KiB
Go
165 lines
3.7 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
GoPath = os.Getenv("GOPATH")
|
|
)
|
|
|
|
func TrapSignal(cb func()) {
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt)
|
|
signal.Notify(c, os.Kill)
|
|
go func() {
|
|
for sig := range c {
|
|
fmt.Printf("captured %v, exiting...\n", sig)
|
|
if cb != nil {
|
|
cb()
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
select {}
|
|
}
|
|
|
|
func Exit(s string) {
|
|
fmt.Printf(s + "\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
func EnsureDir(dir string, mode os.FileMode) error {
|
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
err := os.MkdirAll(dir, mode)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not create directory %v. %v", dir, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func IsDirEmpty(name string) (bool, error) {
|
|
f, err := os.Open(name)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return true, err
|
|
}
|
|
// Otherwise perhaps a permission
|
|
// error or some other error.
|
|
return false, err
|
|
}
|
|
defer f.Close()
|
|
|
|
_, err = f.Readdirnames(1) // Or f.Readdir(1)
|
|
if err == io.EOF {
|
|
return true, nil
|
|
}
|
|
return false, err // Either not empty or error, suits both cases
|
|
}
|
|
|
|
func FileExists(filePath string) bool {
|
|
_, err := os.Stat(filePath)
|
|
return !os.IsNotExist(err)
|
|
}
|
|
|
|
func ReadFile(filePath string) ([]byte, error) {
|
|
return ioutil.ReadFile(filePath)
|
|
}
|
|
|
|
func MustReadFile(filePath string) []byte {
|
|
fileBytes, err := ioutil.ReadFile(filePath)
|
|
if err != nil {
|
|
Exit(Fmt("MustReadFile failed: %v", err))
|
|
return nil
|
|
}
|
|
return fileBytes
|
|
}
|
|
|
|
func WriteFile(filePath string, contents []byte, mode os.FileMode) error {
|
|
err := ioutil.WriteFile(filePath, contents, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// fmt.Printf("File written to %v.\n", filePath)
|
|
return nil
|
|
}
|
|
|
|
func MustWriteFile(filePath string, contents []byte, mode os.FileMode) {
|
|
err := WriteFile(filePath, contents, mode)
|
|
if err != nil {
|
|
Exit(Fmt("MustWriteFile failed: %v", err))
|
|
}
|
|
}
|
|
|
|
// Writes to newBytes to filePath.
|
|
// Guaranteed not to lose *both* oldBytes and newBytes,
|
|
// (assuming that the OS is perfect)
|
|
func WriteFileAtomic(filePath string, newBytes []byte, mode os.FileMode) error {
|
|
// If a file already exists there, copy to filePath+".bak" (overwrite anything)
|
|
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
|
|
fileBytes, err := ioutil.ReadFile(filePath)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not read file %v. %v", filePath, err)
|
|
}
|
|
err = ioutil.WriteFile(filePath+".bak", fileBytes, mode)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not write file %v. %v", filePath+".bak", err)
|
|
}
|
|
}
|
|
// Write newBytes to filePath.new
|
|
err := ioutil.WriteFile(filePath+".new", newBytes, mode)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not write file %v. %v", filePath+".new", err)
|
|
}
|
|
// Move filePath.new to filePath
|
|
err = os.Rename(filePath+".new", filePath)
|
|
return err
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
func Tempfile(prefix string) (*os.File, string) {
|
|
file, err := ioutil.TempFile("", prefix)
|
|
if err != nil {
|
|
PanicCrisis(err)
|
|
}
|
|
return file, file.Name()
|
|
}
|
|
|
|
func Tempdir(prefix string) (*os.File, string) {
|
|
tempDir := os.TempDir() + "/" + prefix + RandStr(12)
|
|
err := EnsureDir(tempDir, 0700)
|
|
if err != nil {
|
|
panic(Fmt("Error creating temp dir: %v", err))
|
|
}
|
|
dir, err := os.Open(tempDir)
|
|
if err != nil {
|
|
panic(Fmt("Error opening temp dir: %v", err))
|
|
}
|
|
return dir, tempDir
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
func Prompt(prompt string, defaultValue string) (string, error) {
|
|
fmt.Print(prompt)
|
|
reader := bufio.NewReader(os.Stdin)
|
|
line, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return defaultValue, err
|
|
} else {
|
|
line = strings.TrimSpace(line)
|
|
if line == "" {
|
|
return defaultValue, nil
|
|
}
|
|
return line, nil
|
|
}
|
|
}
|