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

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
}