//+build linux package staros import ( "b612.me/stario" "os" "syscall" "time" ) type FileLock struct { fd int filepath string } func timespecToTime(ts syscall.Timespec) time.Time { return time.Unix(int64(ts.Sec), int64(ts.Nsec)) } func GetFileCreationTime(fileinfo os.FileInfo) time.Time { return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctim) } func GetFileAccessTime(fileinfo os.FileInfo) time.Time { return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim) } func (f *FileLock) openFileForLock() error { fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600) if err != nil { return err } f.filepath = f.filepath f.fd = fd return nil } func (f *FileLock) Lock(Exclusive bool) error { var lockType int if Exclusive { lockType = syscall.LOCK_EX } else { lockType = syscall.LOCK_SH } if err := f.openFileForLock(); err != nil { return err } return syscall.Flock(f.fd, lockType) } func (f *FileLock) LockNoBlocking(Exclusive bool) error { var lockType int if Exclusive { lockType = syscall.LOCK_EX } else { lockType = syscall.LOCK_SH } if err := f.openFileForLock(); err != nil { return err } err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB) if err != nil { syscall.Close(f.fd) if err == syscall.EWOULDBLOCK { return ERR_ALREADY_LOCKED } } return err } func (f *FileLock) Unlock() error { err := syscall.Flock(f.fd, syscall.LOCK_UN) if err != nil { return err } return syscall.Close(f.fd) } func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error { return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error { err := f.Lock(Exclusive) select { case <-tmout: f.Unlock() return nil default: } return err }) }