add FILE_SHARE_DELETE flag when opening file
This commit is contained in:
parent
22e519566e
commit
c2a48be739
4
tail.go
4
tail.go
|
@ -104,7 +104,7 @@ func TailFile(filename string, config Config) (*Tail, error) {
|
|||
|
||||
if t.MustExist {
|
||||
var err error
|
||||
t.file, err = os.Open(t.Filename)
|
||||
t.file, err = OpenFile(t.Filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ func (tail *Tail) reopen() error {
|
|||
}
|
||||
for {
|
||||
var err error
|
||||
tail.file, err = os.Open(tail.Filename)
|
||||
tail.file, err = OpenFile(tail.Filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
tail.Logger.Printf("Waiting for %s to appear...", tail.Filename)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// +build linux
|
||||
|
||||
package tail
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func OpenFile(name string) (file *os.File, err error) {
|
||||
return os.Open(name)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// +build windows
|
||||
|
||||
package tail
|
||||
|
||||
import (
|
||||
"github.com/ActiveState/tail/winfile"
|
||||
"os"
|
||||
)
|
||||
|
||||
func OpenFile(name string) (file *os.File, err error) {
|
||||
return winfile.OpenFile(name, os.O_RDONLY, 0)
|
||||
}
|
|
@ -51,6 +51,8 @@ func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, origFi os.FileInfo) *Fi
|
|||
go func() {
|
||||
defer changes.Close()
|
||||
|
||||
var retry int = 0
|
||||
|
||||
prevSize := fw.Size
|
||||
for {
|
||||
select {
|
||||
|
@ -67,6 +69,11 @@ func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, origFi os.FileInfo) *Fi
|
|||
changes.NotifyDeleted()
|
||||
return
|
||||
}
|
||||
|
||||
if permissionErrorRetry(err, &retry) {
|
||||
continue
|
||||
}
|
||||
|
||||
// XXX: report this error back to the user
|
||||
util.Fatal("Failed to stat file %v: %v", fw.Filename, err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||
// +build linux
|
||||
|
||||
package watch
|
||||
|
||||
func permissionErrorRetry(err error, retry *int) bool {
|
||||
// No need for this on linux, don't retry
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// +build windows
|
||||
|
||||
package watch
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const permissionDeniedRetryCount int = 5
|
||||
|
||||
func permissionErrorRetry(err error, retry *int) bool {
|
||||
if os.IsPermission(err) && *retry < permissionDeniedRetryCount {
|
||||
// While pooling a file that does not exist yet, but will be created by another process we can get Permission Denied
|
||||
(*retry)++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// +build windows
|
||||
|
||||
package winfile
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// issue also described here
|
||||
//https://codereview.appspot.com/8203043/
|
||||
|
||||
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L218
|
||||
func Open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
|
||||
if len(path) == 0 {
|
||||
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
|
||||
}
|
||||
pathp, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return syscall.InvalidHandle, err
|
||||
}
|
||||
var access uint32
|
||||
switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
|
||||
case syscall.O_RDONLY:
|
||||
access = syscall.GENERIC_READ
|
||||
case syscall.O_WRONLY:
|
||||
access = syscall.GENERIC_WRITE
|
||||
case syscall.O_RDWR:
|
||||
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
|
||||
}
|
||||
if mode&syscall.O_CREAT != 0 {
|
||||
access |= syscall.GENERIC_WRITE
|
||||
}
|
||||
if mode&syscall.O_APPEND != 0 {
|
||||
access &^= syscall.GENERIC_WRITE
|
||||
access |= syscall.FILE_APPEND_DATA
|
||||
}
|
||||
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
|
||||
var sa *syscall.SecurityAttributes
|
||||
if mode&syscall.O_CLOEXEC == 0 {
|
||||
sa = makeInheritSa()
|
||||
}
|
||||
var createmode uint32
|
||||
switch {
|
||||
case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
|
||||
createmode = syscall.CREATE_NEW
|
||||
case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
|
||||
createmode = syscall.CREATE_ALWAYS
|
||||
case mode&syscall.O_CREAT == syscall.O_CREAT:
|
||||
createmode = syscall.OPEN_ALWAYS
|
||||
case mode&syscall.O_TRUNC == syscall.O_TRUNC:
|
||||
createmode = syscall.TRUNCATE_EXISTING
|
||||
default:
|
||||
createmode = syscall.OPEN_EXISTING
|
||||
}
|
||||
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
|
||||
return h, e
|
||||
}
|
||||
|
||||
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L211
|
||||
func makeInheritSa() *syscall.SecurityAttributes {
|
||||
var sa syscall.SecurityAttributes
|
||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||
sa.InheritHandle = 1
|
||||
return &sa
|
||||
}
|
||||
|
||||
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_windows.go#L133
|
||||
func OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
|
||||
r, e := Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return os.NewFile(uintptr(r), name), nil
|
||||
}
|
||||
|
||||
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_posix.go#L61
|
||||
func syscallMode(i os.FileMode) (o uint32) {
|
||||
o |= uint32(i.Perm())
|
||||
if i&os.ModeSetuid != 0 {
|
||||
o |= syscall.S_ISUID
|
||||
}
|
||||
if i&os.ModeSetgid != 0 {
|
||||
o |= syscall.S_ISGID
|
||||
}
|
||||
if i&os.ModeSticky != 0 {
|
||||
o |= syscall.S_ISVTX
|
||||
}
|
||||
// No mapping for Go's ModeTemporary (plan9 only).
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue