Repository: zyedidia/micro
File: internal/buffer/save.go (Go)

Code before:
		// contents to its stdin it might hang because the kernel's pipe size
		// is too small to handle the full file contents all at once
		err = cmd.Start()
		if err != nil {
			screen.TempStart(screenb)

			signal.Notify(util.Sigterm, os.Interrupt)
			signal.Stop(sigChan)

			return wrappedFile{}, err
		}
	} else {
		writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE, util.FileMode)
		if err != nil {
			return wrappedFile{}, err
		}
	}

	return wrappedFile{name, writeCloser, withSudo, screenb, cmd, sigChan}, nil
}

func (wf wrappedFile) Truncate(size int64) error {
	if wf.withSudo {
		// we don't need to stop the screen here, since it is still stopped
		// by openFile()
		cmd := exec.Command(config.GlobalSettings["sucmd"].(string), "truncate", "-s", strconv.FormatInt(size, 10), wf.name)
		return cmd.Run()
	}
	return wf.writeCloser.(*os.File).Truncate(size)
}

func (wf wrappedFile) Write(b *Buffer) (int, error) {
	file := bufio.NewWriter(transform.NewWriter(wf.writeCloser, b.encoding.NewEncoder()))

	b.Lock()
	defer b.Unlock()

	if len(b.lines) == 0 {
		return 0, nil
	}

	// end of line
	var eol []byte
	if b.Endings == FFDos {
		eol = []byte{'\r', '\n'}
	} else {
		eol = []byte{'\n'}
	}

	err := wf.Truncate(0)
	if err != nil {

Review comment (suggestion):
I checked all Unix platforms in `cross-compile.sh` and only 3 platforms don't have `truncate` as a command, which are [Illumos](https://www.illumos.org/man/1/truncate), [NetBSD](https://man.netbsd.org/truncate.1), and [OpenBSD](https://man.openbsd.org/truncate.1).

If we will replace the `truncate` command, `dd count=0 of=path` may work on all such platforms but could only truncate to 0 bytes. There might be a difference in behavior, since the command may open the file with `O_TRUNC` (and closes it after) instead of just using the `truncate` system call, but I doubt it would be different.

Code after:
		signal.Reset(os.Interrupt)
		signal.Notify(sigChan, os.Interrupt)

		screenb = screen.TempFini()
		// need to start the process now, otherwise when we flush the file
		// contents to its stdin it might hang because the kernel's pipe size
		// is too small to handle the full file contents all at once
		err = cmd.Start()
		if err != nil {
			screen.TempStart(screenb)

			signal.Notify(util.Sigterm, os.Interrupt)
			signal.Stop(sigChan)

			return wrappedFile{}, err
		}
	} else {
		writeCloser, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE, util.FileMode)
		if err != nil {
			return wrappedFile{}, err
		}
	}

	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) {
	file := bufio.NewWriter(transform.NewWriter(wf.writeCloser, b.encoding.NewEncoder()))

	b.Lock()
	defer b.Unlock()

	if len(b.lines) == 0 {
		return 0, nil
	}

	// end of line
	var eol []byte
	if b.Endings == FFDos {
		eol = []byte{'\r', '\n'}