add atomic package
This commit is contained in:
parent
5d325597a8
commit
43833d937f
1
Nut.toml
1
Nut.toml
@ -14,6 +14,7 @@ authors = [
|
||||
"github.com/kr/pty" = "5cf931ef8f76dccd0910001d74a58a7fca84a83d"
|
||||
"github.com/kr/text" = "6807e777504f54ad073ecef66747de158294b639"
|
||||
"github.com/inconshreveable/mousetrap" = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
"github.com/natefinch/atomic" = "a62ce929ffcc871a51e98c6eba7b20321e3ed62d"
|
||||
"github.com/olekukonko/ts" = "ecf753e7c962639ab5a1fb46f7da627d4c0a04b8"
|
||||
"github.com/rubyist/tracerx" = "d7bcc0bc315bed2a841841bee5dbecc8d7d7582f"
|
||||
"github.com/spf13/cobra" = "c55cdf33856a08e4822738728b41783292812889"
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/github/git-lfs/vendor/_nuts/github.com/cheggaaa/pb"
|
||||
"github.com/github/git-lfs/vendor/_nuts/github.com/natefinch/atomic"
|
||||
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
||||
)
|
||||
|
||||
@ -198,7 +199,7 @@ func bufferDownloadedFile(filename string, reader io.Reader, size int64, cb Copy
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Rename(name, filename); err != nil {
|
||||
if err := atomic.ReplaceFile(name, filename); err != nil {
|
||||
return fmt.Errorf("cannot replace %q with tempfile %q: %v", filename, name, err)
|
||||
}
|
||||
return nil
|
||||
|
24
vendor/_nuts/github.com/natefinch/atomic/.gitignore
vendored
Normal file
24
vendor/_nuts/github.com/natefinch/atomic/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
22
vendor/_nuts/github.com/natefinch/atomic/LICENSE
vendored
Normal file
22
vendor/_nuts/github.com/natefinch/atomic/LICENSE
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Nate Finch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
35
vendor/_nuts/github.com/natefinch/atomic/README.md
vendored
Normal file
35
vendor/_nuts/github.com/natefinch/atomic/README.md
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# atomic
|
||||
import "github.com/natefinch/atomic"
|
||||
atomic is a go package for atomic file writing
|
||||
|
||||
By default, writing to a file in go (and generally any language) can fail
|
||||
partway through... you then have a partially written file, which probably was
|
||||
truncated when the write began, and bam, now you've lost data.
|
||||
|
||||
This go package avoids this problem, by writing first to a temp file, and then
|
||||
overwriting the target file in an atomic way. This is easy on linux, os.Rename
|
||||
just is atomic. However, on Windows, os.Rename is not atomic, and so bad things
|
||||
can happen. By wrapping the windows API moveFileEx, we can ensure that the move
|
||||
is atomic, and we can be safe in knowing that either the move succeeds entirely,
|
||||
or neither file will be modified.
|
||||
|
||||
|
||||
## func ReplaceFile
|
||||
``` go
|
||||
func ReplaceFile(source, destination string) error
|
||||
```
|
||||
ReplaceFile atomically replaces the destination file or directory with the
|
||||
source. It is guaranteed to either replace the target file entirely, or not
|
||||
change either file.
|
||||
|
||||
|
||||
## func WriteFile
|
||||
``` go
|
||||
func WriteFile(filename string, r io.Reader) (err error)
|
||||
```
|
||||
WriteFile atomically writes the contents of r to the specified filepath. If
|
||||
an error occurs, the target file is guaranteed to be either fully written, or
|
||||
not written at all. WriteFile overwrites any file that exists at the
|
||||
location (but only if the write fully succeeds, otherwise the existing file
|
||||
is unmodified).
|
||||
|
58
vendor/_nuts/github.com/natefinch/atomic/atomic.go
vendored
Normal file
58
vendor/_nuts/github.com/natefinch/atomic/atomic.go
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// package atomic provides functions to atomically change files.
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// WriteFile atomically writes the contents of r to the specified filepath. If
|
||||
// an error occurs, the target file is guaranteed to be either fully written, or
|
||||
// not written at all. WriteFile overwrites any file that exists at the
|
||||
// location (but only if the write fully succeeds, otherwise the existing file
|
||||
// is unmodified).
|
||||
func WriteFile(filename string, r io.Reader) (err error) {
|
||||
// write to a temp file first, then we'll atomically replace the target file
|
||||
// with the temp file.
|
||||
dir, file := filepath.Split(filename)
|
||||
f, err := ioutil.TempFile(dir, file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create temp file: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// Don't leave the temp file lying around on error.
|
||||
_ = os.Remove(f.Name()) // yes, ignore the error, not much we can do about it.
|
||||
}
|
||||
}()
|
||||
// ensure we always close f. Note that this does not conflict with the
|
||||
// close below, as close is idempotent.
|
||||
defer f.Close()
|
||||
name := f.Name()
|
||||
if _, err := io.Copy(f, r); err != nil {
|
||||
return fmt.Errorf("cannot write data to tempfile %q: %v", name, err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return fmt.Errorf("can't close tempfile %q: %v", name, err)
|
||||
}
|
||||
|
||||
// get the file mode from the original file and use that for the replacement
|
||||
// file, too.
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
// no original file
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := os.Chmod(name, info.Mode()); err != nil {
|
||||
return fmt.Errorf("can't set filemode on tempfile %q: %v", name, err)
|
||||
}
|
||||
}
|
||||
if err := ReplaceFile(name, filename); err != nil {
|
||||
return fmt.Errorf("cannot replace %q with tempfile %q: %v", filename, name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
14
vendor/_nuts/github.com/natefinch/atomic/file_unix.go
vendored
Normal file
14
vendor/_nuts/github.com/natefinch/atomic/file_unix.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// +build !windows
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// ReplaceFile atomically replaces the destination file or directory with the
|
||||
// source. It is guaranteed to either replace the target file entirely, or not
|
||||
// change either file.
|
||||
func ReplaceFile(source, destination string) error {
|
||||
return os.Rename(source, destination)
|
||||
}
|
33
vendor/_nuts/github.com/natefinch/atomic/file_windows.go
vendored
Normal file
33
vendor/_nuts/github.com/natefinch/atomic/file_windows.go
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
movefile_replace_existing = 0x1
|
||||
movefile_write_through = 0x8
|
||||
)
|
||||
|
||||
//sys moveFileEx(lpExistingFileName *uint16, lpNewFileName *uint16, dwFlags uint32) (err error) = MoveFileExW
|
||||
|
||||
// ReplaceFile atomically replaces the destination file or directory with the
|
||||
// source. It is guaranteed to either replace the target file entirely, or not
|
||||
// change either file.
|
||||
func ReplaceFile(source, destination string) error {
|
||||
src, err := syscall.UTF16PtrFromString(source)
|
||||
if err != nil {
|
||||
return &os.LinkError{"replace", source, destination, err}
|
||||
}
|
||||
dest, err := syscall.UTF16PtrFromString(destination)
|
||||
if err != nil {
|
||||
return &os.LinkError{"replace", source, destination, err}
|
||||
}
|
||||
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
|
||||
if err := moveFileEx(src, dest, movefile_replace_existing|movefile_write_through); err != nil {
|
||||
return &os.LinkError{"replace", source, destination, err}
|
||||
}
|
||||
return nil
|
||||
}
|
27
vendor/_nuts/github.com/natefinch/atomic/zfile_windows.go
vendored
Normal file
27
vendor/_nuts/github.com/natefinch/atomic/zfile_windows.go
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// mksyscall_windows -l32 file_windows.go
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procMoveFileExW = modkernel32.NewProc("MoveFileExW")
|
||||
)
|
||||
|
||||
func moveFileEx(lpExistingFileName *uint16, lpNewFileName *uint16, dwFlags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(lpExistingFileName)), uintptr(unsafe.Pointer(lpNewFileName)), uintptr(dwFlags))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user