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 {
|
if t.MustExist {
|
||||||
var err error
|
var err error
|
||||||
t.file, err = os.Open(t.Filename)
|
t.file, err = OpenFile(t.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ func (tail *Tail) reopen() error {
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
var err error
|
var err error
|
||||||
tail.file, err = os.Open(tail.Filename)
|
tail.file, err = OpenFile(tail.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
tail.Logger.Printf("Waiting for %s to appear...", tail.Filename)
|
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() {
|
go func() {
|
||||||
defer changes.Close()
|
defer changes.Close()
|
||||||
|
|
||||||
|
var retry int = 0
|
||||||
|
|
||||||
prevSize := fw.Size
|
prevSize := fw.Size
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -67,6 +69,11 @@ func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, origFi os.FileInfo) *Fi
|
||||||
changes.NotifyDeleted()
|
changes.NotifyDeleted()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if permissionErrorRetry(err, &retry) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: report this error back to the user
|
// XXX: report this error back to the user
|
||||||
util.Fatal("Failed to stat file %v: %v", fw.Filename, err)
|
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