Skip to content
Snippets Groups Projects
files.go 2.45 KiB
// Cross-platform file utils.
package files

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

// We don't concern ourselves with executable files here.
const (
	FILE_RW = os.FileMode(0666)
	FILE_W  = os.FileMode(0222)
	FILE_R  = os.FileMode(0444)
)

func IsWritable(fm os.FileMode) bool {
	return fm&2 == 2
}

// Write a file that has both read and write flags set.
func WriteFileRW(fileName string, data []byte) error {
	return WriteFile(fileName, data, FILE_RW)
}

// Write file with the read-only flag set.
func WriteFileReadOnly(fileName string, data []byte) error {
	return WriteFile(fileName, data, FILE_R)
}

// Write file with the write-only flag set.
func WriteFileWriteOnly(fileName string, data []byte) error {
	return WriteFile(fileName, data, FILE_W)
}

// WriteFile.
func WriteFile(fileName string, data []byte, perm os.FileMode) error {
	f, err := os.Create(fileName)
	if err != nil {
		fmt.Println("ERROR OPENING: " + err.Error())
		return err
	}
	defer f.Close()
	n, err2 := f.Write(data)
	if err2 != nil {
		fmt.Println("ERROR WRITING: " + err.Error())
		return err
	}
	if err2 == nil && n < len(data) {
		err2 = io.ErrShortWrite
		return err
	}

	return nil
}

// Does the file with the given name exist?
func FileExists(fileName string) bool {
	_, err := os.Stat(fileName)
	return !os.IsNotExist(err)
}

func IsRegular(fileName string) bool {
	fs, err := os.Stat(fileName)
	if err != nil {
		return false
	}
	return fs.Mode().IsRegular()
}

func WriteAndBackup(fileName string, data []byte) error {
	fs, err := os.Stat(fileName)
	fmt.Println("Write and backup")
	if err != nil {
		if os.IsNotExist(err) {
			WriteFileRW(fileName, data)
			return nil
		}
		return err
	}
	if !fs.Mode().IsRegular() {
		return fmt.Errorf("Not a regular file: " + fileName)
	}
	backupName := fileName + ".bak"
	fs, err = os.Stat(backupName)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		// We only work with regular files.
		if !fs.Mode().IsRegular() {
			return fmt.Errorf(backupName + " is not a regular file.")
		}
		errR := os.Remove(backupName)
		if errR != nil {
			return errR
		}
	}
	// Backup file should now be gone.
	// Read from original file.
	bts, errR := ReadFile(fileName)
	if errR != nil {
		return errR
	}
	// Write it to the backup.
	errW := WriteFileRW(backupName, bts)
	if errW != nil {
		return errW
	}
	// Write new bytes to original.
	return WriteFileRW(fileName, data)
}

func ReadFile(fileName string) ([]byte, error) {
	return ioutil.ReadFile(fileName)
}