GenZmeY
a89e63f19f
removes tails for --inplace in case the source file is larger than the modified one
128 lines
2.6 KiB
Go
128 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"multini/types"
|
|
)
|
|
|
|
// Source: https://gist.github.com/var23rav/23ae5d0d4d830aff886c3c970b8f6c6b
|
|
/*
|
|
GoLang: os.Rename() give error "invalid cross-device link" for Docker container with Volumes.
|
|
MoveFile(source, destination) will work moving file between folders
|
|
*/
|
|
func tryMoveFile(sourcePath, destPath string) error {
|
|
inputFile, err := os.Open(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
outputFile, err := os.Create(destPath)
|
|
if err != nil {
|
|
inputFile.Close()
|
|
return err
|
|
}
|
|
defer outputFile.Close()
|
|
_, err = io.Copy(outputFile, inputFile)
|
|
inputFile.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// The copy was successful, so now delete the original file
|
|
err = os.Remove(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func tryRemoveRenameFile(sourcePath, destPath string) bool {
|
|
err := os.Remove(destPath)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
err = os.Rename(sourcePath, destPath)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func replaceOriginal(oldFile, newFile string) error {
|
|
realOldFile, err := filepath.EvalSymlinks(oldFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
infoOldFile, err := os.Stat(realOldFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mode := infoOldFile.Mode()
|
|
|
|
var uid, gid int = GetUidGid(infoOldFile)
|
|
|
|
if !tryRemoveRenameFile(newFile, realOldFile) {
|
|
err = tryMoveFile(newFile, realOldFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = os.Chmod(realOldFile, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// try to restore original uid/gid
|
|
// don't worry if we can't
|
|
os.Chown(realOldFile, uid, gid)
|
|
|
|
return err
|
|
}
|
|
|
|
func iniWrite(filename string, ini *types.Ini) error {
|
|
tmpFile, err := ioutil.TempFile(os.TempDir(), "multini")
|
|
if err == nil {
|
|
datawriter := bufio.NewWriter(tmpFile)
|
|
_, err = datawriter.WriteString(ini.Full())
|
|
if err == nil {
|
|
err = datawriter.Flush()
|
|
tmpFile.Close()
|
|
if err == nil {
|
|
err = replaceOriginal(filename, tmpFile.Name())
|
|
}
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func iniWriteInplace(filename string, ini *types.Ini) error {
|
|
realfilename, err := filepath.EvalSymlinks(filename)
|
|
mode := os.FileMode(int(0644))
|
|
if os.IsNotExist(err) {
|
|
realfilename = filename
|
|
} else if err != nil {
|
|
return err
|
|
} else {
|
|
info, err := os.Stat(realfilename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mode = info.Mode()
|
|
}
|
|
targetFile, err := os.OpenFile(realfilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
|
if err == nil {
|
|
datawriter := bufio.NewWriter(targetFile)
|
|
_, err = datawriter.WriteString(ini.Full())
|
|
if err == nil {
|
|
err = datawriter.Flush()
|
|
targetFile.Close()
|
|
}
|
|
}
|
|
return err
|
|
}
|