GithubHelp home page GithubHelp logo

rust-atomic-write-file's Introduction

Atomic Write File

Crate Documentation License

This is a Rust crate that offers functionality to write and overwrite files atomically, that is: without leaving the file in an intermediate state. Either the new contents of the files are written to the filesystem, or the old contents (if any) are preserved.

This crate implements two main structs: AtomicWriteFile and OpenOptions, which mimic the standard std::fs::File and std::fs::OpenOptions as much as possible.

This crate supports all major platforms, including: Unix systems, Windows, and WASI.

Motivation and Example

Consider the following snippet of code to write a configuration file in JSON format:

use std::io::Write;
use std::fs::File;

let mut file = File::options()
                    .write(true)
                    .create(true)
                    .open("config.json")?;

writeln!(file, "{{")?;
writeln!(file, "  \"key1\": \"value1\",")?;
writeln!(file, "  \"key2\": \"value2\"")?;
writeln!(file, "}}")?;

This code opens a file named config.json, truncates its contents (if the file already existed), and writes the JSON content line-by-line.

If the code is interrupted before all of the writeln! calls are completed (because of a panic, or a signal is received, or the process is killed, or a filesystem error occurs), then the file will be left in a broken state: it will not contain valid JSON data, and the original contents (if any) will be lost.

AtomicWriteFile solves this problem by placing the new contents into the destination file only after it has been completely written to the filesystem. The snippet above can be rewritten using AtomicWriteFile instead of File as follows:

use std::io::Write;
use atomic_write_file::AtomicWriteFile;

let mut file = AtomicWriteFile::options()
                               .open("config.json")?;

writeln!(file, "{{")?;
writeln!(file, "  \"key1\": \"value1\",")?;
writeln!(file, "  \"key2\": \"value2\"")?;
writeln!(file, "}}")?;

file.commit()?;

Note that this code is almost the same as the original, except that it now uses AtomicWriteFile instead of File and there's an additional call to commit().

If the code is interrupted early, before the call to commit(), the original file config.json will be left untouched. Only if the new contents are fully written to the filesystem, config.json will get them.

Documentation

Reference, examples, internal details, and limitations are all available on docs.rs/atomic-write-file.

rust-atomic-write-file's People

Contributors

andreacorbellini avatar sunshowers avatar messense avatar

Stargazers

Radu Marias avatar Nick Minor avatar Konstantinos Kyriakidis avatar Rob Patro avatar Ragnar Groot Koerkamp avatar  avatar Jesse Wang avatar Paolo Barbolini avatar Gunther Xing avatar iamazy avatar Federico Damián Schonborn avatar Sandalots avatar Pierre Tondereau avatar  avatar Jonas Platte avatar Mo avatar

Watchers

 avatar  avatar

Forkers

sunshowers

rust-atomic-write-file's Issues

Automatically fall back to different behavior when `O_TMPFILE` doesn't work

Apparently overlayfs, used by container software, doesn't support unnamed tempfiles: launchbadge/sqlx#2908

It would be nice to be able to easily use O_TMPFILE when it is supported, and fall back to a different behavior when it isn't. Currently, there's just the Cargo feature (and a library can't be sure that it's disabled, since some other package in an application's dependency tree might activate the it).

Rename failures are not propagated to caller of .commit()

  1. make a file manually echo foo > filename
  2. make it immutable chattr +i filename
  3. try to write over it with this library
    	let mut file = AtomicWriteFile::options().open("filename")?;
	writeln!(file, "{}", contents)?;
	file.commit()?;
  1. exit without error
  2. tmp file still exists and file did not get overwritten

Documentation link in readme is broken

Hey, thanks for building this awesome crate! I have been using NamedTempFile from the tempfile crate for this purpose before but this seems more convenient and robust from the how-it-works description in the docs.

There's a small problem with the readme, the docs badge link is broken.

`os error 5` when open `AtomicWriteFile` with `tempfile`

It returns an error when commit, opening with tempfile::NamedTempFile.path().
Access is denied. (os error 5)

dependencies

├── anyhow v1.0.81
├── atomic-write-file v0.1.3
│   └── rand v0.8.5
│       ├── rand_chacha v0.3.1
│       │   ├── ppv-lite86 v0.2.17
│       │   └── rand_core v0.6.4
│       │       └── getrandom v0.2.14
│       │           └── cfg-if v1.0.0
│       └── rand_core v0.6.4 (*)
└── tempfile v3.10.1
    ├── cfg-if v1.0.0
    ├── fastrand v2.0.2
    └── windows-sys v0.52.0
        └── windows-targets v0.52.4
            └── windows_x86_64_msvc v0.52.4

Platform

Windows

Code

use anyhow::Result;
use atomic_write_file::AtomicWriteFile;
use tempfile::NamedTempFile;

fn main() -> Result<()> {
    let file = NamedTempFile::new()?;
    let path = file.path();
    let atomic = AtomicWriteFile::open(path)?;
    atomic.commit()?;
    Ok(())
}

Output

Error: 拒绝访问。 (os error 5)

Missing fsync() call after linkat()

A call to fsync() on a O_TMPFILE does nothing. Now, the anonymous file is given a temporary name then renamed to its final name, without an fsync() call in between. A power failure following the final rename may result in data loss -- the target file now contains no data, filesize is zero.

Take a look at the btrfs source code in the kernel, where the no-op behavior of fsync() is described: https://github.com/torvalds/linux/blob/026e680b0a08a62b1d948e5a8ca78700bfac0e6e/fs/btrfs/tree-log.c#L2422

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.