Documentation ¶
Overview ¶
Package safefile implements safe "atomic" saving of files.
Instead of truncating and overwriting the destination file, it creates a temporary file in the same directory, writes to it, and then renames the temporary file to the original name when calling Commit.
Example:
f, err := safefile.Create("/home/ken/report.txt", 0644) if err != nil { // ... } // Created temporary file /home/ken/sf-ppcyksu5hyw2mfec.tmp defer f.Close() _, err = io.WriteString(f, "Hello world") if err != nil { // ... } // Wrote "Hello world" to /home/ken/sf-ppcyksu5hyw2mfec.tmp err = f.Commit() if err != nil { // ... } // Renamed /home/ken/sf-ppcyksu5hyw2mfec.tmp to /home/ken/report.txt
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAlreadyCommitted = errors.New("file already committed")
ErrAlreadyCommitted error is returned when calling Commit on a file that has been already successfully committed.
Functions ¶
Types ¶
type File ¶
func Create ¶
Create creates a temporary file in the same directory as filename, which will be renamed to the given filename when calling Commit.
func (*File) Close ¶
Close closes temporary file and removes it. If the file has been committed, Close is no-op.
func (*File) Commit ¶
Commit safely commits data into the original file by syncing temporary file to disk, closing it and renaming to the original file name.
In case of success, the temporary file is closed and no longer exists on disk. It is safe to call Close after Commit: the operation will do nothing.
In case of error, the temporary file is still opened and exists on disk; it must be closed by callers by calling Close or by trying to commit again.
Note that when trying to Commit again after a failed Commit when the file has been closed, but not renamed to its original name (the new commit will try again to rename it), safefile cannot guarantee that the temporary file has not been changed, or that it is the same temporary file we were dealing with. However, since the temporary name is unpredictable, it is unlikely that this happened accidentally. If complete atomicity is needed, do not Commit again after error, write the file again.
func (*File) CommitIfNotExists ¶
CommitIfNotExists safely commits data into the original file by syncing temporary file to disk, closing it, and linking it to the original file name. Linking fails with EEXIST if there already exists a file with the target name. That means that if two processes race to create a new file with CommitIfNotExists, one will succeed, and the other one fail and leave target file untouched.
In case of success, the temporary file is closed and removed. If the removal fails for any reason, this method still returns nil; removal will be retried by Close. It is safe to call Close after Commit: the operation will retry removing the temporary file, if needed (and return any resulting error), but otherwise do nothing.
In case of error, the temporary file is still opened and exists on disk; it must be closed by callers by calling Close or by trying to commit again.