You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
2 years ago
|
package main
|
||
|
|
||
|
import (
|
||
|
// "bufio"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
type CopyOp struct {
|
||
|
Bytes int64
|
||
|
Original, Backup *os.File
|
||
|
}
|
||
|
|
||
|
func copy(src, dst string) (CopyOp, error) {
|
||
|
var co CopyOp
|
||
|
sourceFileStat, err := os.Stat(src)
|
||
|
if err != nil {
|
||
|
return co, err
|
||
|
}
|
||
|
|
||
|
if !sourceFileStat.Mode().IsRegular() {
|
||
|
return co, fmt.Errorf("%s is not a regular file", src)
|
||
|
}
|
||
|
|
||
|
source, err := os.Open(src)
|
||
|
if err != nil {
|
||
|
return co, err
|
||
|
}
|
||
|
co.Original = source
|
||
|
defer source.Close()
|
||
|
|
||
|
destination, err := os.Create(dst)
|
||
|
if err != nil {
|
||
|
return co, err
|
||
|
}
|
||
|
defer destination.Close()
|
||
|
co.Backup = destination
|
||
|
|
||
|
nBytes, err := io.Copy(destination, source)
|
||
|
co.Bytes = nBytes
|
||
|
return co, err
|
||
|
}
|
||
|
|
||
|
func restoreBackup(fn string) error {
|
||
|
err := os.Remove(fn)
|
||
|
if err != nil {
|
||
|
// removing the original has failed.
|
||
|
return fmt.Errorf("error removing modified file[%s] : %w", fn, err)
|
||
|
}
|
||
|
|
||
|
// copy the backup back to the original
|
||
|
_, err = copy(fn+".bak", fn)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error copying backup into original location[%s]: %w", fn, err)
|
||
|
}
|
||
|
|
||
|
// remove the backup
|
||
|
err = os.Remove(fn + ".bak")
|
||
|
if err != nil {
|
||
|
// removing the backup has failed.
|
||
|
return fmt.Errorf("error removing backup file[%s] : %w", fn+".bak", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Update modifies the contents of a file in-place.
|
||
|
func Update(fn string, newContents io.Reader) error {
|
||
|
// create a backup copy
|
||
|
copyOp, err := copy(fn, fn+".bak")
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error backing up file[%s]: %w", fn, err)
|
||
|
}
|
||
|
|
||
|
// truncate the original
|
||
|
err = os.Truncate(fn, 0)
|
||
|
if err != nil {
|
||
|
err := restoreBackup(fn)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error restoring backup: %w", err)
|
||
|
}
|
||
|
return fmt.Errorf("error truncating original file[%s]: %w", fn, err)
|
||
|
}
|
||
|
|
||
|
// copy new contents into original
|
||
|
_, err = io.Copy(copyOp.Original, newContents)
|
||
|
if err != nil {
|
||
|
// the copy has failed. we need to remove the original
|
||
|
err := restoreBackup(fn)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error restoring backup: %w", err)
|
||
|
}
|
||
|
|
||
|
return fmt.Errorf("error writing new contents to file[%s] : %w", fn, err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|