mirror of
https://github.com/zyedidia/micro.git
synced 2026-02-04 22:20:20 +09:00
save: Use dd with the notrunc & fsync option
Using notrunc will stop the overall truncation of the target file done by sudo. We need to do this because dd, like other coreutils, already truncates the file on open(). In case we can't store the backup file afterwards we would end up in a truncated file for which the user has no write permission by default. Instead we use a second call of `dd` to perform the necessary truncation on the command line. With the fsync option we force the dd process to synchronize the written file to the underlying device.
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
||||
const LargeFileThreshold = 50000
|
||||
|
||||
type wrappedFile struct {
|
||||
name string
|
||||
writeCloser io.WriteCloser
|
||||
withSudo bool
|
||||
screenb bool
|
||||
@@ -83,7 +84,13 @@ func openFile(name string, withSudo bool) (wrappedFile, error) {
|
||||
var sigChan chan os.Signal
|
||||
|
||||
if withSudo {
|
||||
cmd = exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "bs=4k", "of="+name)
|
||||
conv := "notrunc"
|
||||
// TODO: both platforms do not support dd with conv=fsync yet
|
||||
if !(runtime.GOOS == "illumos" || runtime.GOOS == "netbsd") {
|
||||
conv += ",fsync"
|
||||
}
|
||||
|
||||
cmd = exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "bs=4k", "conv="+conv, "of="+name)
|
||||
writeCloser, err = cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return wrappedFile{}, err
|
||||
@@ -113,7 +120,18 @@ func openFile(name string, withSudo bool) (wrappedFile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return wrappedFile{writeCloser, withSudo, screenb, cmd, sigChan}, nil
|
||||
return wrappedFile{name, writeCloser, withSudo, screenb, cmd, sigChan}, nil
|
||||
}
|
||||
|
||||
func (wf wrappedFile) Truncate() error {
|
||||
if wf.withSudo {
|
||||
// we don't need to stop the screen here, since it is still stopped
|
||||
// by openFile()
|
||||
// truncate might not be available on every platfom, so use dd instead
|
||||
cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "dd", "count=0", "of="+wf.name)
|
||||
return cmd.Run()
|
||||
}
|
||||
return wf.writeCloser.(*os.File).Truncate(0)
|
||||
}
|
||||
|
||||
func (wf wrappedFile) Write(b *Buffer) (int, error) {
|
||||
@@ -134,12 +152,9 @@ func (wf wrappedFile) Write(b *Buffer) (int, error) {
|
||||
eol = []byte{'\n'}
|
||||
}
|
||||
|
||||
if !wf.withSudo {
|
||||
f := wf.writeCloser.(*os.File)
|
||||
err := f.Truncate(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err := wf.Truncate()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// write lines
|
||||
|
||||
Reference in New Issue
Block a user