mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-12-18 22:07:26 +00:00
Update generated and dep addition of safefile
This commit is contained in:
197
vendor/github.com/dchest/safefile/safefile.go
generated
vendored
Normal file
197
vendor/github.com/dchest/safefile/safefile.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// Copyright 2013 Dmitry Chestnykh. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// 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
|
||||
//
|
||||
package safefile
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base32"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrAlreadyCommitted error is returned when calling Commit on a file that
|
||||
// has been already successfully committed.
|
||||
var ErrAlreadyCommitted = errors.New("file already committed")
|
||||
|
||||
type File struct {
|
||||
*os.File
|
||||
origName string
|
||||
closeFunc func(*File) error
|
||||
isClosed bool // if true, temporary file has been closed, but not renamed
|
||||
isCommitted bool // if true, the file has been successfully committed
|
||||
}
|
||||
|
||||
func makeTempName(origname, prefix string) (tempname string, err error) {
|
||||
origname = filepath.Clean(origname)
|
||||
if len(origname) == 0 || origname[len(origname)-1] == filepath.Separator {
|
||||
return "", os.ErrInvalid
|
||||
}
|
||||
// Generate 10 random bytes.
|
||||
// This gives 80 bits of entropy, good enough
|
||||
// for making temporary file name unpredictable.
|
||||
var rnd [10]byte
|
||||
if _, err := rand.Read(rnd[:]); err != nil {
|
||||
return "", err
|
||||
}
|
||||
name := prefix + "-" + strings.ToLower(base32.StdEncoding.EncodeToString(rnd[:])) + ".tmp"
|
||||
return filepath.Join(filepath.Dir(origname), name), nil
|
||||
}
|
||||
|
||||
// Create creates a temporary file in the same directory as filename,
|
||||
// which will be renamed to the given filename when calling Commit.
|
||||
func Create(filename string, perm os.FileMode) (*File, error) {
|
||||
for {
|
||||
tempname, err := makeTempName(filename, "sf")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.OpenFile(tempname, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &File{
|
||||
File: f,
|
||||
origName: filename,
|
||||
closeFunc: closeUncommitted,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// OrigName returns the original filename given to Create.
|
||||
func (f *File) OrigName() string {
|
||||
return f.origName
|
||||
}
|
||||
|
||||
// Close closes temporary file and removes it.
|
||||
// If the file has been committed, Close is no-op.
|
||||
func (f *File) Close() error {
|
||||
return f.closeFunc(f)
|
||||
}
|
||||
|
||||
func closeUncommitted(f *File) error {
|
||||
err0 := f.File.Close()
|
||||
err1 := os.Remove(f.Name())
|
||||
f.closeFunc = closeAgainError
|
||||
if err0 != nil {
|
||||
return err0
|
||||
}
|
||||
return err1
|
||||
}
|
||||
|
||||
func closeAfterFailedRename(f *File) error {
|
||||
// Remove temporary file.
|
||||
//
|
||||
// The note from Commit function applies here too, as we may be
|
||||
// removing a different file. However, since we rely on our temporary
|
||||
// names being unpredictable, this should not be a concern.
|
||||
f.closeFunc = closeAgainError
|
||||
return os.Remove(f.Name())
|
||||
}
|
||||
|
||||
func closeCommitted(f *File) error {
|
||||
// noop
|
||||
return nil
|
||||
}
|
||||
|
||||
func closeAgainError(f *File) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
// 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 (f *File) Commit() error {
|
||||
if f.isCommitted {
|
||||
return ErrAlreadyCommitted
|
||||
}
|
||||
if !f.isClosed {
|
||||
// Sync to disk.
|
||||
err := f.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Close underlying os.File.
|
||||
err = f.File.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.isClosed = true
|
||||
}
|
||||
// Rename.
|
||||
err := rename(f.Name(), f.origName)
|
||||
if err != nil {
|
||||
f.closeFunc = closeAfterFailedRename
|
||||
return err
|
||||
}
|
||||
f.closeFunc = closeCommitted
|
||||
f.isCommitted = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFile is a safe analog of ioutil.WriteFile.
|
||||
func WriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
f, err := Create(filename, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
n, err := f.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err == nil && n < len(data) {
|
||||
err = io.ErrShortWrite
|
||||
return err
|
||||
}
|
||||
return f.Commit()
|
||||
}
|
||||
Reference in New Issue
Block a user