|
|
|
// +build windows
|
|
|
|
|
|
|
|
package staros
|
|
|
|
|
|
|
|
import (
|
|
|
|
"b612.me/win32api"
|
|
|
|
"os"
|
|
|
|
"syscall"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FileLock struct {
|
|
|
|
filepath string
|
|
|
|
handle win32api.HANDLE
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
|
|
|
|
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
|
|
|
|
return time.Unix(0, d.CreationTime.Nanoseconds())
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
|
|
|
|
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
|
|
|
|
return time.Unix(0, d.LastAccessTime.Nanoseconds())
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetFileTimes(file *os.File, info os.FileInfo) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetFileTimesbyTime(file *os.File) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) openFileForLock() error {
|
|
|
|
name, err := syscall.UTF16PtrFromString(f.filepath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
handle, err := syscall.CreateFile(
|
|
|
|
name,
|
|
|
|
syscall.GENERIC_READ,
|
|
|
|
syscall.FILE_SHARE_READ,
|
|
|
|
nil,
|
|
|
|
syscall.OPEN_ALWAYS,
|
|
|
|
syscall.FILE_FLAG_OVERLAPPED|0x00000080,
|
|
|
|
0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
f.handle = win32api.HANDLE(handle)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) lockForTimeout(timeout time.Duration, lockType win32api.DWORD) error {
|
|
|
|
var err error
|
|
|
|
if err = f.openFileForLock(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
event, err := win32api.CreateEventW(nil, true, false, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
myEvent := &syscall.Overlapped{HEvent: syscall.Handle(event)}
|
|
|
|
defer syscall.CloseHandle(myEvent.HEvent)
|
|
|
|
_, err = win32api.LockFileEx(f.handle, lockType, 0, 1, 0, myEvent)
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if err != syscall.ERROR_IO_PENDING {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
millis := uint32(syscall.INFINITE)
|
|
|
|
if timeout >= 0 {
|
|
|
|
millis = uint32(timeout.Nanoseconds() / 1000000)
|
|
|
|
}
|
|
|
|
s, err := syscall.WaitForSingleObject(myEvent.HEvent, millis)
|
|
|
|
switch s {
|
|
|
|
case syscall.WAIT_OBJECT_0:
|
|
|
|
// success!
|
|
|
|
return nil
|
|
|
|
case syscall.WAIT_TIMEOUT:
|
|
|
|
f.Unlock()
|
|
|
|
return ERR_TIMEOUT
|
|
|
|
default:
|
|
|
|
f.Unlock()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) Lock(Exclusive bool) error {
|
|
|
|
var lockType win32api.DWORD
|
|
|
|
if Exclusive {
|
|
|
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
|
|
|
} else {
|
|
|
|
lockType = 0
|
|
|
|
}
|
|
|
|
return f.lockForTimeout(0, lockType)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
|
|
|
|
var lockType win32api.DWORD
|
|
|
|
if Exclusive {
|
|
|
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
|
|
|
} else {
|
|
|
|
lockType = 0
|
|
|
|
}
|
|
|
|
return f.lockForTimeout(tm, lockType)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
|
|
|
|
var lockType win32api.DWORD
|
|
|
|
if Exclusive {
|
|
|
|
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
|
|
|
|
} else {
|
|
|
|
lockType = 0
|
|
|
|
}
|
|
|
|
return f.lockForTimeout(0, lockType|win32api.LOCKFILE_FAIL_IMMEDIATELY)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FileLock) Unlock() error {
|
|
|
|
return syscall.Close(syscall.Handle(f.handle))
|
|
|
|
}
|