atomicfile

package module
v0.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 23, 2024 License: MIT Imports: 4 Imported by: 25

README

atomicfile

GoDoc

Package atomicfile implements all-or-nothing file replacement by staging output to a temporary file adjacent to the specified target file, and renaming over the target when the temporary is closed.

Documentation

Overview

Package atomicfile implements all-or-nothing file replacement by staging output to a temporary file adjacent to the target, and renaming over the target when the temporary is closed.

If (and only if) the implementation of rename is atomic the replacement is also atomic. Since IEEE Std 1003.1 requires rename to be atomic, this is ordinarily true on POSIX-compatible filesystems.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Tx added in v0.3.0

func Tx(target string, mode os.FileMode, f func(*File) error) error

Tx calls f with a file constructed by New. If f reports an error or panics, the file is automatically cancelled and Tx returns the error from f. Otherwise, Tx returns the error from calling Close on the file.

func WriteAll

func WriteAll(target string, r io.Reader, mode os.FileMode) (nw int64, err error)

WriteAll copies all the data from r to the specified target path via a File. It reports the total number of bytes copied.

Example
package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/creachadair/atomicfile"
)

var tempDir string

func cat(path string) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatalf("Open: %v", err)
	}
	defer f.Close()
	io.Copy(os.Stdout, f)
}

func main() {
	path := filepath.Join(tempDir, "writeall.txt")
	nw, err := atomicfile.WriteAll(path, strings.NewReader("I knew you were trouble"), 0640)
	if err != nil {
		log.Fatalf("WriteAll: %v", err)
	}
	fmt.Println(nw)
	cat(path)
}
Output:

23
I knew you were trouble

func WriteData

func WriteData(target string, data []byte, mode os.FileMode) error

WriteData copies data to the specified target path via a File.

Example
package main

import (
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/creachadair/atomicfile"
)

var tempDir string

func cat(path string) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatalf("Open: %v", err)
	}
	defer f.Close()
	io.Copy(os.Stdout, f)
}

func main() {
	path := filepath.Join(tempDir, "writedata.txt")
	if err := atomicfile.WriteData(path, []byte("99 Luftballons"), 0600); err != nil {
		log.Fatalf("WriteData: %v", err)
	}
	cat(path)
}
Output:

99 Luftballons

Types

type File

type File struct {
	// contains filtered or unexported fields
}

A File is a writable temporary file that will be renamed to a target path when successfully closed.

func New

func New(target string, mode os.FileMode) (*File, error)

New constructs a new writable File with the given mode that will be renamed to target when successfully closed. New reports an error if target already exists and is not a plain (regular) file.

Example
package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/creachadair/atomicfile"
)

var tempDir string

func cat(path string) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatalf("Open: %v", err)
	}
	defer f.Close()
	io.Copy(os.Stdout, f)
}

func main() {
	path := filepath.Join(tempDir, "new.txt")
	f, err := atomicfile.New(path, 0600)
	if err != nil {
		log.Fatalf("New: %v", err)
	}
	defer f.Cancel()

	fmt.Fprintln(f, "Hello, world!")
	if err := f.Close(); err != nil {
		log.Fatalf("Close: %v", err)
	}

	cat(path)
}
Output:

Hello, world!

func (*File) Cancel

func (f *File) Cancel()

Cancel closes the temporary associated with f and discards it. It is safe to call Cancel even if f.Close has already succeeded; in that case the cancellation has no effect.

Example
package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/creachadair/atomicfile"
)

var tempDir string

func cat(path string) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatalf("Open: %v", err)
	}
	defer f.Close()
	io.Copy(os.Stdout, f)
}

func main() {
	path := filepath.Join(tempDir, "cancel.txt")
	if err := os.WriteFile(path, []byte("left right\n"), 0600); err != nil {
		log.Fatalf("WriteFile: %v", err)
	}
	cat(path)

	f, err := atomicfile.New(path, 0640)
	if err != nil {
		log.Fatalf("New: %v", err)
	}
	fmt.Fprintln(f, "Hello, world!")
	f.Cancel()

	// After cancellation, Close reports an error.
	if err := f.Close(); err == nil {
		log.Fatal("Close should have reported an error")
	}

	// The target path should not have been modified.
	cat(path)
}
Output:

left right
left right

func (*File) Close

func (f *File) Close() error

Close closes the temporary associated with f and renames it to the designated target file. If closing the temporary fails, or if the rename fails, the temporary file is unlinked before Close returns.

func (*File) ReadFrom added in v0.3.1

func (f *File) ReadFrom(r io.Reader) (int64, error)

ReadFrom implements the io.ReaderFrom interface to the underlying temporary.

func (*File) Write

func (f *File) Write(data []byte) (int, error)

Write writes data to f, satisfying io.Writer.

Directories

Path Synopsis
cmd
acat
Program acat copies its standard input to an output file.
Program acat copies its standard input to an output file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL